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.
- How do I organize packages and classes?
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.
- There is no need for an interface for persistence classes.
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.
- EJB Tools?
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.
How do I test my EJB?
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
Count function in EJB-QL now returns Long instead of Integer
I don't know when it changed but now if you cast
em.createNamedQuery("").getSingleResult();
to Integer, it would throw a ClassCastException.
Setting up JBoss 4.0.4.GA for EJB 3.0
I have been able to make EJB 3.0 work before using an old version of JBoss.
Now that JEE5 is officially released, I'm trying to revisit my old work.
Here are my experiences so far.
Hopefully, it will help others who might encounter the same problems.
I would appreciate feedback on how I can improve this.
I'm using Eclipse Webtools for development.
Eclipse version: 3.2.0 Webtools version: 1.5.0
JBoss and MySQL for deployment.
JBoss version: JBoss-4.0.4.GA and EJB 3.0 RC8
Issues encountered:
- After creating new EAR file and EJB file associated together.
I got an error:
An EJB module must contain one or more enterprise beans. Intranet-EJB/ejbModule/META-INF ejb-jar.xml line 5
Explanation: Webtools only support up to EJB 2.1. Since EJB 3.0 doesn't need ejb-jar.xml, we can safely delete it. However, the compiler will give a warning like the one below. Just ignore it.
CHKJ2905W: The EJB Validator did not run because ejb-jar.xml could not be loaded. Run the XML validator for more information. Intranet-EJB Unknown
- After adding an EJB3 class, There are compilation errors because EJB3 libraries are not found.
Explanation: Webtools currently support only up to EJB 2.1. We have to add EJB 3.0 support to the core JBoss installation.To do this, install EJB 3.0 RC8And follow instructions in the INSTALL.html.
EJB 3.0 files not compiling, libraries not found.
For ejb classes:
/server/default/lib/ejb3-persistence.jar
/server/default/lib/ejb3.deployer/jboss-ejb3x.jar
These files need to be added in Eclipse build path.
Note that you can use the JBoss default setup instead of the all setup as mentioned in the INSTALL.html.
Don't include ejb3-clustered-sfsbcache-service.xml and ejb3-entity-cache-service.xml if you're using the default setup because they are for the JBoss all setup only and not for default setup.
To test, run JBoss and you shouldn't encounter any errors. Try to deploy EJB3Trail.ear to deploy folder and it should work. For now, it will not work because there are missing files. See below.
- There are some missing files that were mentioned in the INSTALL.html.
Explanation:
Forum users are complaining about it here: http://www.jboss.com/index.html?module=bb&op=viewtopic&t=84310.
One of them, Sverker, created an unofficial patch: http://www.abrahamsson.com/jboss-EJB-3.0_RC8-FD-sverker.zip
Download the zip file and read README.txt. The file contains all the needed files to start the server correctly. However, there are still some missing files, which will be discussed below.
- I'm getting an error when running the server.
The error message is:
[ServiceController] Problem starting service jboss.j2ee:service=EJB3,module=Intranet-EJB.jarjava.lang.RuntimeException: Field private javax.persistence.EntityManager com.tougher.intranet.impl.service.employee.UnitServiceImpl.em @PersistenceUnit in error: EMPTY STRING unitName but there is no deployments in scope at org.jboss.ejb3.injection.PersistenceContextHandler.loadFieldDependencies(PersistenceContextHandler.java:358)
Explanation: The keyword here is "there is no deployment in scope". It means there is no EntityManager because there's no Persistence Context. We have to add persistence.xml in the EJB file. We need for it to point it to our DataSource.
After adding persistence.xml, the job is not quite done. Make sure your jdbc jar files are added to jboss lib folder, and then add the DataSource file in jboss deploy folder. Set url, username and password. Restart server and the problem should be gone.
- When running EJB via a client remotely,I'm getting org.jboss.aop.Interceptor not found.
Explanation: Client needs these jars found in <jboss>\client.
hibernate-client.jar
jbossall-client.jar
jboss-ejb3-client.jar
jboss-aop-jdk50-client.jar
jboss-aspect-jdk50-client.jar
Now, even the jboss-EJB-3.0_RC8-FD-sverker.zip file doesn't have the last two jars. I got it from an older version (jboss-4.0.4.CR2).
Honestly, what's with JBoss these days? They seemed to be doing very well prior to this release...
- There's a weird message I get when I run my client
Using ThreadLocal: falseinvoke called, but our invoker is disconnected, discarding and fetching another fresh invoker for: InvokerLocator [socket://10.10.0.2:3873/]connect called for: org.jboss.remoting.transport.socket.SocketClientInvoker@50988
Explanation: It's not doing any harm so I just ignore it. I've seen it being asked about in the forums; no answer so far.
- How to effect changes in EAR or EJB?
After you change something in your EJB or EAR,you can effect the changes by going to Servers->Jboss->Publish. You don't have to restart.
- Can I debug a persistence class?
I'm surprised that we now can. Sweet.
It appears as a stub first when it stops at the breakpoint. After I associated it with the source code, I'm able to step through it.
- Persistence class not Serializable
If your persistence class don't implement Serializable, you'll get an exception.