OpenEJBIndexJNDIEJBClassInvoke
   



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.