EJB pass-by-reference in JBoss EAP 7 / 6

Solution Verified - Updated -

Environment

  • Red Hat JBoss Enterprise Application Platform (EAP)
    • 7
    • 6

Issue

  • EJB A in EAR 1 calls EJB B in EAR 2. The calls succeed but have performance issues due to serialization.

  • We have set the following option in the JBoss EAP ejb3 subsystem:

    <subsystem xmlns="urn:jboss:domain:ejb3:1.3">
        ...
        <in-vm-remote-interface-invocation pass-by-value="false"/>
        ...
    </subsystem>
    

    But when there are two ears packaging the ejb interfaces and transfer objects, a ClassCastException is thrown. Shouldn't pass-by-reference be used only if the classloaders are the same?

  • The ClassCastException occurs when trying to read an object from the list passed from an EJB with code like:

    public TransferReturnValue hellos ( List<TransferParameter> params )
    {
        for(TransferParameter param : params) {    // ClassCastException is thrown here
        log.info("received param: " + param.getValue());
        }
        return new TransferReturnValue ( "Hello " + params );
    }
    
  • Which mechanism is the default for same-VM EJBs: pass-by-reference or pass-by-value?

  • What is the ideal scenario to use pass-by-reference ?

  • What is the difference between using @Local and @Remote?
  • Does JBoss EAP 6 or 7 support the system property -Dorg.jboss.ejb3.remoting.IsLocalInterceptor.passByRef=true from version 5?

Resolution

  • The recommended approach is to use the local interface whenever pass-by-reference is to be used.

  • If using local interface is not feasible, There is a JBoss specific (non-JavaEE specification) option to have JBoss use pass-by-reference when remote interfaces are used. Please read the Notes and Warnings carefully below.

  • By default:

    • pass-by-value mechanism is being used if your are looking for EJB's Remote interface no matter whether it is local JVM or remote JVM
    • pass-by-reference mechanism is always being used if you are calling EJB's Local interface
  • Using pass-by-reference explicitly makes sense only when the EJB's Remote interface is being called within the same JVM.

Note: pass-by-reference can only be used if the classloader of the EJB interfaces & transfer objects is the same on the client application and EJB side. If pass-by-value="false" is specified means "pass-by-reference" is being used then JBoss EAP 6 will do a shallow check instead of deep check for class loaders.

Warning: This shallow check means that if an object contains other objects such as a List<MyObject> for example, JBoss EAP will only look at the List object and not at the objects contained within the List object. This means that the objects in the List itself could be loaded with different classloaders and result in a ClassCastException. JBoss EAP does not perform a deep check to confirm that there would not be a ClassCastException, because to confirm that JBoss would have to check the entire object graph and doing this is an expensive operation of cloning/marshalling and this is performed only in the case of pass-by-value.

Disable pass-by-value (= enable pass-by-reference) at the client level :

  • Individual applications can override the default pass-by-value semantic by setting a per application level configuration which then uses pass-by-reference semantics for in-VM calls on the remote interfaces of the bean. The current setting is allowed in a jboss-ejb-client.xml of the application as follows:

    <jboss-ejb-client xmlns="urn:jboss:ejb-client:1.0">
        <client-context>
            <ejb-receivers local-receiver-pass-by-value="false"/>
        </client-context>
    </jboss-ejb-client>
    

    Note:

    • The jboss-ejb-client.xml is packaged in the top level deployment in the META-INF directory. So if the top level deployment is an ear, you would need to package it in my.ear/META-INF/.
    • A top level deployment is a deployment that is not a sub deployment. A war in the deployments directory would be a top level deployment and the jboss-ejb-client.xml would go in the WEB-INF folder of this war. However if the war is a sub deployment of an ear, then the jboss-ejb-client.xml would go in the ear's META-INF folder. If the jboss-ejb-client.xml is in a sub deployment then there will be a WARN message printed as shown below indicating it is not in the correct location:

      WARN [org.jboss.as.ee] (MSC service thread 1-8) JBAS011013: /$JBOSS_HOME/standalone/deployments/client.ear/client.war/WEB-INF/jboss-ejb-client.xml in subdeployment ignored. jboss-ejb-client.xml is only parsed for top level deployments.

  • Attached is an example, which demonstrates how you are configure, identify and make the 'pass-by-reference' work with jboss-ejb-client.xml.

Disable pass-by-value (= enable pass-by-reference) globally :

  • This is how pass-by-value can be disabled at the subsystem level as described below :

    • With the CLI management:

      $ bin/jboss-cli.sh -c
      [standalone@localhost:9999 /]  /subsystem=ejb3:write-attribute(name=in-vm-remote-interface-invocation-pass-by-value, value=false)
      
    • The XML results looks like this:

      <subsystem xmlns="urn:jboss:domain:ejb3:1.2">
      ...
          <!-- Disable pass-by-value for in-vm remote interface invocations on EJBs -->
          <in-vm-remote-interface-invocation pass-by-value="false"/>
      </subsystem>
      

    Note: This is not recommended as it will affect all applications and JBoss will perform the shallow check for all applications deployed.

Attachments

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.