JBoss Remoting Guide

JBoss Remoting Guide

JBoss Remoting version 2.5.0.SP2

November 20, 2008


Table of Contents

1. Overview
1.1. What is JBoss Remoting?
1.2. Features
1.3. How to get JBoss Remoting
1.4. What's new in version 2.5?
1.4.1. Release 2.5.0.SP2
1.4.2. Release 2.5.0.SP1
1.5. What's new in version 2.4?
1.5.1. Release 2.4.0.SP2
1.5.2. Release 2.4.0.SP1
1.5.3. Release 2.4.0.GA
2. Architecture
3. JBoss Remoting Components
3.1. Discovery
3.2. Transports
4. Remoting libraries and thirdparty dependancies
4.1. Thirdparty libraries
5. Configuration
5.1. General transport configuration
5.1.1. Server side configuration
5.1.1.1. Programmatic configuration.
5.1.1.2. Declarative configuration: MBeans
5.1.1.3. Declarative configuration: POJOs
5.1.1.4. Callback client configuration
5.1.2. Client side configuration
5.2. Handlers
5.3. Discovery (Detectors)
5.4. Transports (Invokers)
5.4.1. Features introduced in Remoting version 2.4
5.4.1.1. Binding to 0.0.0.0
5.4.1.2. Multihome servers
5.4.1.3. Socket creation listeners
5.4.1.4. Making client IP address available to application
5.4.1.5. Support for IPv6 addresses
5.4.1.6. Delayed destruction of client invokers
5.4.2. Server Invokers
5.4.3. Configurations affecting the invoker client
5.4.4. How the server bind address and port is determined
5.4.5. Socket transport
5.4.5.1. How the Socket transport works
5.4.5.2. Configuration
5.4.6. SSL Socket transport
5.4.7. RMI transport
5.4.8. SSL RMI Invoker
5.4.9. HTTP transport
5.4.10. HTTPS transport
5.4.11. HTTP(S) Client Invoker - proxy and basic authentication
5.4.12. Servlet transport
5.4.13. SSL Servlet transport
5.4.14. Exception handling for web based clients
5.4.15. Multiplex transport
5.4.16. SSL Multiplex transport
5.4.17. Bisocket transport
5.4.17.1. Overview
5.4.17.2. Details
5.4.18. SSL Bisocket transport
5.5. Marshalling
5.6. Callbacks
5.6.1. Callback overview
5.6.1.1. Callback connections
5.6.1.2. Transmitting callbacks
5.6.1.3. Callback stores.
5.6.1.4. Callback acknowledgements
5.6.2. Registering callback handlers.
5.6.2.1. Pull callbacks.
5.6.2.2. Push callbacks.
5.6.3. Unregistering callback handlers
5.6.4. Callback store configuration.
5.6.5. Callback Exception Handling
5.7. Socket factories and server socket factories
5.7.1. Server side programmatic configuration
5.7.1.1. Server socket factories.
5.7.1.2. Socket factories
5.7.2. Client side programmatic configuration
5.7.2.1. Server socket factories.
5.7.2.2. Socket factories.
5.7.3. Server side configuration in the JBoss Application Server
5.7.4. Socket creation listeners
5.7.5. SSL transports
5.7.6. SSLSocketBuilder
5.7.7. SSLServerSocketFactoryService
5.7.8. General Security How To
5.7.9. Troubleshooting Tips
5.8. Timeouts
5.8.1. General timeout configuration
5.8.2. Per invocation timeouts
5.8.3. Transport specific timeout handling
5.8.3.1. Socket and bisocket transports
5.8.3.2. HTTP and HTTPS transports
5.8.3.3. RMI and SSLRMI transports
5.8.3.4. Quick client disconnect
5.9. Running with a security manager
5.10. Wire version
5.11. Configuration by properties
5.11.1. org.jboss.remoting.InvokerLocator
5.11.2. org.jboss.remoting.Client
5.11.3. org.jboss.remoting.Remoting
5.11.4. org.jboss.remoting.ServerInvoker
5.11.5. org.jboss.remoting.callback.CallbackPoller
5.11.6. org.jboss.remoting.callback.CallbackStore
5.11.7. org.jboss.remoting.callback.DefaultCallbackErrorHandler
5.11.8. org.jboss.remoting.callback.ServerInvokerCallbackHandler
5.11.9. org.jboss.remoting.detection.jndi.JNDIDetector
5.11.10. org.jboss.remoting.marshal.http.HTTPUnMarshaller
5.11.11. org.jboss.remoting.transport.bisocket.Bisocket
5.11.12. org.jboss.remoting.transport.http.HTTPClientInvoker
5.11.13. org.jboss.remoting.transport.http.HTTPMetadataConstants
5.11.14. org.jboss.remoting.transport.http.ssl.HTTPSClientInvoker
5.11.15. org.jboss.remoting.transport.rmi.RMIServerInvoker
5.11.16. org.jboss.remoting.transport.socket.MicroSocketClientInvoker
5.11.17. org.jboss.remoting.transport.socket.ServerThread
5.11.18. org.jboss.remoting.transport.socket.SocketServerInvoker
6. Adding a New Transport
7. Sending streams
7.1. Configuration
7.2. Issues
8. Serialization
9. Remote classloading facility
9.1. Classloading in client invokers
9.2. Server side support for remote classloading
10. Network Connection Monitoring
10.1. Client side monitoring
10.2. Server side monitoring
10.3. Interactions between client side and server side connection monitoring
11. Transporters - beaming POJOs
12. How to use it - sample code
12.1. Simple invocation
12.2. HTTP invocation
12.3. Oneway invocation
12.4. Discovery and invocation
12.5. Callbacks
12.6. Bisocket transport
12.7. Streaming
12.8. JBoss Serialization
12.9. Transporters
12.9.1. Transporters - beaming POJOs
12.9.2. Transporters sample - simple
12.9.3. Transporter sample - basic
12.9.4. Transporter sample - JBoss serialization
12.9.5. Transporter sample - clustered
12.9.6. Transporters sample - multiple
12.9.7. Transporters sample - proxy
12.9.8. Transporter sample -complex
13. Client programming model
14. Compatibility and versioning
15. Getting the JBossRemoting source and building
16. Known issues
17. Future plans
18. Release Notes
18.1. Important changes and differences in 2.5.0 release (from 2.4.0 release)
18.2. Important changes and differences in 2.4.0 release (from 2.2.0 release)
18.3. Important changes and differences in 2.2.0 release (from 2.0.0 release)
18.4. Release history
18.4.1. Version 2.5
18.4.2. Version 2.4
18.4.3. Version 2.2
18.4.4. Version 2.0
18.4.5. Version 1.4
18.4.6. Version 1.2
18.4.7. Version 1.0

Chapter 1. Overview

1.1. What is JBoss Remoting?

The purpose of JBoss Remoting is to provide a single API for most network based invocations and related service that uses pluggable transports and data marshallers. The JBossRemoting API provides the ability for making synchronous and asynchronous remote calls, push and pull callbacks, and automatic discovery of remoting servers. The intention is to allow for the use of different transports to fit different needs, yet still maintain the same API for making the remote invocations and only requiring configuration changes, not code changes.

JBossRemoting is a standalone project, separate from the JBoss Application Server project, but will be the framework used for many of the JBoss projects and components when making remote calls. JBossRemoting is included in the recent releases of the JBoss Application Server and can be run as a service within the container as well. Service configurations are included in the configuration section below.

1.2. Features

The features available with JBoss Remoting are:

  • Server identification – a simple url based identifier which allows for remoting servers to be identified and called upon.

  • Pluggable transports – can use different protocol transports the same remoting API.

    Provided transports:

    • Socket (SSL Socket)

    • RMI (SSL RMI)

    • HTTP(S)

    • Servlet (SSL Servlet)

    • Bisocket (SSL Bisocket)

  • Pluggable data marshallers – can use different data marshallers and unmarshallers to convert the invocation payloads into desired data format for wire transfer.

  • Pluggable serialization - can use different serialization implementations for data streams.

    Provided serialization implementations:

    • Java serialization

    • JBoss serialization

  • Automatic discovery – can detect remoting servers as they come on and off line.

    Provided detection implementations:

    • Multicast

    • JNDI

  • Server grouping – ability to group servers by logical domains, so only communicate with servers within specified domains.

  • Callbacks – can receive server callbacks via push and pull models. Pull model allows for persistent stores and memory management.

  • Asynchronous calls – can make asynchronous, or one way, calls to server.

  • Local invocation – if making an invocation on a remoting server that is within the same process space, remoting will automatically make this call by reference, to improve performance.

  • Remote classloading – allows for classes, such as custom marshallers, that do not exist within client to be loaded from server.

  • Sending of streams – allows for clients to send input streams to server, which can be read on demand on the server.

  • Clustering - seamless client failover for remote invocations.

  • Connection failure notification - notification if client or server has failed

  • Data Compression - can use compression marshaller and unmarshaller for compresssion of large payloads.

All the features within JBoss Remoting were created with ease of use and extensibility in mind. If you have a suggestion for a new feature or an improvement to a current feature, please log in our issue tracking system at http://jira.jboss.com

1.3. How to get JBoss Remoting

The JBossRemoting distribution can be downloaded from http://www.jboss.org/jbossremoting/ . This distribution contains everything needed to run JBossRemoting stand alone. The distribution includes binaries, source, documentation, javadoc, and sample code.

1.4. What's new in version 2.5?

Version 2.5.0 represents the process of upgrading the jars with which Remoting is tested and shipped. In particular, the jars are now equivalent to the jars found in the JBoss Application Server version 5.0.0.CR2 (as of 9/6/08, before its release). Changes to jbossweb (the JBoss version of Tomcat) have necessitated dropping the use of Apache Tomcat, which means that the "http" transport will no longer function with jdk 1.4.

Other features of Remoting 2.5.0.GA should function with jdk 1.4. However, it is the policy of JBoss, a division of Red Hat, no longer to support jdk 1.4.

1.4.1. Release 2.5.0.SP2

  • A few bug fixes.

1.4.2. Release 2.5.0.SP1

  • The distribution zip file no longer contains previous versions of jboss-remoting.jar.

  • A few bug fixes.

1.5. What's new in version 2.4?

1.5.1. Release 2.4.0.SP2

  • CoyoteInvoker adds the URL query to the InvocationRequest request map.

  • A leak in Java serialization output marshalling has been fixed.

1.5.2. Release 2.4.0.SP1

  • The remote classloading facility can be configured with lists of classloaders.

  • Classloading in the client can optionally start with the thread context classloader.

  • Leasing can be enabled declaratively.

1.5.3. Release 2.4.0.GA

JBossRemoting 2.4.0.GA is an incremental release, with dozens of bug fixes and several new features:

  • servers can be bound to multiple IP addresses

  • can run in the presence of a security manager

  • greater configurability

  • supports IPv6 addresses

  • improved connection monitoring

  • server gets client address in invocations

Chapter 2. Architecture

The most critical component of the JBoss Remoting architecture is how servers are identified. This is done via an InvokerLocator, which can be represented by a simple String with a URL based format (e.g., socket://myhost:5400). This is all that is required to either create a remoting server or to make a call on a remoting server. The remoting framework will then take the information embedded within the InvokerLocator and construct the underlying remoting components needed and build the full stack required for either making or receiving remote invocations.

There are several layers to this framework that mirror each other on the client and server side. The outermost layer is the one which the user interacts with. On the client side, this is the Client class upon which the user will make its calls. On the server side, this is the InvocationHandler, which is implemented by the user and is the ultimate receiver of invocation requests. Next is the transport, which is controlled by the invoker layer. Finally, at the lowest layer is the marshalling, which converts data type to wire format.

When a user calls on the Client to make an invocation, it will pass this invocation request to the appropriate client invoker, based on the transport specified by the locator url. The client invoker will then use the marshaller to convert the invocation request object to the proper data format to send over the network. On the server side, an unmarshaller will receive this data from the network and convert it back into a standard invocation request object and send it on to the server invoker. The server invoker will then pass this invocation request on to the user’s implementation of the invocation handler. The response from the invocation handler will pass back through the server invoker and on to the marshaller, which will then convert the invocation response object to the proper data format and send back to the client. The unmarshaller on the client will convert the invocation response from wire data format into standard invocation response object, which will be passed back up through the client invoker and Client to the original caller.

Client

On the client side, there are a few utility class that help in figuring out which client invoker and marshal instances should be used.

For determining which client invoker to use, the Client will pass the InvokerRegistry the locator for the target server it wishes to make invocations on. The InvokerRegistry will return the appropriate client invoker instance based on information contained within the locator, such as transport type. The client invoker will then call upon the MarshalFactory to get the appropriate Marshaller and UnMarshaller for converting the invocation objects to the proper data format for wire transfer. All invokers have a default data type that can be used to get the proper marshal instances, but can be overridden within the locator specified.

Server

On the server side, there are also a few utility classes for determining the appropriate server invoker and marshal instances that should be used. There is also a server specific class for tying the invocation handler to the server invoker.

On the server side, it is the Connector class that is used as the external point for configuration and control of the remoting server. The Connector class will call on the InvokerRegistry with its locator to create a server invoker. Once the server invoker is returned, the Connector will then register the invocation handlers on it. The server invoker will use the MarshalFactory to obtain the proper marshal instances as is done on the client side.

Detection

To add automatic detection, a remoting Detector will need to be added on both the client and the server side as well as a NetworkRegistry to the client side.

When a Detector on the server side is created and started, it will periodically pull from the InvokerRegistry all the server invokers that it has created. The detector will then use the information to publish a detection message containing the locator and subsystems supported by each server invoker. The publishing of this detection message will be either via a multicast broadcast or a binding into a JNDI server. On the client side, the Detector will either receive the multicast broadcast message or poll the JNDI server for detection messages. If the Detector determines a detection message is for a remoting server that just came online it will register it in the NetworkRegistry. The NetworkRegistry houses the detection information for all the discovered remoting servers. The NetworkRegistry will also emit a JMX notification upon any change to this registry of remoting servers. The change to the NetworkRegistry can also be for when a Detector has discovered that a remoting server is no longer available and removes it from the registry.

Chapter 3. JBoss Remoting Components

This section covers a few of the main components exposed within the Remoting API with a brief overview.

org.jboss.remoting.Client – is the class the user will create and call on from the client side. This is the main entry point for making all invocations and adding a callback listener. The Client class requires only the InvokerLocator for the server you wish to call upon and that you call connect before use and disconnect after use (which is technically only required for stateful transports and when client leasing is turned on, but good to call in either case).

org.jboss.remoting.InvokerLocator – is a class, which can be described as a string URI, for identifying a particular JBossRemoting server JVM and transport protocol. For example, the InvokerLocator string socket://192.168.10.1:8080 describes a TCP/IP Socket-based transport, which is listening on port 8080 of the IP address, 192.168.10.1. Using the string URI, or the InvokerLocator object, JBossRemoting can make a client connection to the remote server. The format of the locator string is the same as the URI type: [transport]://[host]:<port>/path/?<parameter=value>&<parameter=value>

A few important points to note about the InvokerLocator. The string representation used to construct the InvokerLocator may be modified after creation. This can occur if the host supplied is 0.0.0.0, in which case the InvokerLocator will attempt to replace it with the value of the local host name. This can also occur if the port specified is less than zero or not specified at all (in which case remoting will select a random port to use).

The InvokerLocator will accept host name as is and will not automatically convert to IP address (since 2.0.0 release). There are two comparison operators for InvocatorLocators, equals() and isSameEndpoint(), and neither resolve a hostname to IP address or vice versa. equals() compares all components of the InvokerLocator, character by character, while isSameEndpoint() uses only protocol, host, and port. The following examples are just some of the comparisons that can be seen in org.jboss.test.remoting.locator.InvokerLocatorTestCase:

new InvokerLocator("http://localhost:1234/services/uri:Test").equals(
        new InvokerLocator("http://localhost:1234"))
 returns false

new InvokerLocator("http://localhost:1234/services/uri:Test").equals(
        new InvokerLocator("http://127.0.0.1:1234"))
 returns false

new InvokerLocator("http://localhost:1234/services/uri:Test").isSameEndpoint(
        new InvokerLocator("http://localhost:1234"))
 returns true

new InvokerLocator("http://localhost:1234/services/uri:Test").isSameEndpoint(
        new InvokerLocator("http://127.0.0.1:1234"))
 returns false

N.B. As of version 2.4, InvokerLocator uses the class java.net.URI, rather than its original ad hoc parsing code, to parse the String passed to its constructor. If, for some reason, the new algorithm causes problems for legacy code, it is possible to configure InvokerLocator to use the original parsing code by calling the static method org.jboss.remoting.InvokerLocator.setUseLegacyParsing().

org.jboss.remoting.transport.Connector - is an MBean that loads a particular ServerInvoker implementation for a given transport subsystem and one or more ServerInvocationHandler implementations that handle Subsystem invocations on the remote server JVM. The Connector is the main user touch point for configuring and managing a remoting server.

org.jboss.remoting.ServerInvocationHandler – is the interface that the remote server will call on with an invocation received from the client. This interface must be implemented by the user. This implementation will also be required to keep track of callback listeners that have been registered by the client as well.

org.jboss.remoting.InvocationRequest – is the actual remoting payload of an invocation. This class wraps the caller’s request and provides extra information about the invocation, such as the caller’s session id and its callback locator (if one exists). This will be object passed to the ServerInvocationHandler.

org.jboss.remoting.stream.StreamInvocationHandler – extends the ServerInvocationHandler interface and should be implemented if expecting to receive invocations containing an input stream.

org.jboss.remoting.callback.InvokerCallbackHandler – the interface for any callback listener to implement. Upon receiving callbacks, the remoting client will call on this interface if registered as a listener.

org.jboss.remoting.callback.Callback – the callback object passed to the InvokerCallbackHandler. It contains the callback payload supplied by the invocation handler, any handle object specified when callback listener was registered, and the locator from which the callback came.

org.jboss.remoting.network.NetworkRegistry – this is a singleton class that will keep track of remoting servers as new ones are detected and dead ones are detected. Upon a change in the registry, the NetworkRegistry fires a NetworkNotification.

org.jboss.remoting.network.NetworkNotification – a JMX Notification containing information about a remoting server change on the network. The notification contains information in regards to the server’s identity and all its locators.

org.jboss.remoting.detection.Detection – is the detection message fired by the Detectors. Contains the locator and subsystems for the server invokers of a remoting server as well as the remoting server’s identity.

org.jboss.remoting.ident.Identity – is one of the main components remoting uses during discovery to identify remoting server instances (is actually the way it guarantees uniqueness). If have two remoting servers running on the same server, they can be uniquely identified. The reason the identity is persisted (currently only able to do this to the file system) is so if a server crashes and then restarts, can identify it when it restarts as the one that crashed (instead of being a completely new instance that is being started). This may be important from a monitoring point as would want to know that the crashed server is back online.

When creating the identity to be presisted, remoting will first look to see if a system property for 'jboss.identity' has been set already. If it has, will use that one. If not, will get the value for the 'ServerDataDir' attribute of the 'jboss.system:type=ServerConfig' mbean. If can retrieve this value, will use this as the directory to write out the 'jboss.identity' file. If not, will look to see if a system property has been set for 'jboss.identity.dir'. If it has, will use this as the directory to write the 'jboss.identity' file to, otherwise, will default to '.'. If for some reason the file can not be written to, will throw a RuntimeException, which will cause the detector to error during startup. For more details on how and where the identity is persisted, can refer to org.jboss.remoting.ident.Identity.createId().

org.jboss.remoting.detection.multicast.MulticastDetector – is the detector implementation that broadcasts its Detection message to other detectors using multicast.

org.jboss.remoting.detection.jndi.JNDIDetector – is the detector implementation that registers its Detection message to other detectors in a specified JNDI server.

There are a few other components that are not represented as a class, but important to understand.

Subsystem – a sub-system is an identifier for what higher level system an invocation handler is associated with. The sub-system is declared as any String value. The reason for identifying sub-systems is that a remoting Connector’s server invoker may handle invocations for multiple invocation handlers, which need to be routed based on sub-system. For example, a particular socket based server invoker may handle invocations for both customer processing and order processing. The client making the invocation would then need to identify the intended sub-system to handle the invocation based on this identifier. If only one handler is added to a Connector, the client does not need to specify a sub-system when making an invocation.

Domain – a logical name for a group to which a remoting server can belong. The detectors can discriminate as to which detection messages they are interested based on their specified domain. The domain to which a remoting server belongs is stored within the Identity of that remoting server, which is included within the detection messages. Detectors can be configured to accept detection messages from one, many or all domains.

3.1. Discovery

One of the features of JBoss Remoting is to be able to dynamically discover remoting servers. This is done through the use of what remoting calls detectors. These detectors run in same instance as the servers and the clients. The detectors that run within the server instance automatically gets list of remoting servers running locally and emits a detection message contain information about those servers, such as their locator url and subsystems supported. The detector running within the client instance will receive these detection messages and update a local registry, called the network registry, with this information. The client detector will also monitor the remoting servers it has discovered in case one were to fail, in which case, will notify the network registry of the failure The network registry will then fire events to registered listeners (via JMX notifications), to include events such as new server added or server failure.

There are currently two types of detector implementations; multicast and JNDI. The multicast detectors use multicast channel to send and receive detection messages. The JNDI detectors use a well known JNDI server to bind and lookup detection messages.

The standard approach for detecting remoting servers happens in a passive manner, in that as detection messages are received by the client detector, they will cause an event to fire. In some cases, will need ability to synchronously discover the remoting servers that exist upon startup. This can be done by calling the forceDetection() method on the detector. This will return an array of NetworkInstances which contains the server information. Note, this method can take a few seconds to return (at least in multicast implementation).

3.2. Transports

Service provider interface

The transport implementations within remoting, called invokers, are responsible for handling the wire protocol to be used by remoting clients and servers. Remoting will load client and server invoker (transport) implementations (within the InvokerRegistry) using factories. The factory class to be loaded will always be either TransportClientFactory (for loading client invoker) or TransportServerFactory (for loading server invoker). These classes must implement org.jboss.remoting.transport.ClientFactory and org.jboss.remoting.transport.ServerFactory interfaces respectively. The package under which the TransportClientFactory and TransportServerFactory will always start with org.jboss.test.remoting.transport, then the transport protocol type. For example, the 'socket' transport factories are org.jboss.remoting.transport.socket.TransportClientFactory and org.jboss.remoting.transport.socket.TransportServerFactory. The API for org.jboss.remoting.transport.ClientFactory is:

public ClientInvoker createClientInvoker(InvokerLocator locator, Map config) throws IOException;
public boolean supportsSSL();

The API for org.jboss.remoting.transport.ServerFactory is:

public ServerInvoker createServerInvoker(InvokerLocator locator, Map config) throws IOException;
public boolean supportsSSL();

An example of a transport client factory for the socket transport (org.jboss.remoting.transport.socket.TransportClientFactory) is:

public class TransportClientFactory implements ClientFactory
{
   public ClientInvoker createClientInvoker(InvokerLocator locator, Map config)
         throws IOException
   {
      return new SocketClientInvoker(locator, config);
   }

   public boolean supportsSSL()
   {
      return false;
   }
}

The packages used within the factory does not matter as long as they are on the classpath. Note that the transport factories are only loaded upon request for that protocol. Also, the client and server factories have been separated so that only the one requested is loaded (and thus the corresponding classes needed for that invoker implementation). So if only ask for a particular client transport invoker, only those classes are loaded and the ones needed for the server are not required to be on the classpath.

The biggest reason for taking this approach is allows users ability to plugin custom transport implementation with zero config. Remoting comes with the following transports: socket, sslsocket, http, https, multiplex, sslmultiplex, servlet, sslservlet, rmi, sslrmi.

Chapter 4. Remoting libraries and thirdparty dependancies

Remoting partitions its functionality into several different libraries to allow the size of the footprint to be controlled according to the features that will be used. Remoting distribution will include the following remoting binaries (found in the lib directory of the distribution).

jboss-remoting.jar - this binary contains all the remoting classes. This is the only remoting jar that is needed to perform any remoting function within JBoss Remoting.

Since some may want to better control size of the binary footprint needed to use remoting, the remoting classes have been broken out into multiple remoting binaries based on their function. There are four categories of these binaries; core, detection, transport, and other.

core

jboss-remoting-core.jar - contains all the core remoting classes needed for remoting to function. If not using jboss-remoting.jar, then jboss-remoting.core.jar will be required.

detection

jboss-remoting-detection - contains all the remoting classes needed to perform automatic discovery of remoting servers. It includes both the jndi and multicast detector classes as well as the network registry classes.

transport

jboss-remoting-socket.jar - contains all the classes needed for the socket and sslsocket transports to function as both a client and a server.

jboss-remoting-socket-client.jar - contains all the classes needed for the socket and sslsocket transports to function as a client only. This means will not be able to perform any push callbacks or sending of streams using this jar.

jboss-remoting-http.jar - contains all the classes needed for the http and https transports to function as a client and a server.

jboss-remoting-http-client.jar - contains all the classes needed for the http, https, servlet, and sslservlet transports to function as a client only. This means will not be able to perform any push callbacks or sending of streams using this jar.

jboss-remoting-servlet.jar - contains all the classes needed for the servlet or sslservlet transports to function as a server only (also requires servlet-invoker.war be deployed within web container as well).

jboss-remoting-rmi.jar - contains all the classes needed for the rmi and sslrmi transports to function as a client and a server.

jboss-remoting-bisocket.jar - contains all the classes needed for the bisocket and sslbisocket transports to function as both a client and a server.

jboss-remoting-bisocket-client.jar - contains all the classes needed for the bisocket and sslbisocket transports to function as a client only. This means will not be able to perform any push callbacks or sending of streams using this jar.

other

jboss-remoting-serialization.jar - contains just the remoting serialization classes (and serialization manager implementations for java and jboss).

jboss-remoting-samples.jar - all the remoting samples showing example code for different remotng functions.

4.1. Thirdparty libraries

This section covers which thirdparty jars are required based on the feature or transport to be used. Remember, whenever see jboss-remoting-XXX.jar mentioned, they can all be replaced with just the jboss-remoting.jar.

All remoting servers: jboss-remoting-core.jar, jboss-common.jar, jboss-jmx.jar, log4j.jar

All remoting clients: jboss-remoting-core.jar, jboss-common.jar, jboss-jmx.jar, log4j.jar, concurrent.jar

Note: concurrent.jar needed because of org.jboss.util.id.GUID used to create session id within Client (http://jira.jboss.com/jira/browse/JBREM-549)

Remoting requires the use of JMX classes. It does not require the JBoss implementation (jboss-jmx.jar) of JMX in order to function correctly, so can replace jboss-jmx.jar with another JMX implementation library (or exclude it if using jdk 1.5 or higher, which has JMX implementation built in).

Multicast detection: jboss-remoting-detection.jar, concurrent.jar, dom4j.jar

JNDI detection: jboss-remoting-detection.jar, concurrent.jar, dom4j.jar, jnpserver.jar (for jndi api classes)

The dom4j.jar for use of detection is required because using jboss-jmx.jar.

Socket server: jboss-remoting-socket.jar

Socket client: jboss-remoting-socket-client.jar

HTTP server: jboss-remoting-http.jar, tomcat-coyote.jar, tomcat-util.jar, tomcat-http.jar, commons-logging-api.jar; alternatively, the tomcat jars can be replaced by jbossweb.jar

Note: need tomcat-apr.jar (if using tomcat jars) and tcnative-1.dll/tcnative-1.so on system path to use APR based tomcat connector

HTTP client: jboss-remoting-http-client.jar

Servlet server: servlet-invoker.war (deployed in web container), jboss-remoting-servlet.jar

Servlet client: jboss-remoting-http-client.jar

RMI server and client: jboss-remoting-rmi.jar

JBoss serialization: jboss-serialization.jar, trove.jar

Chapter 5. Configuration

This covers the configuration for JBoss Remoting discovery, connectors, marshallers, and transports. All the configuration properties specified can be set either via calls to the object itself, including via JMX (so can be done via the JMX or Web console), via a JBoss AS service xml file. Examples of service xml configurations can be seen with each of the sections below. There is also an example-service.xml file included in the remoting distribution that shows full examples of all the remoting configurations. In the presence of the JBoss Microcontainer, Remoting servers may be configured by the injection of an org.jboss.remoting.ServerConfiguration object specified in an *-beans.xml file.

5.1. General transport configuration

Remoting offers a variety of ways of configuring transports on the server side and client side. This section presents an overview, and the rest of the chapter elaborates the material presented here. For easy reference the configuration parameters discussed throughout the chapter are gathered together at the end of the chapter in section Configuration by properties

5.1.1. Server side configuration

The heart of the server side is the Connector, and it is through the Connector that the server side of a transport is configured. The central goals of configuration on the server side are to establish a server invoker and supply it with a set of invocation handlers. Only one invoker can be declared per Connector. Although declaring an invocation handler is not required, it should only be omitted in the case of declaring a callback server that will not receive direct invocations, but only callback messages. Otherwise client invocations can not be processed. The invocation handler is the only interface that is required by the remoting framework for a user to implement and will be what the remoting framework calls upon when receiving invocations.

There are two general approaches to server side configuration: programmatic and declarative. A variety of programmatic techniques work in any environment, including the JBoss Application Server (JBossAS). Moreover, JBossAS adds the option of declarative configuration. In particular, the SARDeployer (see The JBoss 4 Application Server Guide on the labs.jboss.org web site) can read information from a *-service.xml file and use it to configure MBeans such as Connectors.

5.1.1.1. Programmatic configuration.

The simplest way to configure a Connector is to pass an InvokerLocator to a Connector constructor. For example, the code fragment

String locatorURI = "socket://test.somedomain.com:8084";
String params = "/?clientLeasePeriod=10000&timeout=120000";
locatorURI += params;
InvokerLocator locator = new InvokerLocator(locatorURI);
Connector connector = new Connector(locator);
connector.create();
SampleInvocationHandler invocationHandler = new SampleInvocationHandler();
connector.addInvocationHandler("sample", invocationHandler);
connector.start();

creates a server invoker based on the socket transport, directs it to listen for invocations on port 8084 of host test.somedomain.com, and passes two configuration parameters, "clientLeasePeriod" and "timeout". It also supplies the server invoker with an invocation handler.

One limitation of the InvokerLocator is that it can only represent string values. An alternative that overcomes this limitation is to pass some or all of the parameters to the Connector by way of a configuration map. The following code fragment accomplishes all that the previous fragment does, but it passes one parameter by way of the InvokerLocator and passes the other by way of a configuration map. It also passes in a non-string object, a ServerSocketFactory:

String locatorURI = "socket://test.somedomain.com:8084";
String params = "/?clientLeasePeriod=10000";
locatorURI += params;
InvokerLocator locator = new InvokerLocator(locatorURI);
HashMap config = new HashMap();
config.put(ServerInvoker.TIMEOUT, 120000);
config.put(ServerInvoker.SERVER_SOCKET_FACTORY, new MyServerSocketFactory());
Connector connector = new Connector(locator, config);
connector.create();
SampleInvocationHandler invocationHandler = new SampleInvocationHandler();
connector.addInvocationHandler("sample", invocationHandler);
connector.start();

Note that the value of ServerInvoker.TIMEOUT is "timeout", and the value of ServerInvoker.SERVER_SOCKET_FACTORY is "serverSocketFactory". These configuration map keys are discussed throughout the chapter and accumulated in section Configuration by properties. Also, server socket factory configuration is covered in Socket factories and server socket factories.

A third programmatic option is available for those configuration properties which happen to be server invoker MBean properties. In the following fragment, the server invoker is obtained from the Connector and a ServerSocketFactory is passed to it by way of a setter method:

String locatorURI = "socket://test.somedomain.com:8084";
String params = "/?clientLeasePeriod=10000";
locatorURI += params;
InvokerLocator locator = new InvokerLocator(locatorURI);
HashMap config = new HashMap();
config.put(ServerInvoker.TIMEOUT, 120000);
Connector connector = new Connector(locator, config);
connector.create();
ServerInvoker serverInvoker = connector.getServerInvoker();
ServerSocketFactory ssf = new MyServerSocketFactory();
serverInvoker.setServerSocketFactory(ssf);
SampleInvocationHandler invocationHandler = new SampleInvocationHandler();
connector.addInvocationHandler("sample", invocationHandler);
connector.start();

Note. The Connector creates the server invoker during the call to Connector.create(), so this option only works after that method has been called. Also, depending on the parameter and the transport, this option may or may not be effective after the call to Connector.start(), which calls start() on the server invoker.

A fourth option, which exists primarily to support the declarative mode of configuration presented below, is to pass an XML document to the Connector. The following fragment duplicates the behavior of the first and second examples above.

HashMap config = new HashMap();
config.put(ServerInvoker.TIMEOUT, 120000);
Connector connector = new Connector(config);

// Set xml configuration element.
StringBuffer buf = new StringBuffer();
buf.append("<?xml version=\"1.0\"?>\n");
buf.append("<config>");
buf.append("   <invoker transport=\"socket\">");
buf.append("      <attribute name=\"serverBindAddress\">test.somedomain.com</attribute>");
buf.append("      <attribute name=\"serverBindPort\">8084</attribute>");
buf.append("      <attribute name=\"clientLeasePeriod\">10000</attribute>");
buf.append("   </invoker>");
buf.append("   <handlers>");
buf.append("      <handler subsystem=\"mock\">");
buf.append("         org.jboss.remoting.transport.mock.SampleInvocationHandler");
buf.append("      </handler>");
buf.append("   </handlers>");
buf.append("</config>");

ByteArrayInputStream bais = new ByteArrayInputStream(buf.toString().getBytes());
Document xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(bais);
connector.setConfiguration(xml.getDocumentElement());

connector.create();
connector.start();

Note that there is no InvokerLocator in this example. If the Connector gets an InvokerLocator, it ignores the presence of the xml document. Note also that this method only supports the use of string values, so it is necessary to include the fully qualified name of the invocation handler, from which the handler is created by calling the default constructor.

An example of this option in use can be found in org.jboss.test.remoting.configuration.SocketClientConfigurationTestCase.

A fifth option, which exists primarily to support the injection of POJOs in the presence of the JBoss Microcontainer, is to pass an org.jboss.remoting.ServerConfiguration object to the Connector.setServerConfiguration() method. The following fragment duplicates the behavior of the first and second examples above.

HashMap config = new HashMap();
config.put(ServerInvoker.TIMEOUT, 120000);
Connector connector = new Connector(config);

// Create ServerConfiguration object for socket transport
ServerConfiguration serverConfig = new ServerConfiguration("socket");

// Add invokerLocatorParameters (applicable to client and server)
Map locatorConfig = new HashMap();
locatorConfig.put("serverBindAddress", "test.somedomain.com");
locatorConfig.put("serverBindPort", "8084");
serverConfig.setInvokerLocatorParameters(locatorConfig);

// Add serverParameters (applicable to server)
Map serverParameters = new HashMap();
locatorConfig.put("clientLeasePeriod", "10000");
serverConfig.setServerParameters(serverParameters);

// Add invocation handlers
Map handlers = new HashMap();
handlers.put("mock", "org.jboss.remoting.transport.mock.SampleInvocationHandler");
serverConfig.setInvocationHandlers(handlers);

connector.setServerConfiguration(serverConfig);
connector.create();
connector.start();

For more information about ServerConfiguration, see the section "Declarative configuration: POJOs".

5.1.1.2. Declarative configuration: MBeans

One configuration option discussed in Section Programmatic configuration, passing an XML document to the Connector, works in conjunction with the service archive deployer (SARDeployer) inside the JBoss Application Server to allow declarative configuration on the server side. In particular, the SARDeployer reads XMl documents containing MBean descriptors from files whose name has the form "*-service.xml". When it sees a descriptor for a Connector MBean, it passes the descriptor's <config> element to a newly created Connector.

There are two ways in which to specify the server invoker configuration via a service xml file. The first is to specify just the InvokerLocator attribute as a sub-element of the Connector MBean. For example, a possible configuration for a Connector using a socket invoker that is listening on port 8084 on the test.somedomain.com address would be:

<mbean code="org.jboss.remoting.transport.Connector"
       name="jboss.remoting:service=Connector,transport=Socket"
       display-name="Socket transport Connector">
   <attribute name="InvokerLocator">
      <![CDATA[socket://test.somedomain.com:8084]]>
   </attribute>
   <attribute name="Configuration">
      <config>
         <handlers>
            <handler subsystem="mock">
               org.jboss.remoting.transport.mock.MockServerInvocationHandler
            </handler>
         </handlers>
      </config>
   </attribute>
</mbean>

Note that all the server side socket invoker configurations will be set to their default values in this case. Also, it is important to add CDATA to any locator uri that contains more than one parameter.

The other way to configure the Connector and its server invoker in greater detail is to provide an invoker sub-element within the config element of the Configuration attribute. The only attribute of invoker element is transport, which will specify which transport type to use (e.g.. socket, rmi, or http). All the sub-elements of the invoker element will be attribute elements with a name attribute specifying the configuration property name and then the value. An isParam attribute can also be added to indicate that the attribute should be added to the locator uri, in the case the attribute needs to be used by the client. An example using this form of configuration is as follows:

<mbean code="org.jboss.remoting.transport.Connector"
       name="jboss.remoting:service=Connector,transport=Socket"
       display-name="Socket transport Connector">
   
   <attribute name="Configuration">
      <config>
          
         <invoker transport="socket">
            <attribute name="numAcceptThreads">1</attribute>
            <attribute name="maxPoolSize">303</attribute>
            <attribute name="clientMaxPoolSize" isParam="true">304</attribute>
            <attribute name="socketTimeout">60000</attribute>
            <attribute name="serverBindAddress">192.168.0.82</attribute>
            <attribute name="serverBindPort">6666</attribute>
            <attribute name="clientConnectAddress">216.23.33.2</attribute>
            <attribute name="clientConnectPort">7777</attribute>
            <attribute name="enableTcpNoDelay" isParam="true">false</attribute>
            <attribute name="backlog">200</attribute>
         </invoker>
         
         <handlers>
            <handler subsystem="mock">
               org.jboss.remoting.transport.mock.MockServerInvocationHandler
            </handler>
         </handlers>
      </config>
   </attribute>
   
</mbean>

Also note that ${jboss.bind.address} can be used for any of the bind address properties, which will be replaced with the bind address specified to JBoss when starting (i.e. via the -b option).

All the attributes set in this configuration could be set directly in the locator uri of the InvokerLocator attribute value, but would be much more difficult to decipher visually and is more prone to editing mistakes.

One of the components of a locator uri that can be expressed within the InvokerLocator attribute is the path. For example, can express a locator uri path of 'foo/bar' via the InvokerLocator attribute as:

<attribute name="InvokerLocator">
   <![CDATA[socket://test.somedomain.com:8084/foo/bar]]>
</attribute>

To include the path using the Configuration attribute, can include a specific 'path' attribute. So the same InvokerLocator can be expressed as follows with the Configuration attribute:

<attribute name="Configuration">
   <config>
      <invoker transport="socket">
         <attribute name="serverBindAddress">test.somedomain.com</attribute>
         <attribute name="serverBindPort">8084</attribute>
         <attribute name="path">foo/bar</attribute>
      </invoker>
      ...

Note: The value for the 'path' attribute should NOT start or end with a / (slash).

5.1.1.3. Declarative configuration: POJOs

The last configuration option discussed in Section Programmatic configuration, passing an org.jboss.remoting.ServerConfiguration object to the Connector.setServerConfiguration() method, works in conjunction with the JBoss Microcontainer, which supports the injection of POJOs. In particular, the Microcontainer reads XML documents containing POJO descriptors from files whose name has the form "*-beans.xml".

A ServerConfiguration object holds four components:

  • transport (supplied by constructor)

  • invokerLocatorParameters: this is a map of all parameter names and values that will go into the org.jboss.remoting.InvokerLocator

  • serverParameters: this is a map of parameter names and values that will be used by the server but will not go into the InvokerLocator

  • invocationHandlers: this is a map of invocation handlers. The key is the subsystem, or comma separated list of subsystems.

A sample remoting-beans.xml file which duplicates the example in the previous sections is:

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
            
   <bean name="remoting:invocationHandler"
         class="org.jboss.remoting.transport.mock.SampleInvocationHandler"/>
             
   <bean name="remoting:serverConfiguration"
         class="org.jboss.remoting.ServerConfiguration">
      <constructor>
         <parameter>socket</parameter>
      </constructor>
      <property name="invokerLocatorParameters">
         <map keyClass="java.lang.String" valueClass="java.lang.String">
            <entry>
               <key>serverBindAddress</key>
               <value>test.somedomain.com</value>
            </entry>
            <entry>
               <key>serverBindPort</key>
               <value>8084</value>
            </entry>
         </map>
      </property>
      <property name="serverParameters">
         <map keyClass="java.lang.String" valueClass="java.lang.String">
            <entry>
               <key>clientLeasePeriod</key>
               <value>10000</value>
            </entry>
         </map>
      </property>
      <property name="invocationHandlers">
         <map keyClass="java.lang.String" 
              valueClass="org.jboss.remoting.ServerInvocationHandler">
            <entry>
               <key>mock</key>
               <value><inject bean="remoting:invocationHandler"/></value>
            </entry>
         </map>
      </property>
   </bean>
             
   <bean name="remoting:connector" class="org.jboss.remoting.transport.Connector">
      <property name="serverConfiguration">
         <inject bean="remoting:serverConfiguration"/>
      </property>
   </bean>
             
</deployment>

For more information about using the JBoss Microcontainer, see http://www.jboss.org/jbossmc/.

5.1.1.4. Callback client configuration

Remoting supports asynchronous computation and delivery of results through a callback mechanism, as described in Section Callbacks. Callbacks are sent from the server side to the client side on a callback connection which is the reverse of the usual client to server connection. That is, a client invoker on the server side communicates with a server invoker on the client side (in the case of push callbacks - again, see Section Callbacks). When a callback connection is created, all of the configuration information passed to the server side Connector is passed on to the server side callback client invoker. It follows that callback client invokers are configured by way of the server side Connector.

5.1.2. Client side configuration

Invoker configuration on the client side parallels configuration on the server side, with the exception that (1) it operates in a simpler environment (in particular, it does not assume the presence of an MBeanServer) and (2) it does not support a declarative option. However, it does support versions of the first three server side programmatic options, with the Client class playing the central role played by the Connector class on the server side.

Again, the most straightforward form of configuration is to put the configuration parameters on the InvokerLocator. For example, the fragment

String locatorURI = "socket://test.somedomain.com:8084";
String params = "/?clientMaxPoolSize=10&timeout=360000";
locatorURI += params;
InvokerLocator locator = new InvokerLocator(locatorURI);
Client client = new Client(locator);
client.connect();

creates a Client using the socket transport to connect to a server on host test.somedomain.com, listening on port 8084. It also passes in two parameters, "clientMaxPoolSize" and "timeout", that will be used by the client invoker.

It is also possible to use configuration maps on the client side. The following code fragment accomplishes all that the previous fragment does, but it passes one parameter by way of the InvokerLocator and passes the other by way of a configuration map. It also passes in a non-string object, a SocketFactory:

String locatorURI = "socket://test.somedomain.com:8084";
String params = "/?clientMaxPoolSize=10";
locatorURI += params;
InvokerLocator locator = new InvokerLocator(locatorURI);
HashMap config = new HashMap();
config.put(ServerInvoker.TIMEOUT, 360000);
config.put(Remoting.CUSTOM_SOCKET_FACTORY, new MySocketFactory());
Client client = new Client(locator, config);
client.connect();

Note that the value of ServerInvoker.TIMEOUT is "timeout", and the value of Remoting.CUSTOM_SOCKET_FACTORY is "customSocketFactory". These configuration map keys are discussed throughout the chapter and accumulated in section Configuration by properties. Also, socket factory configuration is covered in Socket factories and server socket factories.

Finally, a third programmatic option is available for those configuration properties which happen to be settable client invoker properties. In the following fragment, the client invoker is obtained from the Client and a SocketFactory is passed to it by way of a setter method:

String locatorURI = "socket://test.somedomain.com:8084";
String params = "/?clientMaxPoolSize=10";
locatorURI += params;
InvokerLocator locator = new InvokerLocator(locatorURI);
HashMap config = new HashMap();
config.put(ServerInvoker.TIMEOUT, 360000);
Client client = new Client(locator, config);
client.connect();
SocketFactory sf = new MySocketFactory();
ClientInvoker clientInvoker = client.getInvoker();
clientInvoker.setSocketFactory(sf);

Note. The Client creates the client invoker during the call to Client.connect(), so this option only works after that method has been called.

5.2. Handlers

Handlers are classes that the invocation is given to on the server side (the final target for remoting invocations). To implement a handler, all that is needed is to implement the org.jboss.remoting.ServerInvocationHandler interface. There are a two ways in which to register a handler with a Connector. The first is to do it programmatically. The second is via service configuration. For registering programmatically, can either pass the ServerInvocationHandler reference itself or an ObjectName for the ServerInvocationHandler (in the case that it is an MBean). To pass the handler reference directly, call Connector::addInvocationHandler(String subsystem, ServerInvocationHandler handler). For example (from org.jboss.remoting.samples.simple.SimpleServer):

InvokerLocator locator = new InvokerLocator(locatorURI);
Connector connector = new Connector();
connector.setInvokerLocator(locator.getLocatorURI());
connector.create();

SampleInvocationHandler invocationHandler = new SampleInvocationHandler();
// first parameter is sub-system name. can be any String value.
connector.addInvocationHandler("sample", invocationHandler);

connector.start();

To pass the handler by ObjectName, call Connector::addInvocationHandler(String subsystem, ObjectName handlerObjectName) . For example (from org.jboss.test.remoting.handler.mbean.ServerTest):

MBeanServer server = MBeanServerFactory.createMBeanServer();
InvokerLocator locator = new InvokerLocator(locatorURI);
Connector connector = new Connector();
connector.setInvokerLocator(locator.getLocatorURI());
connector.start();

server.registerMBean(connector, new ObjectName("test:type=connector,transport=socket"));

// now create Mbean handler and register with mbean server
MBeanHandler handler = new MBeanHandler();
ObjectName objName = new ObjectName("test:type=handler");
server.registerMBean(handler, objName);

connector.addInvocationHandler("test", objName);

Is important to note that if not starting the Connector via the service configuration, will need to explicitly register it with the MBeanServer (will throw exception otherwise).

If using a service configuration for starting the Connector and registering handlers, can either specify the fully qualified class name for the handler, which will instantiate the handler instance upon startup (which requires there be a void parameter constructor), such as:

<handlers>
   <handler subsystem="mock">
      org.jboss.remoting.transport.mock.MockServerInvocationHandler
   </handler>
</handlers>

where MockServerInvocationHandler will be constructed upon startup and registered with the Connector as a handler.

Can also use an ObjectName to specify the handler. The configuration is the same, but instead of specifying a fully qualified class name, you specify the ObjectName for the handler, such as (can see mbeanhandler-service.xml under remoting tests for full example):

<handlers>
   <handler subsystem="mock">test:type=handler</handler>
</handlers>

The only requirement for this configuration is that the handler MBean must already be created and registered with the MBeanServer at the point the Connector is started.

Handler implementations

The Connectors will maintain a reference to the handler instances provided (either indirectly via the MBean proxy or directly via the instance object reference). For each request to the server invoker, the handler will be called upon. Since the server invokers can be multi-threaded (and in most cases would be), this means that the handler may receive concurrent calls to handle invocations. Therefore, handler implementations should take care to be thread safe in their implementations.

Stream handler

There is also an invocation handler interface that extends the ServerInvocationHandler interface specifically for handling of input streams as well as normal invocations. See the section on sending streams for further details. As for Connector configuration, it is the same.

HTTP handlers

Since there is extra information needed when dealing with the http transport, such as headers and response codes, special consideration is needed by handlers. The handlers receiving http invocations can get and set this extra information via the InvocationRequest that is passed to the handler.

Server invoker for the http transport will add the following to the InvocationRequest's request payload map:

MethodType - the http request type (i.e., GET, POST, PUT, HEADER, OPTIONS). Can use the contant value HTTPMetadataConstants.METHODTYPE, if don't want to use the actual string 'MethodType' as the key to the request payload map.

Path - the url path. Can use the contant value HTTPMetadataConstants.PATH, if don't want to use the actual string 'Path' as the key to the request payload map.

HttpVersion - the client's http version. Can use the contant value HTTPMetadataConstants.HTTPVERSION, if don't want to use the actual string 'HttpVersion' as the key to the request payload map.

Other properties from the original http request will also be included in the request payload map, such as request headers. Can reference org.jboss.test.remoting.transport.http.method.MethodInvocationHandler as an example for pulling request properties from the InvocationRequest.

The only time this will not be added is a POST request where an InvocationRequest is passed and is not binary content type (application/octet-stream).

The handlers receiving http invocations can also set the response code, response message, and response headers. To do this, will need to get the return payload map from the InvocationRequest passed (via its getReturnPayload() method). Then populate this map with whatever properties needed. For response code and message, will need to use the following keys for the map:

ResponseCode - Can use the constant value HTTPMetaDataConstants.RESPONSE_CODE, if don't want to use the actual string 'ResponseCode' as they key. IMPORTANT - The value put into map for this key MUST be of type java.lang.Integer.

ResponseCodeMessage - Can use the constant value HTTPMetadataConstants.RESPONSE_CODE_MESSAGE, if don't want to use the actual string 'ResponseCodeMessage' as the key. The value put into map for this key should be of type java.lang.String.

Is also important to note that ALL http requests will be passed to the handler. So even OPTIONS, HEAD, and PUT method requests will need to be handled. So, for example, if want to accept OPTIONS method requests, would need to populate response map with key of 'Allow' and value of 'OPTIONS, POST, GET, HEAD, PUT', in order to tell calling client that all these method types are allowed. Can see an example of how to do this within org.jboss.test.remoting.transport.http.method.MethodInvocationHandler.

The PUT request will be handled the same as a POST method request and the PUT request payload will be included within the InvocationRequest passed to the server handler. It is up to the server handler to set the proper resonse code (or throw proper exception) for the processing of the PUT request. See http://www.ietf.org/rfc/rfc2616.txt?number=2616 , section 9.6 for details on response codes and error responses).

HTTP Client

The HttpClientInvoker will now put the return from HttpURLConnection getHeaderFields() method into the metadata map passed to the Client's invoke() method (if not null). This means that if the caller passes a non-null Map, it can then get the response headers. It is important to note that each response header field key in the metadata map is associated with a list of response header values, so to get a value, would need code similar to:

Object response = remotingClient.invoke((Object) null, metadata); 
String allowValue = (String) ((List) metadata.get("Allow").get(0);

Can reference org.jboss.test.remoting.transport.http.method.HTTPInvokerTestClient for an example of this.

Note that when making a http request using the OPTIONS method type, the return from the Client's invoke() method will ALWAYS be null.

Also, if the response code is 400, the response returned will be that of the error stream and not the standard input stream. So is important to check for the response code.

Two values that will always be set within the metadata map passed to the Client's invoke() method (when not null), is the response code and response message from the server. These can be found using the keys:

ResponseCode - Can use the constant value HTTPMetaDataConstants.RESPONSE_CODE, if don't want to use the actual string 'ResponseCode' as the key. IMPORTANT - The value returned for this key will be of type java.lang.Integer.

ResponseCodeMessage - Can use the constant value from HTTPMetadataConstants.RESPONSE_CODE_MESSAGE, if don't want to use the actual string 'ResponseCodeMessage' as the key. The value returned for this key will be of type java.lang.String.

An example of getting the response code can be found within org.jboss.test.remoting.transport.http.method.HTTPInvokerTestClient.

5.3. Discovery (Detectors)

Domains

Detectors have the ability to accept multiple domains. What domains that the detector will accept as viewable can either be set programmatically via the method:

public void setConfiguration(org.w3c.dom.Element xml)

or by adding to jboss-service.xml configuration for the detector. The domains that the detector is currently accepting can be retrieved from the method:

public org.w3c.dom.Element getConfiguration()

The configuration xml is a MBean attribute of the detector, so can be set or retrieved via JMX.

There are three possible options for setting up the domains that a detector will accept. The first is to not call the setConfiguration() method (or just not add the configuration attribute to the service xml). This will cause the detector to use only its domain and is the default behavior. This enables it to be backwards compatible with earlier versions of JBoss Remoting (JBoss 4, DR2 and before).

The second is to call the setConfiguration() method (or add the configuration attribute to the service xml) with the following xml element:

<domains>
   <domain>domain1</domain>
   <domain>domain2</domain>
</domains>

where domain1 and domain2 are the two domains you would like the detector to accept. This will cause the detector to accept detections only from the domains specified, and no others.

The third and final option is to call the setConfiguration() method (or add the configuration attribute to the service xml) with the following xml element:

<domains>
</domains>

This will cause the detector to accept all detections from any domain.

By default, remoting detection will ignore any detection message the it receives from a server invoker running within its own jvm. To disable this, add an element called 'local' to the detector configuration (alongside the domain element) to indicate should accept detection messages from local server invokers. This will be false by default, so maintains the same behavior as previous releases. For example:

<domains>
   <domain>domain1</domain>
   <domain>domain2</domain>
</domains>
<local/>

An example entry of a Multicast detector in the jboss-service.xml that accepts detections only from the roxanne and sparky domains using port 5555, including servers in the same jvm, is as follows:

<mbean code="org.jboss.remoting.detection.multicast.MulticastDetector"
       name="jboss.remoting:service=Detector,transport=multicast">
   <attribute name="Port">5555</attribute>
   <attribute name="Configuration">
      <domains>
         <domain>roxanne</domain>
         <domain>sparky</domain>
      </domains>
      <local/>
   </attribute>
</mbean>

Global Detector Configuration

The following are configuration attributes for all the remoting detectors.

DefaultTimeDelay - amount of time, in milliseconds, which can elapse without receiving a detection event before suspecting that a server is dead and performing an explicit invocation on it to verify it is alive. If this invocation, or ping, fails, the server will be removed from the network registry. The default is 5000 milliseconds.

HeartbeatTimeDelay - amount of time to wait between sending (and sometimes receiving) detection messages. The default is 1000 milliseconds.

JNDIDetector

Port - port to which detector will connect for the JNDI server.

Host - host to which the detector will connect for the JNDI server.

ContextFactory - context factory string used when connecting to the JNDI server. The default is org.jnp.interfaces.NamingContextFactory .

URLPackage - url package string to use when connecting to the JNDI server. The default is org.jboss.naming:org.jnp.interfaces .

CleanDetectionNumber - Sets the number of detection iterations before manually pinging remote server to make sure still alive. This is needed since remote server could crash and yet still have an entry in the JNDI server, thus making it appear that it is still there. The default value is 5.

Can either set these programmatically using setter method or as attribute within the remoting-service.xml (or anywhere else the service is defined). For example:

<mbean code="org.jboss.remoting.detection.jndi.JNDIDetector"
       name="jboss.remoting:service=Detector,transport=jndi">
   <attribute name="Host">localhost</attribute>
   <attribute name="Port">5555</attribute>
</mbean>

If the JNDIDetector is started without the Host attribute being set, it will try to start a local JNP instance (the JBoss JNDI server implementation) on port 1088.

MulticastDetector

DefaultIP - The IP that is used to broadcast detection messages on via multicast. To be more specific, will be the ip of the multicast group the detector will join. This attribute is ignored if the Address has already been set when started. Default is 224.1.9.1.

Port - The port that is used to broadcast detection messages on via multicast. Default is 2410.

BindAddress - The address to bind to for the network interface.

Address - The IP of the multicast group that the detector will join. The default will be that of the DefaultIP if not explicitly set.

If any of these are set programmatically, need to be done before the detector is started (otherwise will use default values).

5.4. Transports (Invokers)

This section covers configuration issues for each of the transports, beginning with material that applies to all transports. The material in a later section in this chapter, Socket factories and server socket factories, also applies to all transports.

5.4.1. Features introduced in Remoting version 2.4

A number of transport independent features are introduced in Remoting version 2.4.

5.4.1.1. Binding to 0.0.0.0

Before version 2.4, a Remoting server could bind to only one specific IP address. In particular, the address 0.0.0.0 was translated to the host returned by java.net.InetAddress.getLocalHost() (or its equivalent IP address). As of version 2.4 [and later releases in the 2.2 series], a server started with the address 0.0.0.0 binds to all available interfaces.

Note. If 0.0.0.0 appears in the InvokerLocator, it needs to be translated to an address that is usable on the client side. If the system property InvokerLocator.BIND_BY_HOST (actual value "remoting.bind_by_host") is set to "true", the InvokerLocator host will be transformed to the value returned by InetAddress.getLocalHost().getHostName(). Otherwise, it will be transformed to the value returned by InetAddress.getLocalHost().getHostAddress().

5.4.1.2. Multihome servers

As of release 2.4, besides binding to all available interfaces, it is also possible to configure a server to bind to a subset of the interfaces available on a given host. Suppose, for example, that a host machine has NICs configured with addresses 10.32.4.2, 192.168.4.2, and 192.168.8.2, and suppose that 192.168.8.2 is on a LAN from which access is meant to be denied. It is now possible to create a single server that binds to 10.32.4.2 and 192.168.4.2.

It would be convenient to be able to create an InvokerLocator that looks something like:

socket://10.32.4.2&192.168.4.2:6500

but, unfortunately, that violates the URI syntax. Instead, a special placeholder, "multihome", is used in the host position, and the actual host addresses are given in the query component, e.g.,

socket://multihome/?homes=10.32.4.2:6500!192.168.4.2:6500

An abbreviated syntax allows factoring out the bind port:

socket://multihome:6500/?homes=10.32.4.2!192.168.4.2

The value in the port position is treated as a default value which can be overriden in the "homes" parameter:

socket://multihome:6500/?homes=10.32.4.2!192.168.4.2:6501

binds to 10.32.4.2:6500 and 192.168.4.2:6501.

In the presence of a NAT router, it may be necessary for the client to connect to addresses different than the bind addresses, and a set of connect addresses may be specified with a "connecthomes" parameter:

socket://multihome/?homes=10.32.4.2:6500!192.168.4.2:6501
       &connecthomes=10.32.42.2:7500!192.168.42.2:7501

specifies a server that binds to 10.32.4.2:6500 and 192.168.4.2:6501, as before, but now a client connects to it using the addresses 10.32.42.2:7500 and 192.168.42.2:7501.

Multihome servers may be configured, also, in *-service.xml MBean files and *-beans.xml POJO files. The following MBean definition is equivalent to the preceding locator:

<mbean code="org.jboss.remoting.transport.Connector"
       name="jboss.remoting:service=Connector,transport=Socket"
       display-name="Socket transport Connector">
    
   <attribute name="Configuration">
      <config>
         <invoker transport="socket">
            
            <attribute name="homes">
               <home>10.32.4.2:6500</home>
               <home>192.168.4.2:6501</home>
            </attribute>
            <attribute name="connecthomes">
               <connecthome>10.32.42.2:7500</connecthome>
               <connecthome>192.168.42.2:7501</connecthome>
            </attribute>
            
         </invoker>
         <handlers>
            ...
         </handlers>
      </config>
   </attribute>
</mbean>

The "serverBindPort" and "clientConnectPort" attributes may be used to give default values for bind ports and connect ports, respectively.

The same server may be configured with the org.jboss.remoting.ServerInvocation object as well. For example,

Connector connector = new Connector();
         
// Create ServerConfiguration object for socket transport
ServerConfiguration serverConfig = new ServerConfiguration("socket");
            
// Add invokerLocatorParameters (applicable to client and server)
Map locatorConfig = new HashMap();

locatorConfig.put("homes", "10.32.4.2:6500!192.168.4.2:6501");
locatorConfig.put("connecthomes", "10.32.42.2:7500!192.168.42.2:7501");

serverConfig.setInvokerLocatorParameters(locatorConfig);
                   
// Add invocation handlers
...
             
connector.setServerConfiguration(serverConfig);
connector.create();
connector.start();

is equivalent to the preceding MBean definition.

Note. The Strings "homes" and "connecthomes" are available as constants in the InvokerLocator class: InvokerLocator.HOMES_KEY and InvokerLocator.CONNECT_HOMES_KEY.

5.4.1.3. Socket creation listeners

Sometimes it is useful to be able to grab a socket right after it has been created to either apply some additional configuration or retrieve some information. It is possible to configure Remoting with instantions of the interface org.jboss.remoting.socketfactory.SocketCreationListener

public interface SocketCreationListener
{
   /**
    * Called when a socket has been created.
    * 
    * @param socket socket that has been created
    * @param source SocketFactory or ServerSocket that created the socket
    * @throws IOException
    */
   void socketCreated(Socket socket, Object source) throws IOException;
}

Socket creation listeners can be configured through the use of the keys org.jboss.remoting.Remoting.SOCKET_CREATION_CLIENT_LISTENER (actual value "socketCreationClientListener") and org.jboss.remoting.Remoting.SOCKET_CREATION_SERVER_LISTENER (actual value "socketCreationServerListener"), which install listeners for javax.net.SocketFactorys and java.net.ServerSockets, respectively. The value associated with these keys may be (1) an object that implements SocketCreationListener or (2) a string that names a class that implements SocketCreationListener. In the latter case, the default constructor will be used to create an object of the designated class.

5.4.1.4. Making client IP address available to application

All of the transports (bisocket, sslbisocket, http, https, rmi, sslrmi, servlet, sslservlet, socket, and sslsocket) capture the IP address of the client side of a TCP connection from client to server and make it available to application code on both the client side and server side. On the client side, the method org.jboss.remoting.Client.getAddressSeenByServer(), with signature

public InetAddress getAddressSeenByServer() throws Throwable

returns the IP address of the client as seen by the server. On the server side, the same IP address is placed in the request payload map held by the org.jboss.remoting.InvocationRequest. It may be retrieved by the org.jboss.remoting.ServerInvocationHandler as follows:

public Object invoke(InvocationRequest invocation throws Throwable
{
   ...
   InetAddress address = invocation.getRequestPayload().get(Remoting.CLIENT_ADDRESS);
   ...
}

5.4.1.5. Support for IPv6 addresses

org.jboss.remoting.InvokerLocator will now accept IPv6 IP addresses. For example,

socket://[::1]:3333/?timeout=10000
socket://[::]:4444/?timeout=10000
socket://[::ffff:127.0.0.1]:5555/?timeout=10000
socket://[fe80::205:9aff:fe3c:7800%7]:6666/?timeout=10000
socket://multihome/?homes=[fe80::205:9aff:fe3c:7800%7]:7777![fe80::214:22ff:feef:68bb%4]:8888

5.4.1.6. Delayed destruction of client invokers

Multiple clients may share a single client invoker. For example, in the code

InvokerLocator locator = new InvokerLocator("socket://127.0.0.1:5555");
Client client1 = new Client(locator);
Client client2 = new Client(locator);

client1 and client2 will both communicate with the server through a single org.jboss.remoting.transport.socket.MicroSocketClientInvoker. The number of Clients using a single client invoker is tracked, and the invoker is destroyed when the count goes to zero. It may be useful to delay the destruction of the invoker when it is known that another Client will want to use it in the near future. The delayed destruction of a client invoker may be achieved through the use of the key Client.INVOKER_DESTRUCTION_DELAY (actual value "invokerDestructionDelay"). For example,

InvokerLocator locator =
        new InvokerLocator("socket://127.0.0.1:5555/?invokerDestructionDelay=5000");
Client client = new Client(locator);
client.connect();
...
client.disconnect();

will cause client to delay the destruction of its client invoker (assuming client is the only user), by 5000 milliseconds. Of course, "invokerDestructionDelay" may be passed to the Client by way of a configuration map, as well.

5.4.2. Server Invokers

The following configuration properties are common to all the current server invokers.

serverBindAddress - The address on which the server binds to listen for requests. The default is an empty value which indicates the server should be bound to the host provided by the locator url, or if this value is null, the local host as provided by InetAddress.getLocalHost() .

serverBindPort - The port to listen for requests on. A value of 0 or less indicates that a free anonymous port should be chosen.

maxNumThreadsOneway - specifies the maximum number of threads to be used within the thread pool for accepting one way invocations on the server side. This property will only be used in the case that the default thread pool is used. If a custom thread pool is set, this property will have no meaning. This property can also be retrieved or set programmatically via the MaxNumberOfOnewayThreads property.

onewayThreadPool - specifies either the fully qualified class name for a class that implements the org.jboss.util.threadpool.ThreadPool interface or the JMX ObjectName for an MBean that implements the org.jboss.util.threadpool.ThreadPool interface. This will replace the default org.jboss.util.threadpool.BasicThreadPool used by the server invoker.

Note that this value will NOT be retrieved until the first one-way (server side) invocation is made. So if the configuration is invalid, will not be detected until this first call is made. The thread pool can also be accessed or set via the OnewayThreadPool property programmatically.

Important to note that the default thread pool used for the one-way invocations on the server side will block the calling thread if all the threads in the pool are in use until one is released.

5.4.3. Configurations affecting the invoker client

There are some configurations which will impact the invoker client. These will be communicated to the client invoker via parameters in the Locator URI. These configurations can not be changed during runtime, so can only be set up upon initial configuration of the server invoker on the server side. The following is a list of these and their effects.

clientConnectPort - the port the client will use to connect to the remoting server. This would be needed in the case that the client will be going through a router that forwards requests made externally to a different port internally.

clientConnectAddress - the ip or hostname the client will use to connect to the remoting server. This would be needed in the case that the client will be going through a router that forwards requests made externally to a different ip or host internally.

If no client connect address or server bind address specified, will use the local host's address (via InetAddress.getLocalHost().getHostAddress() ).

5.4.4. How the server bind address and port is determined

If the serverBindAddress property is set, the server invoker will bind to that address. Otherwise, it will, with one exception, use the address in the InvokerLocator (if there is one). The exception is the case in which the clientConnectAddress property is set, which indicates that the adddess in the InvokerLocator is not the real address of the server's host. In that case, and in the case that there is no address in the InvokerLocator, the server will bind to the address of the local host, as determined by the call

InetAddress.getLocalHost().getHostAddress();

In other words, the logic is

if (serverBindAddress is set)
   use it
else if (the host is present in the InvokerLocator and clientConnectAddress is not set)
   use host from InvokerLocator
else
   use local host address

If the serverBindPort property is set, it will be used. If this value is 0 or a negative number, then the next available port will be found and used. If the serverBindPort property is not set, but the clientConnectPort property is set, then the next available port will be found and used. If neither the serverBindPort nor the clientConnectPort is set, then the port specified in the original InvokerLocator will be used. If this is 0 or a negative number, then the next available port will be found and used. In the case that the next available port is used because either the serverBindPort or the original InvokerLocator port value was either 0 or negative, the InvokerLocator will be updated to reflect the new port value.

5.4.5. Socket transport

The Socket transport is one of the more complicated invokers mainly because allows the highest degree of configuration. To better understand how changes to configuration properties for the Socket invoker (both client and server) will impact performance and scalability, will discuss the implementation and how it works in detail.

5.4.5.1. How the Socket transport works

Server

When the socket server invoker is started, it will create one, and only one, instance of java.net.ServerSocket for each configured bind address. Typically there would exactly one ServerSocket, but there would be more than one for a mltihome server with multiple bind addresses. Upon being started, it will also create and start a number of threads to be used for accepting incoming requests from the ServerSocket. These threads are called the accept threads and the number of them created is controlled by the "numAcceptThreads" property. If "numAcceptThreads" is set to "n" (it defaults to 1), there will be "n" accept threads per ServerSocket. When these accept threads are started, they will call accept() on the ServerSocket and block until the ServerSocket receives a request from a client, where it will return a Socket back to the accept thread who called the accept() method. As soon as this happens, the accept thread will try to pass off the Socket to another thread for processing.

The threads that actually process the incoming request, referred to as server threads (org.jboss.remoting.transport.socket.ServerThread), are stored in a pool. The accept thread will try to retrieve the first available server thread from the pool and hand off the Socket for processing. If the pool does not contain any available server threads and the max pool size has not been reached, a new server thread will be created for processing. Otherwise, if the max pool size has been reached, the accept thread will wait for one to become available (will wait until socket timeout has been reached). The size of the server thread pool is defined by the 'maxPoolSize' property. As soon as the accept thread has been able to hand off the Socket to a server thread for processing, it will loop back to ServerSocket and call accept() on it again. This will continue until the socket server invoker is stopped.

The server thread processing the request will be the thread of execution through the unmarshalling of the data, calling on the server invocation handler, and marshalling of response back to the client. After the response has been sent, the server thread will then hold the socket connection and wait for another request to come from this client. It will wait until the socket is closed by the client, a socket timeout occurs, or receives another request from the client in which to process. When the client socket connection session is closed, meaning timeout or client closed socket connection, then the thread will return itself to the pool.

If all the server threads from the pool are in use, meaning have a client connection established, and the pool has reached its maximum value, the accept threads (no matter how many there are) will have to wait until one of the server threads is available for processing. This why having a large number of accept threads does not provide any real benefit. If all the accept threads are blocked waiting for server thread, new client requests will then be queued until it can be accepted. The number of requests that can be queued is controlled by the "backlog" property and can be useful in managing sudden bursts in requests.

If take an example with a socket server invoker that has max pool set to 300, accept threads is 2, and backlog is 200, will be able to make 502 concurrent client calls. The 503rd client request will get an exception immediately. However, this does not mean all 502 requests will be guaranteed to be processed, only the first 300 (as they have server threads available to do the processing). If 202 of the server threads finish processing their requests from their initial client connections and the connection is released before the timeout for the other 202 that are waiting (200 for backlog and 2 for accept thread), then they will be processed (of course this is a request by request determination).

As of JBossRemoting 2.2.0 release, can also add configuration for cleaning up idle server threads using the 'idleTimeout' configuration property. Setting this property to a value of greater than zero will activate idle timeout checking, which is disabled by default. When enabled, the idle timeout checker will periodically iterate through the server threads that are active and inactive and if have not processed a request within the designated idle timeout period, the server thread will be shutdown and removed from corresponding pool. Active server threads are ones that have a socket connection associated with it and are in a blocked read waiting for data from the client. Inactive server threads are ones that have finished processing on a particular socket connection and have been returned to the thread pool for later reuse.

Note. As of Remoting version 2.4, some changes have been made to ServerThread.

  1. Once a server thread has completed an invocation, it will try to read another invocation instead of returning to the thread pool. It follows that the fact that a server thread is not in the thread pool does not necessarily indicate that it is busy: it might just be blocked in a InputStream.read(). Therefore, when an accept thread needs a server thread and the thread pool is empty, it will try to appropriate server threads which are not in the thread pool. While a server thread is in the middle of processing an invocation, it cannot be interrupted, but if it is blocked waiting for the next invocation, it is available to be interrupted. However, when the server is busy, it is conceivable for an accept thread to grab a server thread and before the server thread gets a chance to read an invocation, it gets interrupted again by the accept thread. To prevent server threads from bouncing around like that, the parameter ServerThread.EVICTABILITY_TIMEOUT (actual value "evictabilityTimeout) has been introduced. If less than that period has elapsed since the server thread has started waiting for the next invocation, it will not allow itself to be pre-empted.

  2. Prior to version 2.4, if a server thread experienced a java.net.SocketTimeoutException, it would return itself to the thread pool and could not be reused until a new socket connection was created for it to use. In principle, it would be more efficient for the server thread simply to try again to read the next invocation. Unfortunately, java.io.ObjectInputStream ceases to function once it experiences a SocketTimeoutException. The good news is that org.jboss.serial.io.JBossObjectInputStream, made available by the JBossSerialization project, does not suffer from that problem. Therefore, when it experiences a SocketTimeoutException, a server thread will check whether it is using a JBossObjectInputStream or not and act accordingly. Just to allow for the possibility that an application is using yet another version of ObjectInputStream, the parameter ServerThread.CONTINUE_AFTER_TIMEOUT (actual value "continueAfterTimeout") allows the behavior following a SocketTimeoutException to be configured explicitly.

Client

When the socket client invoker makes its first invocation, it will check to see if there is an available socket connection in its pool. Since is the first invocation, there will not be and will create a new socket connection and use it for making the invocation. Then when finished making invocation, wi