Remote Access to Services, Detached Invokers


In addition to the MBean services notion that allows for the ability to integrate arbitrary functionality, JBoss also has a detached invoker concept that allows MBean services to expose functional interfaces via arbitrary protocols for remote access by clients. The notion of a detached invoker is that remoting and the protocol by which a service is accessed is a functional aspect or service that is independent of the component. Thus, you can make a naming service available for use via RMI/JRMP, RMI/HTTP, RMI/SOAP, or any arbitrary custom transport.

Let's begin our discussion of the detached invoker architecture with an overview of the components involved. The main components in the detached invoker architecture are shown in Figure 2.23.

Figure 2.23. The main components in the detached invoker architecture.


On the client side, a client proxy exposes the interface(s) of the MBean service. This is the same smart, compile-less dynamic proxy that you use for EJB home and remote interfaces. The only differences between the proxy for an arbitrary service and the EJB are the set of interfaces exposed and the client-side interceptors found inside the proxy. The client interceptors are represented by the rectangles inside the client proxy in Figure 2.23. An interceptor is an assembly-line type of pattern that allows for transformation of a method invocation and/or return values. A client obtains a proxy through some lookup mechanism, typically JNDI. Although RMI is indicated in Figure 2.23, the only real requirement on the exposed interface and its types is that they are serializable between the client server over JNDI as well as the transport layer.

The choice of the transport layer is determined by the last interceptor in the client proxy, which is referred to as invoker interceptor in Figure 2.23. The invoker interceptor contains a reference to the transport specific stub of the server-side detached invoker MBean service. The invoker interceptor also handles the optimization of calls that occur within the same VM as the target MBean. When the invoker interceptor detects that this is the case, the call is passed to a call-by-reference invoker that simply passes the invocation along to the target MBean.

The detached invoker service is responsible for making a generic invoke operation available via the transport that the detached invoker handles. The Invoker interface illustrates the generic invoke operation:

 package org.jboss.invocation; import java.rmi.Remote; import org.jboss.proxy.Interceptor; import org.jboss.util.id.GUID; public interface Invoker     extends Remote {     GUID ID = new GUID();     String getServerHostName() throws Exception;     Object invoke(Invocation invocation) throws Exception; } 

The Invoker interface extends Remote to be compatible with RMI, but this does not mean that an invoker must expose an RMI service stub. The detached invoker service simply acts as a transport gateway that accepts invocations represented as the org.jboss. invocation.Invocation object over its specific transport, unmarshals the invocation, forwards the invocation onto the destination MBean service, represented by the target MBean in Figure 2.23, and marshals the return value or exception resulting from the forwarded call back to the client.

The Invocation object is just a representation of a method invocation context. This includes the target MBean name, the method, the method arguments, a context of information associated with the proxy by the proxy factory, and an arbitrary map of data associated with the invocation by the client proxy interceptors.

The configuration of the client proxy is done by the server-side proxy factory MBean service, indicated by the proxy factory component in Figure 2.23. The proxy factory performs the following tasks:

  • Creates a dynamic proxy that implements the interface the target MBean wishes to expose.

  • Associates the client proxy interceptors with the dynamic proxy handler.

  • Associates the invocation context with the dynamic proxy. This includes the target MBean, the detached invoker stub, and the proxy JNDI name.

  • Makes the proxy available to clients by binding the proxy into JNDI.

The last component in Figure 2.23 is the target MBean service that wishes to expose an interface for invocations to remote clients. These steps are required for an MBean service to be accessible through a given interface:

1.

Define a JMX operation that matches the signature public Object invoke(org.jboss.invocation.Invocation) throws Exception.

2.

Create a HashMap<Long, Method> mapping from the exposed interface java.lang.reflect.Methods to the long hash representation, using the org.jboss.invocation.MarshalledInvocation.calculateHash method.

3.

Implement the invoke(Invocation) JMX operation and use the interface method hash mapping to transform from the long hash representation of the invoked method to the java.lang.reflect.Method of the exposed interface. Reflection is used to perform the actual invocation on the object associated with the MBean service that actually implements the exposed interface.

A Detached Invoker Example: The MBeanServer Invoker Adaptor Service

As mentioned earlier in this chapter, there is a service that allows you to access the javax.management.MBeanServer via any protocol, using an invoker service. This section presents the org.jboss.jmx.connector.invoker.InvokerAdaptorService and its configuration for access via RMI/JRMP as an example of the steps required to provide remote access to an MBean service.

InvokerAdaptorService is a simple MBean service that only exists to fulfill the target MBean role in the detached invoker pattern (see Listing 2.16).

Listing 2.16. The InvokerAdaptorService MBean
 package org.jboss.jmx.connector.invoker; public interface InvokerAdaptorServiceMBean     extends org.jboss.system.ServiceMBean {     Class getExportedInterface();     void setExportedInterface(Class exportedInterface);     Object invoke(org.jboss.invocation.Invocation invocation)         throws Exception; } package org.jboss.jmx.connector.invoker; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.management.MBeanServer; import javax.management.ObjectName; import org.jboss.invocation.Invocation; import org.jboss.invocation.MarshalledInvocation; import org.jboss.mx.server.ServerConstants; import org.jboss.system.ServiceMBeanSupport; import org.jboss.system.Registry; public class InvokerAdaptorService     extends ServiceMBeanSupport     implements InvokerAdaptorServiceMBean, ServerConstants { private static ObjectName mbeanRegistry; static {     try {         mbeanRegistry = new ObjectName(MBEAN_REGISTRY);     } catch (Exception e) {         throw new RuntimeException(e.toString());     } } private Map marshalledInvocationMapping = new HashMap(); private Class exportedInterface; public Class getExportedInterface() {     return exportedInterface; } public void setExportedInterface(Class exportedInterface) {     this.exportedInterface = exportedInterface; } protected void startService()     throws Exception {     // Build the interface method map     Method[] methods = exportedInterface.getMethods();     HashMap tmpMap = new HashMap(methods.length);     for (int m = 0; m < methods.length; m ++) {         Method method = methods[m];         Long hash = new Long(MarshalledInvocation.calculateHash(method));         tmpMap.put(hash, method);     }     marshalledInvocationMapping = Collections.unmodifiableMap(tmpMap);     // Place our ObjectName hash into the Registry so invokers can     // resolve it     Registry.bind(new Integer(serviceName.hashCode()), serviceName); } protected void stopService()     throws Exception {     Registry.unbind(new Integer(serviceName.hashCode())); } public Object invoke(Invocation invocation)     throws Exception {     // Make sure we have the correct classloader before unmarshaling     Thread thread = Thread.currentThread();     ClassLoader oldCL = thread.getContextClassLoader();     // Get the MBean this operation applies to     ClassLoader newCL = null;     ObjectName objectName = (ObjectName)         invocation.getValue("JMX_OBJECT_NAME");     if (objectName != null) {         // Obtain the ClassLoader associated with the MBean deployment         newCL = (ClassLoader)             server.invoke(mbeanRegistry, "getValue",                           new Object[] { objectName, CLASSLOADER },                           new String[] { ObjectName.class.getName(),                                          "java.lang.String" });     }     if (newCL != null && newCL != oldCL) {         thread.setContextClassLoader(newCL);     }     try {         // Set the method hash to Method mapping         if (invocation instanceof MarshalledInvocation) {             MarshalledInvocation mi = (MarshalledInvocation) invocation;             mi.setMethodMap(marshalledInvocationMapping);         }         // Invoke the MBeanServer method via reflection         Method method = invocation.getMethod();         Object[] args = invocation.getArguments();         Object value = null;         try {             String name = method.getName();             Class[] sig = method.getParameterTypes();             Method mbeanServerMethod =                 MBeanServer.class.getMethod(name, sig);                 value = mbeanServerMethod.invoke(server, args);             } catch(InvocationTargetException e) {                 Throwable t = e.getTargetException();                 if (t instanceof Exception) {                     throw (Exception) t;                 } else {                     throw new UndeclaredThrowableException(t, method.toString());                 }             }             return value;         } finally {             if (newCL != null && newCL != oldCL) {                 thread.setContextClassLoader(oldCL);             }         }     } } 

Let's go through the key details of this service. The InvokerAdaptorServiceMBean Standard MBean interface of the InvokerAdaptorService has a single ExportedInterface attribute and a single invoke(Invocation) operation. The ExportedInterface attribute allows customization of the type of interface the service exposes to clients. It has to be compatible with the MBeanServer class in terms of method name and signature. The invoke(Invocation) operation is the required entry point that target MBean services must expose to participate in the detached invoker pattern. This operation is invoked by the detached invoker services that have been configured to provide access to the InvokerAdaptorService.

Lines 5464 of the InvokerAdaptorService build the HashMap<Long,Method> of the ExportedInterface class, using the org.jboss.invocation.MarshalledInvocation. calculateHash(Method) utility method. Because java.lang.reflect.Method instances are not serializable, a MarshalledInvocation version of the nonserializable Invocation class is used to marshal the invocation between the client and server. The MarshalledInvocation replaces the Method instances with their corresponding hash representation. On the server side, the MarshalledInvocation must be told what the hash-to-Method mapping is.

Line 64 creates a mapping between the InvokerAdaptorService service name and its hash code representation. This is used by detached invokers to determine what the target MBean ObjectName of an Invocation is. When the target MBean name is stored in the Invocation, it is stored by its hashCode because ObjectNames are relatively expensive objects to create. The org.jboss.system.Registry is a global map-like construct that invokers use to store the hash code-to-ObjectName mappings in.

Lines 7793 obtain the name of the MBean on which the MBeanServer operation is being performed and look up the class loader associated with the MBean's SAR deployment. This information is available via org.jboss.mx.server.registry.BasicMBeanRegistry, a JBoss JMX implementation-specific class. It is generally necessary for an MBean to establish the correct class-loading context because the detached invoker protocol layer may not have access to the class loaders needed to unmarshal the types associated with an invocation.

Lines 101105 install the ExposedInterface class method hash-to-Method mapping if the invocation argument is of type MarshalledInvocation. The method mapping calculated at lines 5462 is used here.

Lines 107114 perform a second mapping from the ExposedInterface method to the matching method of the MBeanServer class. The InvokerServiceAdaptor decouples the ExposedInterface from the MBeanServer class in that it allows an arbitrary interface. This is needed on one hand because the standard java.lang.reflect.Proxy class can only proxy interfaces. It also allows you to expose only a subset of the MBeanServer methods and add transport-specific exceptions such as java.rmi.RemoteException to the ExposedInterface method signatures.

Line 115 dispatches the MBeanServer method invocation to the MBeanServer instance to which the InvokerAdaptorService was deployed. The server instance variable is inherited from the ServiceMBeanSupport superclass.

Lines 117124 handle any exceptions coming from the reflective invocation, including the unwrapping of any declared exception thrown by the invocation.

Line 126 is the return of the successful MBeanServer method invocation result.

Note that the InvokerAdaptorService MBean does not deal directly with any transport-specific details. There is the calculation of the method hash-to-Method mapping, but this is a transport-independent detail.

Now let's take a look at how the InvokerAdaptorService can be used to expose the same org.jboss.jmx.adaptor.rmi.RMIAdaptor interface via RMI/JRMP as seen in the section "Connecting to JMX Using RMI," earlier in this chapter. We will start by presenting the proxy factory and InvokerAdaptorService configurations found in the default setup in the jmx-invoker-adaptor-service.sar deployment. Listing 2.17 shows the jboss-service.xml descriptor for this deployment.

Listing 2.17. The Default jmx-invoker-adaptor-server.sar jboss-service.xml Deployment Descriptor

[View full width]

<server> <!-- The JRMP invoker proxy configuration for the InvokerAdaptorService --> <mbean code="org.jboss.invocation.jrmp.server.JRMPProxyFactory" name="jboss.jmx:type=adaptor,name=Invoker,protocol=jrmp, service=proxyFactory"> <!-- Use the standard JRMPInvoker from conf/jboss-service.xml --> <attribute name="InvokerName">jboss:service=invoker,type=jrmp</attribute> <!-- The target MBean is the InvokerAdaptorService configured below --> <attribute name="TargetName">jboss.jmx:type=adaptor,name=Invoker </attribute> <!-- Where to bind the RMIAdaptor proxy --> <attribute name="JndiName">jmx/invoker/RMIAdaptor</attribute> <!-- The RMI compatible MBeanServer interface --> <attribute name="ExportedInterface">org.jboss.jmx.adaptor.rmi.RMIAdaptor</attribute> <attribute name="ClientInterceptors"> <interceptors> <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor> <interceptor> org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor </interceptor> <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor> </interceptors> </attribute> <depends>jboss:service=invoker,type=jrmp</depends> </mbean> <!-- This is the service that handles the RMIAdaptor invocations by routing them to the MBeanServer the service is deployed under. --> <mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=Invoker"> <attribute name="ExportedInterface">org.jboss.jmx.adaptor.rmi.RMIAdaptor</attribute> </mbean> </server>

The first MBean, org.jboss.invocation.jrmp.server.JRMPProxyFactory, is the proxy factory MBean service that creates proxies for the RMI/JRMP protocol. The configuration of this service, as shown in Example 2.17, states that JRMPInvoker will be used as the detached invoker, InvokerAdaptorService is the target MBean to which requests will be forwarded, the proxy will expose the RMIAdaptor interface, the proxy will be bound into JNDI under the name jmx/invoker/RMIAdaptor, and the proxy will contain three interceptors: ClientMethodInterceptor, InvokerAdaptorClientInterceptor, and InvokerInterceptor. The configuration of InvokerAdaptorService simply sets the RMIAdaptor interface that the service is exposing.

The last piece of the configuration for exposing the InvokerAdaptorService via RMI/JRMP is the detached invoker. The detached invoker you will use is the standard RMI/JRMP invoker used by the EJB containers for home and remote invocations, and this is the org.jboss.invocation.jrmp.server.JRMPInvoker MBean service configured in the conf/jboss-service.xml descriptor. That you can use the same service instance emphasizes the detached nature of the invokers. JRMPInvoker simply acts as the RMI/JRMP endpoint for all RMI/JRMP proxies, regardless of the interfaces the proxies expose or the service the proxies utilize.

JRMPInvoker: RMI/JRMP Transport

The org.jboss.invocation.jrmp.server.JRMPInvoker class is an MBean service that provides the RMI/JRMP implementation of the Invoker interface. JRMPInvoker exports itself as an RMI server so that when it is used as the invoker in a remote client, the JRMPInvoker stub is sent to the client instead, and invocations use the RMI/JRMP protocol.

The JRMPInvoker MBean supports a number of attributes to configure the RMI/JRMP transport layer. The following are its configurable attributes:

  • RMIObjectPort This attribute sets the RMI server socket listening port number. This is the port RMI that clients will connect to when communicating through the proxy interface. The default setting in the jboss-service.xml descriptor is 4444, and if it is not specified, the attribute defaults to 0 to indicate that an anonymous port should be used.

  • RMIClientSocketFactory This attribute specifies a fully qualified classname for the j ava.rmi.server.RMIClientSocketFactory interface to use during export of the proxy interface.

  • RMIServerSocketFactory This attribute specifies a fully qualified classname for the java.rmi.server.RMIServerSocketFactory interface to use during export of the proxy interface.

  • ServerAddress This attribute specifies the interface address that will be used for the RMI server socket listening port. This can be either a DNS hostname or a dotted-decimal Internet address. Because RMIServerSocketFactory does not support a method that accepts an InetAddress object, this value is passed to the RMIServerSocketFactory implementation class, using reflection. A check for the existence of a public void setBindAddress(java.net.InetAddress addr) method is made, and if one exists, the RMIServerSocketAddr value is passed to the RMIServerSocketFactory implementation. If the RMIServerSocketFactory implementation does not support such a method, the ServerAddress value will be ignored.

  • SecurityDomain This attribute specifies the JNDI name of an org.jboss.security.SecurityDomain interface implementation to associate with the RMIServerSocketFactory implementation. The value will be passed to the RMIServerSocketFactory, using reflection, to locate a method with the signature public void setSecurity-Domain (org.jboss.security.SecurityDomain d). If no such method exists, the SecurityDomain value will be ignored.

PooledInvoker: RMI/Socket Transport

The org.jboss.invocation.pooled.server.PooledInvoker class is an MBean service that provides RMI over a custom socket transport implementation of the Invoker interface. PooledInvoker exports itself as an RMI server so that when it is used as the Invoker in a remote client, the PooledInvoker stub is sent to the client instead, and invocations use a custom socket protocol.

The PooledInvoker MBean supports a number of attributes to configure the socket transport layer. These are its configurable attributes:

  • NumAcceptThreads The number of threads that exist for accepting client connections. The default is 1.

  • MaxPoolSize The number of server threads for processing a client. The default is 300.

  • SocketTimeout The socket timeout value passed to the Socket.setSoTimeout() method. The default is 60000.

  • ServerBindPort The port used for the server socket. A value of 0 indicates that an anonymous port should be chosen.

  • ClientConnectAddress The address that the client passes to the Socket(addr,port) constructor. This defaults to the server InetAddress.getLocalHost() value.

  • ClientConnectPort The port that the client passes to the Socket(addr,port) constructor. The default is the port of the server listening socket.

  • ClientMaxPoolSize The client-side maximum number of threads. The default is 300.

  • Backlog The backlog associated with the server accept socket. The default is 200.

  • EnableTcpNoDelay A Boolean flag that indicates whether client sockets will enable the TcpNoDelay flag on the socket. The default is false.

  • ServerBindAddress The address on which the server binds its listening socket. The default is an empty value which indicates that the server should be bound on all interfaces.

  • transactionManagerService The JMX ObjectName of the JTA transaction manager service.

IIOPInvoker: RMI/IIOP Transport

The org.jboss.invocation.iiop.IIOPInvoker class is an MBean service that provides the RMI/IIOP implementation of the Invoker interface. The IIOPInvoker IIOP invoker that routes IIOP requests to CORBA servants is used by the org.jboss.proxy.ejb.IORFactory proxy factory to create RMI/IIOP proxies. However, rather than create Java proxies (as the JRMP proxy factory does), this factory creates CORBA IORs. An IORFactory is associated to a given Enterprise Bean. It registers with the IIOP invoker two CORBA servants: anEjbHomeCorbaServant for the bean's EJBHome and EjbObjectCorbaServant for the bean's EJBObjects.

The IIOPInvoker MBean has no configurable properties because all properties are configured from the conf/jacorb.properties property file used by the JacORB CORBA service.

JRMPProxyFactory: Building Dynamic JRMP Proxies

The org.jboss.invocation.jrmp.server.JRMPProxyFactory MBean service is a proxy factory that can expose any interface with RMI-compatible semantics for access to remote clients, using JRMP as the transport. JRMPProxyFactory supports the following attributes:

  • InvokerName The server-side JRMPInvoker MBean service JMX ObjectName string that will handle the RMI/JRMP transport.

  • TargetName The server-side MBean that exposes the invoke(Invocation) JMX operation for the exported interface. This is used as the destination service for any invocations done through the proxy.

  • JndiName The JNDI name under which the proxy will be bound.

  • ExportedInterface The fully qualified classname of the interface that the proxy implements. This is the typed view of the proxy that the client uses for invocations.

  • ClientInterceptors An XML fragment of interceptors/interceptor elements, with each interceptor element body specifying the fully qualified classname of an org.jboss.proxy.Interceptor implementation to include in the proxy interceptor stack. The ordering of the interceptors/interceptor elements defines the order of the interceptors.

HttpInvoker: RMI/HTTP Transport

The org.jboss.invocation.http.server.HttpInvoker MBean service provides support for making invocations into the JMX bus over HTTP. Unlike JRMPInvoker, HttpInvoker is not an implementation of Invoker, but it does implement the Invoker.invoke method. The HttpInvoker is accessed indirectly by issuing an HTTP POST against the org.jboss. invocation.http.servlet.InvokerServlet. The HttpInvoker exports a client-side proxy in the form of the org.jboss.invocation.http.interfaces.HttpInvokerProxy class, which is an implementation of Invoker and is serializable. HttpInvoker is a drop-in replacement for the JRMPInvoker as the target of the bean-invoker and home-invoker EJB configuration elements. The HttpInvoker and InvokerServlet are deployed in the http-invoker.sar discussed in Chapter 3, "Naming on JBoss," in the section "Accessing JNDI over HTTP."

The HttpInvoker supports the following attributes:

  • InvokerURL This is either the HTTP URL to the InvokerServlet mapping or the name of a system property that will be resolved inside the client VM to obtain the HTTP URL to the InvokerServlet.

  • InvokerURLPrefix If there is no invokerURL set, one will be constructed via the concatenation of invokerURLPrefix and the local host and invokerURLSuffix. The default prefix is http://.

  • InvokerURLSuffix If there is no invokerURL set, one will be constructed via the concatenation of invokerURLPrefix and the local host and invokerURLSuffix. The default suffix is :8080/invoker/JMXInvokerServlet.

  • UseHostName This is a Boolean flag if the InetAddress.getHostName() or getHostAddress() method should be used as the host component of the concatenation of invokerURLPrefix and host and invokerURLSuffix. If true, getHostName() is used; otherwise, getHostAddress() is used.

JRMPInvoker: Clustered RMI/JRMP Transport

The org.jboss.proxy.generic.ProxyFactoryHA service is an extension of ProxyFactoryHA, which is a cluster-aware factory. ProxyFactoryHA fully supports all the attributes of JRMPProxyFactory. This means that customized bindings of the port, interface, and socket transport are available to clustered RMI/JRMP as well. In addition, the following cluster-specific attributes are supported:

  • PartitionObjectName The JMX ObjectName of the cluster service to which the proxy is to be associated.

  • LoadBalancePolicy The classname of the org.jboss.ha.framework.interfaces.LoadBalancePolicy interface implementation to associate with the proxy.

HttpInvoker: Clustered RMI/HTTP Transport

The RMI/HTTP layer allows for software load balancing of the invocations in a clustered environment. The HA-capable extension of the HTTP invoker borrows much of its functionality from the HA-RMI/JRMP clustering. To enable HA-RMI/HTTP, you need to configure the invokers for the EJB container. This is done through either a jboss.xml descriptor or the standardjboss.xml descriptor.

HttpProxyFactory: Building Dynamic HTTP Proxies

The org.jboss.invocation.http.server.HttpProxyFactory MBean service is a proxy factory that can expose any interface with RMI-compatible semantics for access to remote clients, using HTTP as the transport. HttpProxyFactory supports the following attributes:

  • InvokerName The server-side MBean that exposes the invoke operation for the exported interface. The name is embedded into the HttpInvokerProxy context as the target to which the invocation should be forwarded by the HttpInvoker.

  • JndiName The JNDI name under which the HttpInvokerProxy will be bound. This is the name clients look up to obtain the dynamic proxy that exposes the service interfaces and marshals invocations over HTTP. This may be specified as an empty value to indicate that the proxy should not be bound into JNDI.

  • InvokerURL This is either the HTTP URL to the InvokerServlet mapping or the name of a system property that will be resolved inside the client VM to obtain the HTTP URL to the InvokerServlet.

  • InvokerURLPrefix If there is no invokerURL set, one will be constructed via the concatenation of invokerURLPrefix and the local host and invokerURLSuffix. The default prefix is http: //.

  • InvokerURLSuffix If there is no invokerURL set, one will be constructed via the concatenation of invokerURLPrefix and the local host and invokerURLSuffix. The default suffix is :8080/invoker/JMXInvokerServlet.

  • UseHostName This Boolean flag indicates whether the InetAddress.getHostName() or getHostAddress() method should be used as the host component of the concatenation of invokerURLPrefix and host and invokerURLSuffix. If TRue, getHostName() is used; otherwise, getHostAddress() is used.

  • ExportedInterface The name of the RMI-compatible interface that HttpInvokerProxy implements.

Steps to Expose Any RMI Interface via HTTP

By using the HttpProxyFactory MBean and JMX, you can expose any interface for access, using HTTP as the transport. The interface to expose does not have to be an RMI interface, but it does have to be compatible with RMI in that all method parameters and return values need to be serializable. There is also no support for converting RMI interfaces used as method parameters or return values into their stubs.

There are three steps to making an object invocable via HTTP:

1.

Create a mapping of longs to the RMI interface methods, using the MarshalledInvocation.calculateHash method. Here, for example, is the procedure for an RMI SRPRemoteServerInterface interface:

 import java.lang.reflect.Method; import java.util.HashMap; import org.jboss.invocation.MarshalledInvocation; HashMap marshalledInvocationMapping = new HashMap(); // Build the Naming interface method map Method[] methods = SRPRemoteServerInterface.class.getMethods(); for(int m = 0; m < methods.length; m ++) {     Method method = methods[m];     Long hash = new Long(MarshalledInvocation.calculateHash(method));     marshalledInvocationMapping.put(hash, method); } 

2.

Either create or extend an existing MBean to support an invoke operation. Its signature is Object invoke (Invocation invocation) throws Exception, and the steps it performs are as shown here for the SRPRemoteServerInterface interface:

 import org.jboss.invocation.Invocation; import org.jboss.invocation.MarshalledInvocation; public Object invoke(Invocation invocation)     throws Exception {     SRPRemoteServerInterface theServer = <the_actual_rmi_server_object>;     // Set the method hash to Method mapping     if (invocation instanceof MarshalledInvocation) {         MarshalledInvocation mi = (MarshalledInvocation) invocation;         mi.setMethodMap(marshalledInvocationMapping);     }     // Invoke the Naming method via reflection     Method method = invocation.getMethod();     Object[] args = invocation.getArguments();     Object value = null;     try {         value = method.invoke(theServer, args);     } catch(InvocationTargetException e) {         Throwable t = e.getTargetException();         if (t instanceof Exception) {             throw (Exception) e;         } else {             throw new UndeclaredThrowableException(t, method.toString());         }     }     return value; } return value; } 

Note that this uses the marshalledInvocationMapping from step 1 to map from the Long method hashes in the MarshalledInvocation to the Method for the interface.

3.

Create a configuration of the HttpProxyFactory MBean to make the RMI/HTTP proxy available through JNDI. Here's an example:

 <!-- Expose the SRP service interface via HTTP --> <mbean code="org.jboss.invocation.http.server.HttpProxyFactory"        name="jboss.security.tests:service=SRP/HTTP">     <attribute name="InvokerURL">http://localhost:8080/invoker/JMXInvokerServlet</attribute>     <attribute name="InvokerName">jboss.security.tests:service=SRPService</attribute>     <attribute name="ExportedInterface">org.jboss.security.srp.SRPRemoteServerInterface     </attribute><attribute name="JndiName">srp-test-http/SRPServerInterface</attribute> </mbean> 

Any client can now look up the RMI interface from JNDI, using the name specified in the HttpProxyFactory (for example, srp-test-http/SRPServerInterface) and use the obtained proxy in exactly the same manner as the RMI/JRMP version.



JBoss 4. 0(c) The Official Guide
JBoss 4.0 - The Official Guide
ISBN: B003D7JU58
EAN: N/A
Year: 2006
Pages: 137

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net