This section provides you with some pointers that might prove helpful when using AndroMDA with the Spring cartridge.
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); }
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>
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 ... }
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)
<namespace name="spring"> ... <property name="userTransactionName">null</property> <property name="transactionManagerName">java:/TransactionManager</property> ... </namespace>
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>