UnifiedInvoker and UnifiedInvokerHA


1. Overview
2. UnifiedInvoker
3. Changing UnifiedInvoker transport
4. Handling configuration dependencies between UnifiedInvoker and Connector
5. Clustering - UnifiedInvokerHA
6. Making UnifiedInvoker/UnifiedInvoker default EJB invoker

1. Overview

The JBoss Application Server uses detached invokers for making remote service invocations. These invokers are best known within the context of making EJB 2.x invocations. Traditionally each implementation of these invokers are specific to the transport protocol they use to make the remote invocation. The UnifiedInvoker is a detached invoker implementation which uses JBoss Remoting in order to abstract out the transport protocol being used so that the same implementation can be used regardless of transport. For more information on the detached invokers in general, please refer to the 2.7. Remote Access to Services, Detached Invokers section of the JBoss Application Server Guide.

2. UnifiedInvoker

Since the UnifiedInvoker uses JBoss Remoting to handle the actual transport for the remote invocations, will need to first review how JBoss Remoting works at a high level. For more details on JBoss Remoting, please refer to the JBoss Remoting product page (http://www.jboss.com/products/remoting).

The main component of JBoss Remoting is the Connector. This binds the transport invoker with the handler of the invocation. The Connector can have one more handlers that receive and process invocation requests. The UnifiedInvoker is considered a handler (more on this below).

The first thing that is needed is declaring the UnifiedInvoker as a service. An example of a UnifiedInvoker configuration can be found within the jboss-service.xml under the server node's conf directory. The default UnifiedInvoker declaration should look similar to the following:

   <!-- Unified invoker (based on remoting) -->
   <mbean code="org.jboss.invocation.unified.server.UnifiedInvoker"
      name="jboss:service=invoker,type=unified">
      <!-- To turn on strict RMI exception propagation uncomment block below -->
      <!-- This will cause the UnifiedInvokerProxy to wrap RemoteExceptions  -->
      <!-- within a ServerException, otherwise will throw root exception     -->
      <!-- (not RemoteException)                                             -->
      <!-- <attribute name="StrictRMIException">true</attribute> -->
      <depends>jboss:service=TransactionManager</depends>
      <depends>jboss.remoting:service=Connector,transport=socket</depends>
   </mbean>

This simply declares the UnifiedInvoker and the services that it depends on. Notice the depends on the connector, specified by its ObjectName.

Next, the Connector must be declared. An example of a Connector configuration can be found within the jboss-service.xml under the server node's conf directory. The default Connector declaration should look similar to the following:

   <!-- The Connector is the core component of the remoting server service. -->
   <!-- It binds the remoting invoker (transport protocol, callback configuration, -->
   <!-- data marshalling, etc.) with the invocation handlers.  -->
   <mbean code="org.jboss.remoting.transport.Connector"
          xmbean-dd="org/jboss/remoting/transport/Connector.xml"
          name="jboss.remoting:service=Connector,transport=socket"
          display-name="Socket transport Connector">

       <!-- Can either just specify the InvokerLocator attribute and not the invoker element in the -->
       <!-- Configuration attribute, or do the full invoker configuration in the in invoker element -->
       <!-- of the Configuration attribute. -->

       <!-- Remember that if you do use more than one param on the uri, will have to include as a CDATA, -->
       <!-- otherwise, parser will complain. -->
       <!-- <attribute name="InvokerLocator"><![CDATA[socket://${jboss.bind.address}:4446/?datatype=invocation]]></attribute> -->

      <attribute name="Configuration">
         <!-- Using the following <invoker> element instead of the InvokerLocator above because specific attributes needed. -->
         <!-- If wanted to use any of the parameters below, can just add them as parameters to the url above if wanted use the InvokerLocator attribute. -->
         <config>
            <!-- Other than transport type and handler, none of these configurations are required (will just use defaults). -->
            <invoker transport="socket">
               <attribute name="dataType" isParam="true">invocation</attribute>
               <attribute name="marshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationMarshaller</attribute>
               <attribute name="unmarshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationUnMarshaller</attribute>
               <!-- This will be port on which the marshall loader port runs on.  -->
               <!-- <attribute name="loaderport" isParam="true">4447</attribute> -->
               <!-- The following are specific to socket invoker -->
               <!-- <attribute name="numAcceptThreads">1</attribute>-->
               <!-- <attribute name="maxPoolSize">303</attribute>-->
               <!-- <attribute name="clientMaxPoolSize" isParam="true">304</attribute>-->
               <attribute name="socketTimeout" isParam="true">600000</attribute>
               <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
               <attribute name="serverBindPort">4446</attribute>
               <!-- <attribute name="clientConnectAddress">216.23.33.2</attribute> -->
               <!-- <attribute name="clientConnectPort">7777</attribute> -->
               <attribute name="enableTcpNoDelay" isParam="true">true</attribute>
               <!-- <attribute name="backlog">200</attribute>-->
               <!-- The following is for callback configuration and is independent of invoker type -->
               <!-- <attribute name="callbackMemCeiling">30</attribute>-->
               <!-- indicates callback store by fully qualified class name -->
               <!-- <attribute name="callbackStore">org.jboss.remoting.CallbackStore</attribute>-->
               <!-- indicates callback store by object name -->
               <!-- <attribute name="callbackStore">jboss.remoting:service=CallbackStore,type=Serializable</attribute> -->
               <!-- config params for callback store.  if were declaring callback store via object name, -->
               <!-- could have specified these config params there. -->
               <!-- StoreFilePath indicates to which directory to write the callback objects. -->
               <!-- The default value is the property value of 'jboss.server.data.dir' and if this is not set, -->
               <!-- then will be 'data'. Will then append 'remoting' and the callback client's session id. -->
               <!-- An example would be 'data\remoting\5c4o05l-9jijyx-e5b6xyph-1-e5b6xyph-2'. -->
               <!-- <attribute name="StoreFilePath">callback</attribute>-->
               <!-- StoreFileSuffix indicates the file suffix to use for the callback objects written to disk. -->
               <!-- The default value for file suffix is 'ser'. -->
               <!-- <attribute name="StoreFileSuffix">cst</attribute>-->
            </invoker>

            <!-- At least one handler is required by the connector.  If have more than one, must declare -->
            <!-- different subsystem values.  Otherwise, all invocations will be routed to the only one -->
            <!-- that is declared. -->
            <handlers>
               <!-- can also specify handler by fully qualified classname -->
               <handler subsystem="invoker">jboss:service=invoker,type=unified</handler>
            </handlers>
         </config>
      </attribute>
      <depends>jboss.remoting:service=NetworkRegistry</depends>
   </mbean>

This configuration, although rather long due to is showing all the possible configuration options available, declares a Connector with an remoting invoker that uses the socket transport and has a the previously declared UnifiedInvoker defined as its handler, using the UnifiedInvoker's ObjectName. Please refer to the JBoss Remoting documentation for more information about specific configuration of the different remoting invoker transports.

One important note; the Connector does have a depends declared for the NetworkRegistry. This is a JBoss Remoting specific requirement and allows for the Connector to be registered in a global directory for remote discovery. All that is needed to declare the NetworkRegistry is the following:

    <mbean code="org.jboss.remoting.network.NetworkRegistry"
           name="jboss.remoting:service=NetworkRegistry"/>

This is all that is required for declaring the UnifiedInvoker within JBoss. Once the JBoss server is run, it will create and start both the JBoss Remoting Connector and the UnifiedInvoker. Any requests that come into the Connector, via the socket listening on port 4446, will be forwarded onto the UnifiedInvoker.

3. Changing UnifiedInvoker transport

To change the transport the UnifiedInvoker uses, only the Connector configuration needs to be changed. More information about how to change the Connector transport and the configuration attributes available for the specific transports can be found within the JBoss Remoting documentation. Using the previous example, if wanted to change the UnifiedInvoker to use RMI transport instead of the socket one, would only need to change the Connector configuration above to:

   <mbean code="org.jboss.remoting.transport.Connector"
          xmbean-dd="org/jboss/remoting/transport/Connector.xml"
          name="jboss.remoting:service=Connector,transport=socket"
          display-name="Socket transport Connector">

      <attribute name="Configuration">
         <config>
            <invoker transport="rmi">
               <attribute name="dataType" isParam="true">invocation</attribute>
               <attribute name="marshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationMarshaller</attribute>
               <attribute name="unmarshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationUnMarshaller</attribute>
               <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
               <attribute name="serverBindPort">4446</attribute>
            </invoker>

            <handlers>
               <!-- can also specify handler by fully qualified classname -->
               <handler subsystem="invoker">jboss:service=invoker,type=unified</handler>
            </handlers>
         </config>
      </attribute>
      <depends>jboss.remoting:service=NetworkRegistry</depends>
   </mbean>

A good bit of the extra comments and attributes specific to the socket transport were removed, but the main change was to change the invoker transport attribute value from socket to rmi. It would also be a good idea to change the ObjectName declared for the Connector to reflect that the transport is now rmi instead of socket as well, but technically not required.

To change the UnifiedInvoker to use HTTP transport instead of the socket one, there are a few more changes required. The following is an example of a Connector configuration using the http transport to be used by the UnifiedInvoker:

   <mbean code="org.jboss.remoting.transport.Connector"
          xmbean-dd="org/jboss/remoting/transport/Connector.xml"
          name="jboss.remoting:service=Connector,transport=socket"
          display-name="Socket transport Connector">

      <attribute name="Configuration">
         <config>
            <invoker transport="http">
               <attribute name="dataType" isParam="true">httpinvocation</attribute>
               <attribute name="marshaller" isParam="true">org.jboss.invocation.unified.marshall.HTTPInvocationMarshaller</attribute>
               <attribute name="unmarshaller" isParam="true">org.jboss.invocation.unified.marshall.HTTPInvocationUnMarshaller</attribute>
               <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
               <attribute name="serverBindPort">4446</attribute>
            </invoker>

            <handlers>
               <!-- can also specify handler by fully qualified classname -->
               <handler subsystem="invoker">jboss:service=invoker,type=unified</handler>
            </handlers>
         </config>
      </attribute>
      <depends>jboss.remoting:service=NetworkRegistry</depends>
   </mbean>

As expected, the transport attribute value needs to be http. Will also notice that the dataType attribute value and the marshaller and unmarshaller attribute values have changed. To understand why these changes, need a little background on how remoting works. Each remoting transport invoker will use a marshaller and unmarshaller for converting Objects to wire format and back into Objects again. The InvocationMarshaller and InvocationUnMarshaller does this, plus takes care of some extra processing such as converting transaction contexts, which can not be serialized outright. Because the HTTP transport is a bit different in how it does its processing of the wire protocol (pre-reading headers, etc.) compared to the other pure socket based transports (i.e. socket, rmi, multiplex), a HTTP specific marshaller and unmarshaller is needed.

The dataType signifies the type of data that will be processed and is the name that will be used for identifying which marshaller/unmarshaller pair should be used. Once a marshaller and unmarshaller have been attached to a particular data type, they will be cached for later use and looked up via the data type. This is why the value for the dataType value should be changed if using the http transport for UnifiedInvoker. Otherwise, if using an UnifiedInvoker with http transport and another UnifiedInvoker with another transport, both with the same value for the dataType, then the first one loaded will be used for marshalling/unmarshalling for both UnifiedInvokers. This really only comes into play when using clustering (UnifiedInvokerHA, which will be discussed below).

As a side note, the actual value of the dataType attribute can be any free form string, but suggest keeping to the naming convention used here.

4. Handling configuration dependencies between UnifiedInvoker and Connector

As already discussed previously, there is an explicitly dependency between the UnifiedInvoker and the remoting Connector. Since the UnifiedInvoker is a remoting handler, the Connector must be made aware of it so it can forward requests to it. Also, the UnifiedInvoker depends on the Connector or would not otherwise be able to receive requests.

This presents an issue in regards to starting the services since there is somewhat of a circular dependency on each other. One way to approach this is illustrated in the previous examples where the UnifiedInvoker is declared before the Connector, but still has a depends tag for the Connector. Then the Connector has the UnifiedInvoker declared as its handler. This allows for the UnifiedInvoker to be constructed before the Connector, but also allows the Connector to have a valid reference to handler when it starts. If the Connector does not have a valid handler when it starts, it will throw an exception and shutdown (since there is no point accepting request is there is no handler to process them).

Another way to handle this issue is to have the Connector declared first without specifying a handler explicitly within the configuration. An example would be:

   <mbean code="org.jboss.remoting.transport.Connector"
          xmbean-dd="org/jboss/remoting/transport/Connector.xml"
          name="jboss.remoting:service=Connector,transport=socket"
          display-name="Socket transport Connector">
      <attribute name="Configuration">
         <config>
            <invoker transport="socket">
               <attribute name="dataType" isParam="true">invocation</attribute>
               <attribute name="marshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationMarshaller</attribute>
               <attribute name="unmarshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationUnMarshaller</attribute>
               <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
               <attribute name="serverBindPort">4446</attribute>
            </invoker>
         </config>
      </attribute>
      <depends>jboss.remoting:service=NetworkRegistry</depends>
   </mbean>

Then later declare the UnifiedInvoker with an depends tag that includes a proxy-type attribute. For example:

   <mbean code="org.jboss.invocation.unified.server.UnifiedInvoker"
      name="jboss:service=invoker,type=unified">
      <depends>jboss:service=TransactionManager</depends>
      <depends optional-attribute-name="Connector"
       proxy-type="attribute">jboss.remoting:service=Connector,transport=socket</depends>
      <depends>jboss:service=${jboss.partition.name:DefaultPartition}</depends>
   </mbean>

Doing a depends tag using this format will tell the container to call the setConnector(ConnectorMBean connector) on the UnifiedInvoker instance once it is instantiated and pass the Connector specified via the ObjectName as the parameter. Then JBoss will create the Connector and then create the UnifiedInvoker because of the depends specified by the UnifiedInvoker configuration. By create, am meaning the create service method as specified by the JBoss service life cycle (see 2.4.2.2. The Service Life Cycle Interface in JBoss Application Server Guide for more information on service life cycle). When the create is called on the UnifiedInvoker, it will add itself as a handler to the Connector previously set. Remember, at this point, neither service has been started. Next, the Connector and then the UnifiedInvoker will be started (in the life cycle sense). This fulfills the Connectors requirement of having a valid handler registered when it is started. This is also key to allowing a UnifiedInvoker and UnifiedInvokerHA to use the same Connector, which will discuss further below.

5. Clustering - UnifiedInvokerHA

As with the other detached invokers, the UnifiedInvoker also has a clustered version, UnifiedInvokerHA (the HA stands for high availability). The UnifiedInvokerHA extends the UnifiedInvoker, but includes the ability to seamlessly failover to other JBoss instances that have the same target resource deployed on it which are part of the cluster.

It is important to understand what fail over means in this case, so will walk through a concrete example (for more detailed information on clustering and how it works, please refer to the Clustering with JBoss documentation). In this example scenario, there are two JBoss server instance that running the clustering service, to include UnifiedInvokerHA, which will refer to as node1 and node2 (and are part of the same clustering partition). Both nodes have an ejb called OrderProcessing deployed on them.

When a client does a JNDI lookup for the OrderProcessing bean, what is actually downloaded to the client is a proxy for the OrderProcessing home interface, which will include the UnifiedInvokerHAProxy (among other things). When create() is called on the home interface, the remote interface for the OrderProcessing bean is also a proxy (which will include the UnifiedInvokerHAProxy). As the client makes calls on the OrderProcessing remote interface, the invocation requests are being handled by the UnifiedInvokerHAProxy. The UnifiedInvokerHAProxy internally contains a list of remote target servers (that have the OrderProcessing ejb deployed on them). In this example, the internal target list would include node1 and node2. It will use a load balancing policy to select the target server to make the remote call on. As part of the response for any invocation request, the server may send an updated list of target servers (in the case a new server comes online or one goes off line). This keeps the internal list of remote target servers on the client in sync with the cluster topology.

If the UnifiedInvokerHAProxy makes a call on a selected target server and the invocation fails to be processed by the server (because the server crashed, the ejb was undeployed on that server, etc.), the UnifiedInvokerHAProxy will then automatically select another target server within its internal collection and make the invocation request on that target server. This continues until the request is either successful and response returned or run out of targets and throws an exception. So for this example, if node1 is selected by the load balancing policy to be the target server, but it has crashed, the UnifiedInvokerHAProxy will then try to make the call on node1. The main point is that the code making the call on the OrderProcessing remote interface would not be aware that there was any error unless none of the target servers can process the request.

There are other clustering features, such as state replication, that are provided by other JBoss services, but the UnifiedInvokerHA is only responsible for failover. Again, for more information on all the clustering features and services, please refer to the Clustering with JBoss documentation.

Although the UnifiedInvokerHA is very similar to the other detached invokers with HA support, it does have one feature that others do not. It is able to fail over to regardless of the transport protocol being used. For example, if have three JBoss servers using UnifiedInvokerHA, but each is using a different remoting transport protocol (i.e. socket, rmi, and http), each can fail over to any of the others.

UnifiedInvokerHA configuration

The configuration for the UnifiedInvokerHA is very similar to its parent, UnifiedInvoker. The only change required is the fully qualified class name specified, as seen below:

  <mbean code="org.jboss.invocation.unified.server.UnifiedInvokerHA"
      name="jboss:service=invoker,type=unifiedha">
      <depends>jboss:service=TransactionManager</depends>
      <depends optional-attribute-name="Connector"
       proxy-type="attribute">jboss.remoting:service=Connector,transport=socket</depends>
      <depends>jboss:service=${jboss.partition.name:DefaultPartition}</depends>
   </mbean>

Will also want to change the ObjectName declared if there is already an UnifiedInvoker declared to avoid collision (which is a good idea regardless).

Another thing to consider is if want to use any other Connector that has been defined. In the example configuration above, the UnifiedInvokerHA will add itself as a handler to the same Connector that was being used by the standard UnifiedInvoker. This is perfectly legal and correct, but will only work if using the depends tag that includes the proxy-type attribute.

It is also possible to create a separate Connector that is used by the UnifiedInvokerHA, if want to use a different transport or even just a different port. Although not required, it is a good idea to define the UnifiedInvokerHA, and its Connector if not using one already defined, within the cluster-service.xml that can be found within the deploy directory of the all node configuration.

6. Making UnifiedInvoker/UnifiedInvoker default EJB invoker

Up to this point, there has been no mention of how to configure the JBoss server to use the UnifiedInvoker or UnifiedInvokerHA instead of one of the other detached invokers, only how to make the service available for use. There are two ways in which to do this for use by ejbs. The first is to set the UnifiedInvoker/UnifiedInvokerHA as the default invoker for all the different ejb types (statefull session beans, stateless session beans, and entity beans). This is done by editing the standardjboss.xml, which can be found in the conf directory. The following is a snippet of this file:

...
  <invoker-proxy-bindings>

    <invoker-proxy-binding>
      <name>entity-jrmp-invoker</name>
      <invoker-mbean>jboss:service=invoker,type=jrmp</invoker-mbean>
      <proxy-factory>org.jboss.proxy.ejb.ProxyFactory</proxy-factory>
      <proxy-factory-config>
        <client-interceptors>
          <home>
            <interceptor>org.jboss.proxy.ejb.HomeInterceptor</interceptor>
            <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
          </home>
          <bean>
            <interceptor>org.jboss.proxy.ejb.EntityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
          </bean>
          <list-entity>
            <interceptor>org.jboss.proxy.ejb.ListEntityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
          </list-entity>
        </client-interceptors>
      </proxy-factory-config>
    </invoker-proxy-binding>
...

This example uses the JRMP invoker by default for non-clustered entity beans. To change to use the UnifiedInvoker, replace the <invoker-mbean> value with that of the ObjectName specified when declaring the UnifiedInvoker. So the change would look like:

...
  <invoker-proxy-bindings>

    <invoker-proxy-binding>
      <name>entity-unified-invoker</name>
      <invoker-mbean>jboss:service=invoker,type=unified</invoker-mbean>
      <proxy-factory>org.jboss.proxy.ejb.ProxyFactory</proxy-factory>
      <proxy-factory-config>
        <client-interceptors>
          <home>
            <interceptor>org.jboss.proxy.ejb.HomeInterceptor</interceptor>
            <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
          </home>
          <bean>
            <interceptor>org.jboss.proxy.ejb.EntityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
          </bean>
          <list-entity>
            <interceptor>org.jboss.proxy.ejb.ListEntityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
            <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
          </list-entity>
        </client-interceptors>
      </proxy-factory-config>
    </invoker-proxy-binding>
...

Also note that the <name> value was changed to reflect that is using the UnifiedInvoker. By making this change, will also need to make sure that the name is update for the actual container configuration. This would require the following change:

... 
<container-configurations>

    <container-configuration>
      <container-name>Standard CMP 2.x EntityBean</container-name>
      <call-logging>false</call-logging>
      <invoker-proxy-binding-name>entity-unified-invoker</invoker-proxy-binding-name>
      <sync-on-commit-only>false</sync-on-commit-only>
      <insert-after-ejb-post-create>false</insert-after-ejb-post-create>
      <call-ejb-store-on-clean>true</call-ejb-store-on-clean>
      <container-interceptors>
        <interceptor>org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor</interceptor>
        <interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>
...

The same process can be applied for all the different ejb types (stateful session bean and stateless session bean). Will also notice that this file has separate declaration for the clustered version. Can set the clustered versions to use UnifiedInvokerHA in the same way, such as:

...
    <invoker-proxy-binding>
      <name>clustered-entity-unified-invoker</name>
      <invoker-mbean>jboss:service=invoker,type=unifiedha</invoker-mbean>
      <proxy-factory>org.jboss.proxy.ejb.ProxyFactoryHA</proxy-factory>
      <proxy-factory-config>
        <client-interceptors>
...

The other way to specify that the UnifiedInvoker should be used is per ejb. This can be done by editing the jboss.xml within the ejb deployment file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC
      "-//JBoss//DTD JBOSS 3.2//EN"
      "http://www.jboss.org/j2ee/dtd/jboss_3_2.dtd">

<jboss>
      <session>
         <ejb-name>OrderProcessingBean</ejb-name>
         <invoker-bindings>
            <invoker>
               <invoker-proxy-binding-name>clustered-stateless-unified-invoker</invoker-proxy-binding-name>
               <jndi-name>OrderProcessingBean</jndi-name>
            </invoker>
         </invoker-bindings>
         <clustered>true</clustered>
      </session>

      <invoker-proxy-binding>
         <name>clustered-stateless-unified-invoker</name>
         <invoker-mbean>jboss:service=invoker,type=unifiedha</invoker-mbean>
         <proxy-factory>org.jboss.proxy.ejb.ProxyFactoryHA</proxy-factory>
         <proxy-factory-config>
            <client-interceptors>
             <home>
               <interceptor>org.jboss.proxy.ejb.HomeInterceptor</interceptor>
               <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
               <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
               <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
               <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
             </home>
             <bean>
               <interceptor>org.jboss.proxy.ejb.StatelessSessionInterceptor</interceptor>
               <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
               <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
               <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor</interceptor>
               <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor</interceptor>
             </bean>
            </client-interceptors>
         </proxy-factory-config>
      </invoker-proxy-binding>
...

The previous snippet is an example jboss.xml deployment file for the OrderProcessingBean. This deployment configuration will over write the standard JBoss invoker configuration and use the UnifiedInvoker instead for this ejb.