Please document Pass-By-Value semantics.
Our project team has developed a number of general-purpose EJBs, and these have evolved over time. Many of these EJBs depend on shared class libraries that also evolve over time. Now imagine that we have two general-purpose EJBs (called EJB1 and EJB2) that are deploed into jBoss and utilized by our application. EJB1 and EJB2 both use the library SHARED1.
Now, SHARED1 has evolved over time. In fact, EJB1 uses an older version of SHARED1, while EJB2 uses a version that has a few more methods available in it. Also, EJB2 has an ejb-ref to EJB1, indicating that EJB2 depends on EJB1.
Given the current jBoss deployment scenario, we have three options when it comes to the UnifiedClassloaders:
1. Deploy EJB1 and EJB2 in the same scope.
This is the default jBoss 3.2 behavior, and is easily achieved by adding nothing extra to the deployment desciptors in the EAR. It can also be achieved using the jboss-app.xml descriptor specifiying the same name for the <loader-repository> tag.
This approach will limit any duplicate class definitions (such as all of the classes in SHARED1) to the first one encountered by the classloader. If the SHARED1 (older version) in EJB1 gets loaded first, then EJB2 will not have access to the newer methods in its copy of SHARED1. This will manifest by receiving the NoSuchMethodError exception.
2. Deploy EJB1 and EJB2 in separate scopes.
This is achieved by adding a META-INF/jboss-app.xml descriptor to the ear files and specifying different values for the <loader-repository> tag. With this approach, EJB1 and EJB2 will use their own individual classloaders.
This approach gives each EJB access to their own SHARED1 library. However, EJB2 will eventually need to invoke a method on EJB1, and when it goes to lookup the Home interface in JNDI it can run into casting problems. Specifically, it attempts to cast the JNDI embedded value (UCL1->EJB1Home) as EJB2->EJB1Home. This causes the ClassCastException since these classes cannot be directly cast to each other.
3. Change the packaging of the EJB's HOME interfaces
By using scoped classloaders, it should be possible to move the Home interfaces for EJB1 into the base UnifiedClassloader (system classloader), but this seems mucho intrusive. This can be further complicated when third-party EJBs are involved.
Apparently, the PortableRemoteObject.lookup behavior can be changed to use Pass-By-Value semantics rather than the default Pass-By-Reference approach, and this should solve the only shortcoming in scenario #2 above.
Scott documented in a bug report (see reference) that pass-by-value is activated by editing the client interceptors and alluded to changing the way InitialContext is initiated. Perhaps the change he mentions regarding InitialContext lookups are necessary, but this would kill our portability and seems way too intrusive.
Nevertheless, I have made changes to the interceptors and the InitialContext in a small testcase without any affect. I still
continue to get ClassCastExceptions. Please provide the complete docs on how to implement pass-by-value.
1. Can the jBoss team provide complete documentation on how to get scenario #2 above working on jBoss 3.2 RC2?
2. Does pass-by-value limit the application developer or performance of the app server in any way? (other than the cost of the lookup which I assume will now require some serialization as opposed to a simple cast. at least we are in the same VM.)
3. Does the pass-by-value behavior require all of the InitialContext creation in our code to be affected? If so, this seems like a really bad idea. Perhaps it can be made dependent on a server config option?