Tips for using the AndroMDA Spring cartridge

This section provides you with some pointers that might prove helpful when using AndroMDA with the Spring cartridge.

Exceptions

It's not needed to model exceptions for all the services you model, the Spring cartridge will generate them automatically for you. That way you don't need to keep writing try/catch blocks in the handleXXX methods in the service implementation classes, just throw any error, it will be handled for you.

So basically this snippet is a good example of an implementation of a service operation, there is no need to catch any exception and re-throw it:

protected PersonDetails handleGet(Long id) throws Exception
{
    return (PersonDetails)getPersonDao().load(PersonDao.TRANSFORM_PERSONDETAILS, id);
}

Running without EJBs

If you have told andromdapp:generate to generate a WAR-only project (i.e. for deployment in Tomcat) EJBs will be disabled by default and you won't need to worry about this section.

With the change of a single line it is possible to enable or disable the usage of stateless session EJBs, simply put the <session-ejbs> outlet in comment, like this (this is done in mda/conf/andromda.xml):

<namespace name="spring">
    <properties>
        ...
        <!--
            <property name="session-ejbs">${maven.andromda.core.generated.dir}</property>
        -->
        ...
    </properties>
</namespace>

Beware of lazy loading!

Unless an Association is composition-modeled, all associations collections are made lazy by default. While this is very nice to avoid retrieving the whole database on each query, you should be aware that each time you invoke a method on a Spring Service, a Hibernate Session is opened at the beginning and closed at the end of the call.

The consequence of this is that every persistent object that was retrieved in the body of a Service method is unable to retrieve its associations lazily outside this very call.

For example: if the user parameter in the following code was obtained as the result of calling a Spring service method, and that user has a lazy group association, and the following is another Spring Service method, it would raise a net.sf.hibernate.LazyInitializationException:

protected boolean doSomethingWithUserGroups(User user) throws Exception
{
    ...
    java.util.Collection userGroups = user.getGroups ();
    java.util.Iterator everyUserGroup = userGroups.iterator(); // this call would generate the exception
    ...
}

Connecting to JBoss with Remote EJBs

When connecting to a remote EJB wrapped Spring service deployed in JBoss, its possible you'll get the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in c
lass path resource [applicationContext-dataSource.xml]: Initialization of bean failed; nested exception is org.springfra
mework.transaction.TransactionSystemException: JTA UserTransaction is not available at JNDI location [java:comp/UserTran
saction]; nested exception is javax.naming.NameNotFoundException: UserTransaction not bound
org.springframework.transaction.TransactionSystemException: JTA UserTransaction is not available at JNDI location [java:
comp/UserTransaction]; nested exception is javax.naming.NameNotFoundException: UserTransaction not bound
javax.naming.NameNotFoundException: UserTransaction not bound
        at org.jnp.server.NamingServer.getBinding(NamingServer.java:491)
        at org.jnp.server.NamingServer.getBinding(NamingServer.java:499)
        at org.jnp.server.NamingServer.getObject(NamingServer.java:505)
        at org.jnp.server.NamingServer.lookup(NamingServer.java:278)
To get around this, place the following 2 properties in your spring namespace:

<namespace name="spring">
    ...
    <property name="userTransactionName">null</property>
    <property name="transactionManagerName">java:/TransactionManager</property>
    ...
</namespace>
                

Using foreign services

You can connect to "foreign" spring services, which are not implemented in your application but in another one (e.g. a other ear), as with "normal" services: just draw a dependency to the "foreign" service class. The foreign service class has to be defined as any other service but without any method or property.

To prevent the spring cartridge from generating java code you have to exclude the packages with a process="false" statement in the andromda configuration just in your appropriate <model> tag:

<modelPackages>
    <modelPackage process="false">de::my::foreign.package::name</modelPackage>
</modelPackages>
                
(look at http://andromda.sourceforge.net/docs/configuration.html#modelPackage) The spring cartridge will generate the dependency code for the source class (property class with getter/setter) and the bean-ref tag in the spring application context file. The only thing you now have to do is to provide the "foreign" spring bean definition file to your application context (in the beanRefFactory file).