Link to home
Start Free TrialLog in
Avatar of kgilpin
kgilpin

asked on

JBoss : Deployment options of shared code

We have a set of common libraries (utilities classes, Hibernate beans) that are used by multiple different J2EE applications. With Weblogic, each application is an EAR file that contains all of its JARs, plus a manifest in the EJB JAR. This works quite nicely. Each application is independent from the rest, which means that we can apply patches to individual applications on our production server, we can hot deploy the entire application, etc.

In JBoss, the default classloader architecture seems to encourage putting all the shared stuff in the [server]/lib folder. However, if I understand correctly, this code will not be hot-deployable, which really defeats the purpose of using a container in my mind (the whole reason I am learning JBoss is because I am fed up with Weblogic's unreliability while hot-deploying).

So, I tried building my EARs with a jboss-app.xml which creates a separate classloading context for each application. I was happy and thought this was working nicely, until I tried an application which looks up Home interfaces from the global JNDI namespace. What happened then is that the objects in JNDI were implementing separately loaded instances of the RemoteHome and RemoteSession interfaces, so PortableRemoteObject.narrow threw ClassCastException. I attempted to work around this problem by trying to figure out how to make JBoss use a non-JNP connection to JNDI, but I don't see a way to do this other than the HTTP invoker. Using the HTTP invoker inside the container is a big hack, but I decided to try it anyway; unfortunately this approach also failed (stack trace below).

So now I am 100% stuck. I can't deploy everything in [server]/lib, because then it won't hot deploy (right?). I also can't deploy everything in their own classloaders, because then I can't use remote Session beans through JNDI.

Surely people do stuff like this all the time. What is the right answer for my deployment situation? I have learned a lot about JBoss, and that is good. But I am ready for it all to start working now.

All this code is currently in production on a Weblogic server, so whatever my problems are they are JBoss-specific.

- kevin

Attempt to use HTTP JNDI provider:

12:41:44,986 WARN [HttpNamingContextFactory] Invalid reply content seen: class
org.jboss.invocation.InvocationException
java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream
.java:2165)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputS
tream.java:2634)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:734
)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:253)
at org.jboss.invocation.http.servlet.InvokerServlet.processRequest(Invok
erServlet.java:117)
Avatar of vzilka
vzilka

Since each class is loaded in its own EAR, are you sure you have the same version of the remote interface and home interface in the EAR file of the calling EJB and the component itself?
Did you try to remove the jboss-application.xml and see what happens?
Avatar of kgilpin

ASKER

Each app definitely has the same version of the class, because both EARs package the same JAR file (Base.jar).

If I remove the jboss-app.xml, then this part of the application works. But I get LinkerErrors (in Struts) when I hot deploy. Even if I didn't get LinkerErrors, I still would want to use the jboss-app.xml, because it is important to me to be able to independently replace the JAR files in the different applications. If I want to fix a bug in one application, I don't want to have to verify that all the other applications will work with the patched code.

I believe my problem could be reproduced in a simple manner. First, write a remote Home and Session interface. Package these interfaces into Base.jar. Then, write an EJB 'A' which implements these interfaces, and package it into A-ejb.jar. Then put both Base.jar and A-ejb.jar in an EAR file, along with a Class-Path in the manifest of A-ejb.jar that references Base.jar, and a jboss-app.xml. Next, write another EJB or web application that also packages Base.jar and also has a jboss-app.xml. This application should look up A using its global JNDI name and try to PortableRemoteObject.narrow it to the Home interface. This will fail with ClassCastException in JBoss; works fine in Weblogic 7.

Removing the jboss-app.xmls will enable application B to use bean A, but it will prevent A and B from being hot-deployable if something in Base.jar changes.
Can you put a log command that will detail the type of class you are getting? Try to remove the narrow command, and maybe do something like this:

Object o = ic.lookup("...");
System.out.println(o.getClass().getName());
System.out.flush();

The way I see it, either you ahve a faulty versioning of the class file (maybe the classpath is not configured correctly, and you are actually getting a class from someplace else - either the EJB returns something weird or your code classpath is broken) or that JBoss is trying to move the object in memory (since both files are deployed on the same server), doesn't notice that the classloader that loaded the classes is different, and then JBoss breaks.

I guess you are using JBoss 3.2.2, as this is a relatively new feature.
Avatar of kgilpin

ASKER

I have put in such a log command. Specifically, what I did was print out

  o.getClass()
and
  Arrays.asList( o.getClass().getInterfaces() )

The o.getClass() is a Proxy class which doesn't tell you much about what it really is. The getInterfaces() prints out the remote Session interface that I expect the object to implement.

I am quite sure that the problem is that JBoss is assuming that it can, as you say, move the object in memory, not realizing that the client and the bound object implement 2 instances of the same interface, loaded in different ClassLoaders.
Avatar of kgilpin

ASKER

I have submitted a bug report to JBoss:

http://sourceforge.net/tracker/index.php?func=detail&aid=845157&group_id=22866&atid=376685

I will award the points for a workaround which solves the ClassCastException problem, or some demonstration that what I am seeing is not a JBoss bug. It would also be great to see someone reproduce this problem so I know that I am not misinterpreting what I am seeing.
Since this is a new feature in JBOss class loading mechanism, and some guys from my company run into similar (but not the same) issues, I guess that the best thing to do is not to use the different class loaders in JBoss, but use a single one for all EAR files.
If you have issues with that, put the shared files inside the lib directory. they shouldn't change much anyway.
IDEA - how about putting the JAR file externally, encapsulate all needed business logic using EJBs, and then deploy just this JAR file?
This way, all EAR files can use this EJB, it is hot deployed, deployed only once.
kgilpin, was this helpful?
Avatar of kgilpin

ASKER

Well, I need to be able to hot deploy everything. The problem with sharing a JAR file across EARs is that if I change something in that JAR file, I may potentially break every application. So I have to test every application before I deploy the change. If each application has its own copy of the shared JAR, I only need to test the one application that I am re-deploying.

I guess I didn't quite catch the meaning of your idea. Do you mean that the shared code would all be in an EAR file, and each application would access the shared code in this EAR file? Or will JBoss deploy a JAR file for me and allow me to hot-deploy that JAR? If the shared code is in an EAR, do I have to access all its functionality through EJB interfaces, or can I simply import classes from it and know that they will be available in the classpath? How are the other applications affected when the shared EAR/JAR is re-loaded? They will still have references to the old classes. Thanks for the follow-up.
ASKER CERTIFIED SOLUTION
Avatar of vzilka
vzilka

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial