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.


 

My logo for the front page.

 

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:



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



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.



Explanation:


Forum users are complaining about it here: http://www.jboss.com/index.html?module=bb&amp;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.



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.



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...



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.



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.



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.



If your persistence class don't implement Serializable, you'll get an exception.


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