JBoss Remoting Guide

JBoss Remoting Guide

JBoss Remoting version 2.2.2.SP10

October 1, 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?
1.4.1. In release 2.2.2.SP10
1.4.2. In release 2.2.2.SP9
1.4.3. In release 2.2.2.SP8
1.4.4. In release 2.2.2.SP7
1.4.5. In release 2.2.2.SP4
1.4.6. In release 2.2.2.SP2
1.4.7. In release 2.2.2.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
5.1.1.3. 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.2
5.4.1.1. Binding to 0.0.0.0
5.4.1.2. Support for IPv6 addresses
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 Invoker
5.4.5.1. How the Socket Invoker works
5.4.6. SSL Socket Invoker
5.4.7. RMI Invoker
5.4.8. SSL RMI Invoker
5.4.9. HTTP Invoker
5.4.10. HTTPS Invoker
5.4.11. HTTP(S) Client Invoker - proxy and basic authentication
5.4.12. Servlet Invoker
5.4.13. SSL Servlet Invoker
5.4.14. Exception handling for web based clients
5.4.15. Multiplex Invoker
5.4.15.1. Setting up the server
5.4.15.2. Setting up the client
5.4.15.3. Shutting down invoker groups.
5.4.15.4. Examples
5.4.15.5. Configuration properties
5.4.16. SSL Multiplex Invoker
5.4.17. Bisocket invoker
5.4.17.1. Overview
5.4.17.2. Details
5.4.18. SSL Bisocket invoker
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 transport
5.8.3.3. Quick client disconnect
5.9. Configuration by properties
6. Sending streams
6.1. Configuration
6.2. Issues
7. Serialization
8. Network Connection Monitoring
8.1. Client side monitoring
8.2. Server side monitoring
8.3. Interactions between client side and server side connection monitoring
9. Transporters - beaming POJOs
10. How to use it - sample code
10.1. Simple invocation
10.2. HTTP invocation
10.3. Oneway invocation
10.4. Discovery and invocation
10.5. Callbacks
10.6. Streaming
10.7. JBoss Serialization
10.8. Transporters
10.8.1. Transporters - beaming POJOs
10.8.2. Transporters sample - simple
10.8.3. Transporter sample - basic
10.8.4. Transporter sample - JBoss serialization
10.8.5. Transporter sample - clustered
10.8.6. Transporters sample - multiple
10.8.7. Transporters sample - proxy
10.8.8. Transporter sample -complex
10.9. Multiplex invokers
11. Client programming model
12. Compatibility and versioning
13. Getting the JBossRemoting source and building
14. Known issues
15. Future plans
16. Release Notes

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)

    • Multiplex (SSL Multiplex)

    • 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://labs.jboss.com/portal/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?

1.4.1. In release 2.2.2.SP10

  1. CoyoteInvoker stores InvokerLocator query in InvocationRequest;

  2. miscellaneous bug and documentation fixes.

1.4.2. In release 2.2.2.SP9

  1. Fixed potential build up of cancelled TimerTasks in bisocket transport;

  2. it's possible to turn on server side connection monitoring (leasing) declaratively;

  3. miscellaneous bug fixes.

1.4.3. In release 2.2.2.SP8

  1. Remoting remote classloading facility now works with isolated EARs;

  2. InvokerLocator can process zone indices;

  3. improved client side connection monitoring;

  4. miscellaneous bug fixes.

1.4.4. In release 2.2.2.SP7

  1. Server side and client side connection listeners can be tied together.

1.4.5. In release 2.2.2.SP4

  1. IPv6 addresses are supported;

  2. org.jboss.remoting.callback.ServerInvokerCallbackHandler can register itself as a lease connection listener.

1.4.6. In release 2.2.2.SP2

  1. The servlet transport can throw an exception generated on the server side;

  2. servers can bind to 0.0.0.0.

1.4.7. In release 2.2.2.GA

Release 2.2.2.GA includes a number of bug fixes, greater configurability, and a couple of new features, including

  1. an improved callback polling method;

  2. the ability for the client to discover its IP address as seen by the server side of the connection;

The following changes affect configurability:

  1. The address and port of the bisocket transport secondary server socket are configurable;

  2. org.jboss.remoting.ConnectorValidator parameters are configurable;

  3. the maximum number of errors before a org.jboss.remoting.callback.CallbackPoller shuts down can be specified;

  4. there is a separate timeout parameter for callbacks.

For the JIRA items related to release 2.2.2.GA, see Release Notes.

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

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-multiplex.jar - contains all the classes needed for the multiplex and sslmultiplex transports to function as a client and a server. Use of this jar also requires jboss-remoting-socket.jar be on classpath as well.

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, commons-logging-api.jar, tomcat-http.jar

Note: need tomcat-apr.jar and tcnative-1.dll/tcnative-1.so on system path if want 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

Multiplex server and client: jboss-remoting-socket.jar, jboss-remoting-multiplex.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), or 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.

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.

5.1.1.2. Declarative configuration

The configuration option discussed at the end of the previous section, 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, http, or multiplex). 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. 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 client invoker MBean 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 a set of properties that apply 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.2

Subsequent to the release of Remoting 2.2.0.GA, some transport independent features have been introduced.

5.4.1.1. Binding to 0.0.0.0

Before release 2.2.2.SP2, 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 release 2.2.2.SP2, 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. Support for IPv6 addresses

As of release 2.2.2.SP4, org.jboss.remoting.InvokerLocator will 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
         

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 Invoker

The following configuration properties can be set at any time, but will not take effect until the socket invoker, on the server side, is stopped and restarted.

timeout - The socket timeout value passed to the Socket.setSoTimeout() method. The default on the server side is 60000 (one minute). If the timeout parameter is set, its value will also be passed to the client side (see below).

backlog - The preferred number of unaccepted incoming connections allowed at a given time. The actual number may be greater than the specified backlog. When the queue is full, further connection requests are rejected. Must be a positive value greater than 0. If the value passed if equal or less than 0, then the default value will be assumed. The default value is 200.

numAcceptThreads - The number of threads that exist for accepting client connections. The default is 1.

maxPoolSize - The number of server threads for processing client. The default is 300.

serverSocketClass - specifies the fully qualified class name for the custom SocketWrapper implementation to use on the server.

socket.check_connection - indicates if the invoker should try to check the connection before re-using it by sending a single byte ping from the client to the server and then back from the server. This config needs to be set on both client and server to work. This if false by default.

idleTimeout - indicates the number of seconds a pooled server thread can be idle (meaning time since last invocations request processed) before it should be cleaned up and removed from the thread pool. The value for this property must be greater than zero in order to enable idle timeouts on pooled server threads (otherwise they will not be checked). Setting to value less than zero will disable idle timeout checks on pooled server threads, in the case was previously enabled. The default value for this property is -1.

continueAfterTimeout - indicates what a server thread should do after experiencing a java.net.SocketTimeoutException. If set to "true", or if JBossSerialization is being used, the server thread will continue to wait for an invocation; otherwise, it will return itself to the thread pool.

Configurations affecting the Socket invoker client

There are some configurations which will impact the socket 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 socket invoker on the server side. The following is a list of these and their effects.

enableTcpNoDelay - can be either true or false and will indicate if client socket should have TCP_NODELAY turned on or off. TCP_NODELAY is for a specific purpose; to disable the Nagle buffering algorithm. It should only be set for applications that send frequent small bursts of information without getting an immediate response; where timely delivery of data is required (the canonical example is mouse movements). The default is false.

timeout - The socket timeout value passed to the Socket.setSoTimeout() method. The default on the client side is 1800000 (or 30 minutes).

clientMaxPoolSize - the client side maximum number of active socket connections. This basically equates to the maximum number of concurrent client calls that can be made from the socket client invoker. The default is 50.

numberOfRetries - number of retries to get a socket from the pool. This basically equates to number of seconds will wait to get client socket connection from pool before timing out. If max retries is reached, will cause a CannotConnectException to be thrown (whose cause will be SocketException saying how long it waited for socket connection from pool). The default is 30 (MAX_RETRIES)

numberOfCallRetries - number of retries for making invocation. This is unrelated to numberOfRetries in that when this comes into play is after it has already received a client socket connection from the pool. However, is possible that the socket connection timed out while waiting within the pool. Since not doing a connection check by default, will throw away the connection and try to get a new one. Will do this for whatever the numberOfCallRetries (which defaults to 3) is. However, when reaches numberOfCallsRetries - 2, will flush the entire connection pool under the assumption that all connections in the pool have timed out and are invalid and will start over by creating a new connection. If still fails, will throw MarshalException with the cause being the original SocketException.

clientSocketClass - specifies the fully qualified class name for the custom SocketWrapper implementation to use on the client. Note, will need to make sure this is marked as a client parameter (using the 'isParam' attribute). Making this change will not affect the marshaller/unmarshaller that is used, which may also be a requirement.

socket.check_connection - indicates if the invoker should try to check the connection before re-using it by sending a single byte ping from the client to the server and then back from the server. This config needs to be set on both client and server to work. This if false by default.

An example of locator uri for a socket invoker that has TCP_NODELAY set to false and the client's max pool size of 30 would be:

socket://test.somedomain.com:8084/?enableTcpNoDelay=false&maxPoolSize=30

To reiterate, these client configurations can only be set within the server side configuration and will not change during runtime.

5.4.5.1. How the Socket Invoker works

The Socket Invoker 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.

server

When the socket server invoker is started, it will create one, and only one, instance of java.net.ServerSocket. 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. 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, are stored in a pool. The accept thread will try to retreive 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 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. Prior to release 2.2.2.SP7, 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, and, in release 2.2.2.SP7, that is what it does. 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, as of release 2.2.2.SP8, 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, will return the still active socket connection to the pool. As more client invocations are made, is possible for the number of socket connections to reach the maximum allowed (which is controlled by 'clientMaxPoolSize' property). At this point, when the next client invocation is made, it will keep trying to get an available connection from the pool, waiting 1 second in between tries for up to maximum number of retries (which is controlled by the numberOfRetries property). If runs out of retries, will throw SocketException saying how long it waited to find available socket connection.

Once the socket client invoker goes get an available socket connection from the pool, are not out of the woods yet. There is still a possibility that the socket connection returned, while still appearing to be valid, has timed out while sitting in the pool. So if discover this while trying to make invocation, will throw it away and retry the whole process again. Will do this up to the number set by the numberOfCallRetries before throwing an exception. The trick here is that when get to numberOfCallRetries -2, will assume that any socket connection gotten from the pool will have timed out and will flush the pool all together so that the next retry will cause a new socket connection to be recreated. A typical scenario when this might occur is when have had a burst of client invocations and then a long period of inactivity.

Note. As of release 2.2.2.GA, the server side of the socket transport can capture the IP address of the client side of a TCP connection from client to server and make it available to application code on the client side. The address can be retrieved as follows:

        Client client = new Client(locator);
        ...
        InvocationResponse response = (InvocationResponse) client.invoke("$GET_CLIENT_LOCAL_ADDRESS$");
        InetAddress address = (InetAddress) response.getResult();
        

5.4.6. SSL Socket Invoker

Supports all the configuration attributes as the Socket Invoker. The main difference is that the SSL Socket Invoker uses an SSLServerSocket by default, created by an SSLServerSocketFactory. See section Socket factories and server socket factories for more information.

5.4.7. RMI Invoker

registryPort - the port on which to create the RMI registry. The default is 3455. This also needs to have the isParam attribute set to true.

Note. The RMI server invoker creates a socket factory and passes it to a client invoker along with the RMI stub, so the socket factory must be serializable. Therefore, if a socket factory is passed in to the server invoker by one of the methods discussed in section Socket factories and server socket factories, then the user is responsible for supplying a serializable socket factory.

5.4.8. SSL RMI Invoker

This is essentially identical to the RMI invoker, except that it creates SSL socket and server socket factories by default.

Note. The SSL RMI server invoker creates a socket factory and passes it to a client invoker along with the RMI stub, so the socket factory must be serializable. If the SSL RMI server invoker is allowed to create an SSLSocketFactory from SSL parameters, as discussed in section Socket factories and server socket factories, it will take care to create a serializable socket factory. However, if a socket factory is passed in to the server invoker (also discussed in section Socket factories and server socket factories), then the user is responsible for supplying a serializable socket factory. See sslrmi below for more information.

5.4.9. HTTP Invoker

The HTTP server invoker implementation is based on the Apache Tomcat connector components which support GET, POST, HEAD, OPTIONS, and HEAD method types and keep-alive. Therefore, most any configuration allowed for Tomcat can be configured for the remoting HTTP server invoker. For more information on the configuration attributes available for the Tomcat connectors, please refer to http://tomcat.apache.org/tomcat-5.5-doc/config/http.html. http://tomcat.apache.org/tomcat-5.5-doc/config/http.html So for example, if wanted to set the maximum number of threads to be used to accept incoming http requests, would use the 'maxThreads' attribute. The only exception when should use remoting configuration over the Tomcat configuration is for attribute 'address' (use serverBindAddress instead) and attribute 'port' (use serverBindPort instead).

Note: The http invoker no longer has the configuration attributes 'maxNumThreadsHTTP' or 'HTTPThreadPool' as thread pooling is now handled within the Tomcat connectors, which does not expose external API for setting these.

Since the remoting HTTP server invoker implementation is using Tomcat connectors, is possible to swap out the Tomcat protocol implementations being used. By default, the protocol being used is org.apache.coyote.http11.Http11Protocol. However, it is possible to switch to use the org.apache.coyote.http11.Http11AprProtocol protocol, which is based on the Apache Portable Runtime (see http://tomcat.apache.org/tomcat-5.5-doc/apr.html and http://apr.apache.org/ for more details). If want to use the APR implementation, simply put the tcnative-1.dll (or tcnative-1.so) on the system path so can be loaded. The APR native binaries can be found at http://tomcat.heanet.ie.

Note: There is a bug with release 1.1.1 of APR where get an error upon shutting down (see JBREM-277 for more information). This does not impact anything while running, but is still an issue when shutting down (as upon starting up again, can get major problems). This should be fixed in a later release of APR so can just replace the 1.1.1 version of tcnative-1.dll with the new one.

Client request headers

The HTTP Invoker allows for some of the properties to be passed as request headers from client caller. The following are possible http headers and what they mean:

sessionId - is the remoting session id to identify the client caller. If this is not passed, the HTTP server invoker will try to create a session id based on information that is passed. Note, this means if the sessionId is not passed as part of the header, there is no guarantee that the sessionId supplied to the invocation handler will always indicate the request from the same client.

subsystem - the subsystem to call upon (which invoker handler to call upon). If there is more than one handler per Connector, this will need to be set (otherwise will just use the only one available).

These request headers are set automatically when using a remoting client, but if using another client to send request to the HTTP server invoker, may want to add these headers.

5.4.10. HTTPS Invoker

Supports all the configuration attributes as the HTTP Invoker, plus the following:

SSLImplementation - Sets the Tomcat SSLImplementation to use. This should always be org.jboss.remoting.transport.coyote.ssl.RemotingSSLImplementation.

The main difference with the HTTP invoker is that the HTTPS Invoker uses an SSLServerSocket by default, created by an SSLServerSocketFactory. See section Socket factories and server socket factories for more information.

5.4.11. HTTP(S) Client Invoker - proxy and basic authentication

This section covers configuration specific to the HTTP Client Invoker only and is NOT related to HTTP(S) invoker configuration on the server side (via service xml).

proxy

There are a few ways in which to enable http proxy using the HTTP client invoker. The first is simply to add the following properties to the metadata Map passed on the Client's invoke() method: http.proxyHost and http.proxyPort.

An example would be:

               Map metadata = new HashMap();
               ...

               // proxy info
               metadata.put("http.proxyHost", "ginger");
               metadata.put("http.proxyPort", "80");

               ...

               response = client.invoke(payload, metadata);
            

The http.proxyPort property is not required and if not present, will use default of 80. Note: setting the proxy config in this way can ONLY be done if using JDK 1.5 or higher.

The other way to enable use of an http proxy server from the HTTP client invoker is to set the following system properties (either via System.setProperty() method call or via JVM arguments): http.proxyHost, http.proxyPort, and proxySet.

An example would be setting the following JVM arguments:

-Dhttp.proxyHost=ginger -Dhttp.proxyPort=80 -DproxySet=true

Note: when testing with Apache 2.0.48 (mod_proxy and mod_proxy_http), all of the properties above were required.

Setting the system properties can be used for JDK 1.4 and higher. However, will not be able to specify proxy server per remoting client if use system properties..

Basic authentication - direct and via proxy

The HTTP client invoker also has support for BASIC authentication for both proxied and non-proxied invocations. For proxied invocations, the following properties need to be set: http.proxy.username and http.proxy.password.

For non-proxied invocations, the following properties need to be set: http.basic.username and http.basic.password.

For setting either proxied or non-proxied properties, can be done via the metadata map or system properties (see setting proxy properties above for how to). However, for authent