Liberty Collectives: Routing MBean Operations

Learn how to route any MBeanServerConnection operation and also file transfer to/from any member of a Liberty Collective by using only the collective controller!

WebSphere Application Server V8.5.5 Liberty Profile introduces a new MBean, com.ibm.websphere.collective.controller.RoutingContextMBean. This allows clients of a Liberty collective to route any MBeanServerConnection operation through the controller into any member of the collective.

What are the benefits of routing through the controller versus directly accessing the member? The client does not need to know or provide any security credentials for the member. The security authentication is done by the controller on behalf of the client, thus providing a seamless bridge of MBean communication between the client and the member.

Furthermore, when used in combination with the FileTransferMBean the client is capable of routing files to/from an offline Liberty instance, or a registered host machine that does not even have a Liberty installation. We’ll go through some useful examples of such usage.

Let’s first take a look at the interface provided by this new MBean:

void assignServerContext(String hostName, String wlpUserDir, String serverName);
void assignHostContext(String hostName);

As we can see, it’s a very simple interface with only 2 methods. Its complete javadoc and and its interface file (if you want to create a MBeanProxy object for it) can be found in wlp\dev\api\ibm\javadoc\com.ibm.websphere.appserver.api.collectiveController_1.0.0-javadoc.zip and wlp\dev\api\ibm\com.ibm.websphere.appserver.api.collectiveController_1.0.0.jar.

The method assignServerContext will route any subsequent MBeanServerConnection invocations to the target member, which is uniquely identified by the 3-tuple: host name, user directory and server name.

For all MBeanServerConnection methods that are invoked after a server-level context is assigned, the target member must have its status as “running” for the operation to take effect.  An exception to this rule is the FileTransferMBean, which we will show an example later on.

Let’s see look at some sample code that retrieves the current mbean from the controller, then sets a server-level routing context and performs the exact same query, but this time it queries the target member through the proxy controller.

Example 1 : Simple MBean Routing

Retrieve an MBeanServerConnection using Liberty’s JMX REST Connector as explained in Creating remote JMX connections in Liberty.


MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();

System.out.println("Before routing: " + mbsc.getMBeanCount());

//Set routing context
ObjectName routingName = new ObjectName("WebSphere:feature=collectiveController,type=RoutingContext,name=RoutingContext");
String[] routingSignature = new String[]{"java.lang.String", "java.lang.String", "java.lang.String"};
Object[] routingParams = new String[]{"myhost.ibm.com", "D:/Demo_Desktop/wlp/usr", "member"};

mbsc.invoke(routingName, "assignServerContext", routingParams, routingSignature);

System.out.println("After routing: " + mbsc.getMBeanCount());

All other operations on the MBeanServerConnection, such as setting up MBean->Listener notifications, can be called in the same exact same way. It is important to note that proper configuration (if any) for specific MBeans needs to be set up on the target member that is receiving the proxied call. So, for example, if the client is routing a FileServiceMXBean invocation that relies on a certain writeDir to be setup, then this writeDir must be configured on the target member (instead of the controller).

As previously mentioned, FileTransferMBean invocations in a server-level routing context do not require the target member to be running at all! The file transfer technology provided by the controller is capable of transfering files in and out of the target by just using its self-contained components and information cached on the repository. Client invoking the FileTransferMBean can also still use Liberty variables, such as ${server.config.dir}, when routing files to/from an offline member because the controller is able to resolve these variables by querying certain nodes on its internal repository.

Let’s look at an example where we set the routing context to a collective member and then perform some file transfer operations on it, while taking advantage of the abilitity to use Liberty variables for our remote paths.

Example 2: Routing files to a member (could be online or offline)

Retrieve an MBeanServerConnection using Liberty’s JMX REST Connector as explained in Creating remote JMX connections in Liberty.


MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();

//Set routing context
ObjectName routingName = new ObjectName("WebSphere:feature=collectiveController,type=RoutingContext,name=RoutingContext");
String[] routingSignature = new String[]{"java.lang.String", "java.lang.String", "java.lang.String"};
Object[] routingParams = new String[]{"myhost.ibm.com", "D:/Demo_Desktop/wlp/usr", "member"};

mbsc.invoke(routingName, "assignServerContext", routingParams, routingSignature);

ObjectName objName = new ObjectName("WebSphere:feature=restConnector,type=FileTransfer,name=FileTransfer");

//Download the configuration file
String[] signature = new String[]{"java.lang.String", "java.lang.String"};
Object[] params = new String[]{"${server.output.dir}/server.xml", "/Users/Shared/Demo/member_server.xml"};
mbsc.invoke(objName, "downloadFile", params, signature);

System.out.println("Download finished.");

//Delete an application
signature = new String[]{"java.lang.String"};
params = new String[]{"${server.output.dir}/dropins/30ExampleEAR.ear"};
mbsc.invoke(objName, "deleteFile", params, signature);

System.out.println("Delete finished.");

Now we move on to the second method exposed by RoutingContextMBean, assignHostContext. It is used when clients want to route a FileTransferMBean invocation to a registered host machine that may not have any target member inside of it. This is called host-level routing, and for similar reasons explained above this is only applicable to file transfer operations. If the client sets a host-level routing, all file transfer operations will be routed to the host while all other MBeanServerConnection invocations will go just to the controller (not routed). Please note that setting a host-level routing context overrides any previously set server-level routing contexts, and vice-versa.

During host-level file transfer routing the controller queries the hostWriteList and hostReadList that was set up for that registered host to determine if it should proceed or not with the current request. The hostWriteList/hostReadList is the host-level equivalent of the writeDir/readDir that is set up at the server-level (in server.xml).

Let’s look at an example where we set up the host-level context to point to a registered host on the collective that only has java installed and no current Liberty instance. We will use the “expandOnCompletion” flag on the uploadFile operation to automatically expand a new Liberty archive (which has been “minified” to only contain the bundles necessary to support servlets). After the upload + extraction is done we will be able to start/stop/etc this new Liberty instance through the controller right away! It’s a nice way to dynamically (or manually) deploy new collective members.

Example 3: Using host-level upload to expand new Liberty instances on empty host

Retrieve an MBeanServerConnection using Liberty’s JMX REST Connector as explained in Creating remote JMX connections in Liberty.


MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();

//Set routing context
ObjectName routingName = new ObjectName("WebSphere:feature=collectiveController,type=RoutingContext,name=RoutingContext");
String[] routingSignature = new String[]{"java.lang.String"};
Object[] routingParams = new String[]{"myhost.ibm.com"};

mbsc.invoke(routingName, "assignHostContext", routingParams, routingSignature);

ObjectName objName = new ObjectName("WebSphere:feature=restConnector,type=FileTransfer,name=FileTransfer");

//Upload and extract
String[] signature = new String[]{"java.lang.String","java.lang.String", "java.lang.Boolean", };

Object[] params = new Object[]{"/Users/Shared/Demo/wlp_servlet.zip", "D:/Demo_Desktop/homeDir/wlp_servlet.zip", true};

long startTime = System.nanoTime();
mbsc.invoke(objName, "uploadFile", params, signature);
long endTime = System.nanoTime();
double seconds = ((double) (endTime - startTime) ) / 1000000000.0;

System.out.println("Upload finished. It took " + seconds + " seconds");