This issue is caused by the test.ejb.ProcessorLocalHome class being loaded by two different classloaders, one classloader for each EAR (which is the WAS default).
The EJB spec itself is fairly silent on whether EJB local (pass-by-reference) interfaces may be used across Java EE applications (i.e. different EAR files). It says that the caller and callee must be in the same JVM, but is silent on the other aspects that factor into whether it will work or not. One aspect that Paul mentioned is that there’s no spec-defined way to look up a local interface within the global JNDI namespace; this means that the only way to get ahold of a local interface is through an ejb-local-ref element in the calling application, along with using an ejb-link element to point the local-ref at the target local interface. The syntax for ejb-link only allows for pointing at EJBs within the same EAR file as the caller, not across EAR files. WAS allows you to set an external EJB binding in the calling EAR using a global JNDI name (seemingly for the remote interface), but under the covers WAS modifies the data from the binding to get the local interface inste
ad. This “modification” is hidden from the user and unfortunately has caused a fair amount of customer confusion when debugging.
After getting past the naming issue, the next issue that commonly comes up is the ClassCastException. It’s not commonly understood that when two classloaders load the exact same Java .class file, objects created from the two classloaders are still NOT type-assignable to each other even though they implement the same class name (and even if they’re based on the same .class file). In this case the generated test.ejb.EJBLocalStatelessProcessHome_6f83b3f2 class DOES implement test.ejb.ProcessorLocalHome, but it implements the test.ejb.ProcessorLocalHome that was loaded by the other application’s classloader. Thus, when the calling app tries to assign the instance to a variable of test.ejb.ProcessorLocalHome, you get a ClassCastException.
One way to prevent this is to use a remote interface. As Paul mentioned, there is optimization that happens when the caller and callee are in the same JVM, so it’s not as expensive as if they’re in separate JVMs. The ORB has classloader machinery that ensures the classes for the caller and callee are loaded using classloaders compatible with each side of the call.
Option 2, including the ejb jar within the new ear, won’t solve the problem. Even though the classes will be available in both classloaders, the object passed by-reference from callee back to caller will still be instanciated using the other application’s classloader and will not be type-assignable. Same with Option 3.
The 2nd way to make it work is to place the classes used by caller and callee in a “WAS shared library” and configure both applications to use that shared library. The subject of shared libraries and how to configure them is described in the WAS InfoCenter documentation…search on “shared library.”
The 3rd way to make it work, which is the least desirable of the three, is to change the WAS server classloader policy to “one classloader per server.” The default, as I mentioned at the top, is “one classloader per application (EAR file).” Changing to one classloader per server ensures that everything gets loaded by the same classloader and is thus type-compatible, but deprives your applications of the isolation/security benefits that come from having each app in its own classloader.