Sunday, August 06, 2006

 

EJB3 application design questions


I'm trying to convert my previous project to EJB 3.0 and I've encountered these issues.
I have answers to some and some I have to discover the answers to later.
I'm posting them and maybe get some feedback from people who had these similar questions…
I'll be updating this blog as I get more insights. Feel free to share yours.




For a system, there's one project, many modules and each module has many layers.
In eclipse, you have to create one project for EAR, one for EJB, one for WEB.


I follow this convention:


<project>-EAR


<project>-EJB


<project>-WAR


All of these are under <project> and it is the root folder in Subversion.


In addition to those mentioned above, I make it a point to test the service classes with live database values and then test the web UI with live database values as well. So I need two additional Java projects.


<project>-EJBTest


<project>-WEBTest




With regards to packaging, it will be:
com.<company>.<project>.api.service.<module>


This is where the interfaces of the service class will go. For EJB3, it will be the interface of the stateless session beans.


com.<company>.<project>.api.domain.<module>


This is where the java beans (search form beans) will be placed, as well as custom Exceptions thrown by the service class.


Persistence classes can be used in the web layer for display and assigning values from the UI. However, we still need to create java beans to contain search criteria.


com.<company>.<project>.impl.domain.<module>


This is where the persistence classes will be placed.


com.<company>.<project>.util


This is where util classes will be placed.



For Spring, entity objects have an interface, so I thought I'll make one for my EJBs. Interfaces must be on separate packages, because doing this will be helpful for web component developers, since they only need to look at the methods and variables available to them, without needing to see the implementation. Therefore, classes under api should never reference classes under impl.


It turns out, I can't do that. Generics as I found out doesn't support inheritance. For example: Unit and UnitImpl classes, where UnitImpl implements Unit.


In Unit, I put:


public abstract Set<Unit> getSubUnits


In UnitImpl, I put:


public abstract Set<UnitImpl> getSubUnits


I though that this would work, but it didn't. I have two choices: either use UnitImpl which breaks the dependency rule that api shouldn't access impl package, OR use Unit. It compiles, but when you run it, it will complain that Unit, being an interface, is not a persistence class.


In short, we would have to use UnitImpl, which because there is no interface anympre, I'm now naming just Unit. We have to break the dependency rule because our service method will be accessing the impl.domain package.





Is there some sort of Eclipse plugin that I can use for EJB 3.0 that is similar to Jboss hibernate tools?
I looked in the JBoss website and found none. So far I have to deploy and run the query to be able to test if the syntax is correct and that it is returning the correct records.



You don't have to wait until you finish coding your web component before you can test your EJB.


First off, you have to make your service class accessible remotely, using @Remote


To be able to access EJBs remotely, you need to call a ctx.lookup using JBoss specific properties.



public static Object getBean(String beanName) throws NamingException{
Properties env = new Properties();
env.setProperty("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
env.setProperty("java.naming.provider.url", "localhost:1099");
env.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
Context ctx = new InitialContext(env);
return ctx.lookup(beanName);
}

The beanName, since we're using an EAR file is, <EAR name>/<Impl name>/remote


The bean should be cast to the interface, in this case (UnitService)


UnitService service = (UnitService) JBossUtil.getBean("Intranet-EAR/UnitServiceImpl/remote");


Below is the general rule for the JNDI name:


If EJB is in EAR file:


<EAR name>/<Impl Name>/remote


<EAR name>/<Impl Name>/local


If EJB is in JAR file:


<Impl Name>/remote


<Impl Name>/local



I don't know when it changed but now if you cast


em.createNamedQuery("").getSingleResult();


to Integer, it would throw a ClassCastException.


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?