|
|
Webapp libraries and EJB libraries
|
The Rule
Never ever put your EJBs in your WEB-INF directories. The same rule applies
to any libraries needed by your EJBs.
The Consequences
If you break the rule, you will be riddled with ClassCastExceptions like the following:
java.lang.ClassCastException
at org.apache.jsp.test$jsp._jspService(test$jsp.java:102)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:107)
...
java.lang.ClassCastException
at com.sun.corba.se.internal.javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:293)
...
Java Classloading Rules
By rule of the Java Language, two classes are only the same if they have the same type AND they were loaded by the same classloader!
Webapp Classloader vs. Common Classloader
In Tomcat, each webapp has it's very own classloader, called it's Webapp Classloader.
When OpenEJB is loaded into Tomcat, it is loaded into Tomcat's Common Classloader.
Classes in the Common Classloader are automatically available to all the Webapp classloaders.
Having OpenEJB in the Common Classloader makes OpenEJB and your EJBs available to all webapps.
There is an important thing to know about the Webapp Classloader; it will always load classes from the WEB-INF/classes or WEB-INF/lib directories even if the same class is available in the Common Classloader.
Remember the Java classloading rules? If your webapp loads a class file from the Webapp Classloader and OpenEJB loads the same class file from the Common Classloader, are they the same class? NO, definitly not!
The Rule Revisited
This brings us back to our rule: never ever put your EJBs in your WEB-INF directories. The same rule applies
to any libraries needed by your EJBs.
OpenEJB creates instances and implementations of the EJBHome and EJBObject using classes it finds in
it's classloader (the Common Classloader). When your Servlet or JSP looks up an EJB, OpenEJB will
generate an implementation of that bean's EJBHome interface and send it to the servlet.
If your servlet's classloader (the Webapp Classloader) already loaded the class into
it's classloader, you have a situation where the exact same class
exists in two different classloaders. When
you try to cast one classloader's version to another classloader's
version, everything blows up.
|
|