Enhancing xsadmin for WebSphere eXtreme Scale

IBM® WebSphere® eXtreme Scale V6.1.0.3 includes a tool called xsadmin, a Java™ application that interacts with WebSphere eXtreme Scale processes and displays information regarding the grid runtime, such as shard placement, available containers, and so on. This article discusses how you can enhance xsadmin to provide new functionality and better consumability for your eXtreme Scale deployment. This content is part of the IBM WebSphere Developer Technical Journal.

John Pape, WebSphere Application Server SWAT Team, IBM

Author photoJohn Pape currently works with the WebSphere SWAT Team and focuses on crit-sit support for clients who utilize WebSphere Application Server, WebSphere Portal Server, and WebSphere Extended Deployment. This role requires attention to detail as well and maintaining a “think-out-of-the-box” innovative mindset, all the while assuring IBM customers get the best support possible! John also has a development background in Domino/Lotus Notes, Microsoft C#, Java, C++, Perl, and python. John is a social media champion within IBM and an avid Linux user.

developerWorks Contributing author

10 December 2008

Also available in Chinese Japanese


IBM WebSphere eXtreme Scale can be deployed in two ways:

  • Into an existing WebSphere Application Server Network Deployment instance by augmenting a WebSphere profile.
  • Into a J2SE™ environment with no WebSphere Application Server presence.

In the first scenario, system monitoring and server administration is accomplished by the administrative components of WebSphere Application Server, but in both the standalone environment and WebSphere-managed environment, the view of the grids’ internals is only visible through the xsadmin application.

The xsadmin application is not part of the WebSphere eXtreme Scale V6.1.0.3 product code; rather, it is included as a sample application. Nearly everything that xsadmin provides can be accomplished by interacting with JMX™ MBean instances contained in the eXtreme Scale processes.

Out of the box, xsadmin enables you to view the current placement of grid shards (primary and replicas) amongst the configured containers, see which containers are available, and see which host the containers are running on. With this article, you will be able to:

  • Rework the command line arguments code to enable a more logical flow of required and non-required arguments.
  • Expose the -l argument used to easily browse available grid instances and associated map sets.
  • Add and expose the -? argument to complement the existing help argument –h.
  • Add the -catserv argument that will be used to display information regarding catalog servers in the environment.
  • Add the -cg argument that will be used to display information regarding the current core group run time state alone, with quorum state, and heartbeat interval settings.

Before you begin making changes to xsadmin, it will be helpful to review what it already includes.

The xsadmin sample application

This article assumes you will be using the IBM Rational® Software Development platform, specifically IBM Rational Application Developer V7.0.0.7, to update the sample application. Since the xsadmin application is a simple Java application, you can use any IDE you wish. However, you must be able to include the objectgrid.jar file from WebSphere eXtreme Scale V6.1.0.3, which contains the necessary compile-time classes that you will need to put into your build path for the application to compile and test correctly. Consult the documentation for your development environment for details on how to insert the objectgrid.jar file into the application’s build path.

The xsadmin application consists of a single package named com.ibm.websphere.samples.objectgrid.admin. Contained inside that package are two class files, JMXProxy and OGAdmin. Our efforts will focus on the OGAdmin class; we will make reference to and use the JMXProxy class, but for the purpose of this article you will not be working with the source code.

The OGAdmin class contains several inner classes:

  • Options
  • CmdLineParser
  • Comp

The focus here is on the Options and CmdLineParser inner classes, along with the containing OGAdmin class.

The Options class exists as a simple Java bean but without the getter and setter methods typically seen on Java beans. The CmdLineParser does exactly what its name implies: it parses the command line arguments passed into the xsadmin program; more specifically, it parses the argument string passed into the main() method of OGAdmin. An “unspoken contract” between the Options and CmdLineParser classes dictates that the CmdLineParser logic must also know about all the potential flags to be set on the Options class; this is “unspoken” in the sense that there is no Java interface defined to make sure this happens.

When xsadmin is run:

  • All the arguments are passed into the main() method of the OGAdmin class.
  • The main method then proceeds to delegate the parsing of the argument to a CmdLineParser object, which then returns an Options object.
  • This Options object is then evaluated for certain criteria that will dictate what logic is run on the OGAdmin class, and therefore what output is seen at the console where the application was invoked.
  • When invoked with no options, a tool will typically print the contents of its syntactical help, which will can assist you in obtaining the grid runtime information you might need.

Now, let’s look at how you can enhance the sample application.

Enhancing the sample

  1. To obtain the source code for the xsadmin application, you simply need to move the xsadmin.jar file from the OBJECTGRID_HOME\samples directory of your WebSphere eXtreme Scale installation to a location from which the file can be imported into your IBM Rational Application Developer workspace. Once the file has been relocated, create a new Java project in Rational Application Developer named XSAdmin, and then import the file by right-clicking on the XSAdmin project in the Package Explorer view of the Java perspective, and select Import. The panel shown in Figure 1 should then display.
    Figure 1. Select the import source
    Figure 1. Select the import source
  2. Select the Archive File import type from the list of import sources (or type Archive File into the filter box above the tree view) and click Next. Figure 2 should display.
    Figure 2. Select the archive to import
    Figure 2. Select the archive to import
  3. Click the Browse button beside the From archive file field and select the xsadmin.jar file. (You can also type the file name if you know the path). Figure 2 shows the path to xsadmin.jar file as a UNC path to another Windows® machine named "alaric." Also, the tree view is expanded on the left side of the dialog box so that you can see the entire folder structure of the archive. Upon clicking a directory in the tree view, the list view on the right side of the dialog box displays the files contained in that directory. Click Finish to complete the import operation.
  4. Upon completion of the import, the Package Explorer view should look like Figure 3.
    Figure 3. Import successfully completed
    Figure 3. Import successfully completed

Now that you have the xsadmin sample code imported into a new Java project in your Rational Application Developer workspace, you can begin to modify the code to suit your requirements.

Changing the command line requirements

The first item that you will change will be the command line argument parsing. As written, the xsadmin application always requires the –g and –m arguments, which are the grid name and the map set name, respectively. This is fine for the majority of invocation of this application, but as you will see shortly, these arguments should not be required to utilize the –l argument, which provides a listing of available grids and associated map sets, and is equivalent to a browse function. Therefore, let’s take care of that first. The process to alter the logic to make the –g and –m arguments not required is two-fold:

You must alter logic in the CmdLineParser class, which is contained in the parseArguments() method. The code, as written, looks like Listing 1.

Listing 1. parseArguments() before modification
if (options.gridName == null || options.mapsetName == null) {
     this.validate = false;
} else {
     this.validate = true;

You need to bypass this logic to effectively always assure that the validate flag is set to true; higher up in the class, it is initialized with a default value of false. By commenting out the code shown in Listing 2, you can be assured that the validate flag will always be false (you can remove it altogether, as an option).

Listing 2. parseArguments() after modifiation
             * Removing these lines in this manner allows for the -g and -m arguments 
		 * to be bypassed, thus allowing bypassed, thus allowing a more logical
             * application of the -l argument like so : xsadmin -l -containers
//            if (options.gridName == null || options.mapsetName == null) {
//                this.validate = false;
//            } else {
                this.validate = true;
//         }

Exposing the grid/map browsing argument

Although the –l option is not explicitly revealed as a viable option in the xsadmin help output, the code is in place to service the option. Prior to your modifying the parseArguments() method above, you could not have used it effectively unless you provided dummy values for the –g and –m arguments (that is, rather than:

xsadmin –ch myhost –p 1099 –l

you would have had to run:

xsadmin –ch myhost –p 1099 –g xxx –m xxx -l


In order to adequately expose the –l option, you need to take a few steps:

  1. Alter the logic in the main() method of the OGAdmin class to make it acceptable to provide the –l argument by itself.
  2. Alter the help content to include the new option.

For the first step, let’s take a look at a piece of the main() method, shown in Listing 3.

Listing 3 main() method code segment
if (!(o.showContainers || o.showHosts || o.showPrimaries || o.showUnAssigned)) {
      // System.exit(-1);

This section of code checks the options derived from the command line arguments and stops execution if it does not find the –containers, -primaries, -unassigned, or –hosts options present. Since you intend on letting the user specify the –l argument alone, you we need to alter this code to enable the –l argument to be used in that manner.

Listing 4. shows modifications to the main() method. A condition has been added to the existing if statement that will not invoke the printHelp() method (the code responsible for advising the user to use one of the –containers, -primaries, -unassigned, or –hosts arguments) if the listOG flag on the Options object (“o” in this example) is "true." This is exactly what you want to happen.

Listing 4. main() snippet after modification
* Added !o.listOG to account for the condition of a user wanting to just see the 
* list of grids and associated mapsets - who wants to specify the other options for 
* a listing????
if (!(o.showContainers || o.showHosts || o.showPrimaries || o.showUnAssigned) 
	&& !o.listOG) {
   // System.exit(-1);

If you look a bit further down in the source code, you will see the code responsible for handling the printing of the grid names and map sets (Listing 5).

Listing 5. Logic for printing grids/map sets
if (o.listOG) {

After compiling this code, you should be ready to run a sample test. To do this in Rational Application Developer, click the Run icon in the toolbar at the top of the panel, and select Run As => Java Application (Figure 4).

Figure 4. Run the application
Figure 4. Run the application

On the Select Java Application dialog (Figure 5), specify the main class to be used as the application by entering OGAdmin. Select the class and click OK to continue.

Figure 5. Choose the OGAdmin class to be run as a Java application
Figure 5. Choose the OGAdmin class to be run as a Java application

Since you specified no command line arguments, the help content should be displayed in the console view after the application runs. The result should look like that shown in Listing 6.

You will notice that the help text is still unchanged, so let’s go take care of that. The help text you want to change originates from the printHelp() method of the CmdLineParser class. You simply need to insert a line in an appropriate place to explain the –l argument and its usage pattern. Listing 6 shows the area of the printHelp() method where you will insert your line of code. The linie of caode that was added appears in bold text.

Listing 6. modified printHelp() method
static void printHelp() {
            System.out.println("The following arguments are required:");
            System.out.println(" " + gridNameArg + " \'ObjectGrid name\'"); // 1
            System.out.println(" " + mapsetNameArg + " \'Mapset name'"); // 2
            System.out.println("The following arguments are optional");
            System.out.println(" " + listOGArg + " \'View a list of available grids 
		and associated mapsets\'");
            System.out.println(" " + jmxHostArg + " \'Catalog service JMX hostname, 
		default value=localhost\'"); // 1
            System.out.println(" " + jmxPortArg + " \'Catalog service JMX port. default: 
		1099 or 9809 for DMGR host\'"); // 2
            System.out.println(" " + dmgrArg + " \'Specify this flag, if connecting to 
		WebSphere DMGR host.\'"); // 14
            System.out.println("The following arguments are required if security is 
            System.out.println(" " + userArg + " \'Username\'");
            System.out.println(" " + passArg + " \'Password\'");// 1

            System.out.println("The following arguments are required if SSL is enabled");
            System.out.println(" " + sslArg + " \'Enables SSL authentication\'");
            System.out.println(" " + trustPathArg + " \'Absolute path to trust store\'");
            System.out.println(" " + trustPassArg + " \'Trust store password\'");
            System.out.println(" " + trustTypeArg + " \'Trust store type\'");

<code continues>

The listOGArg variable evaluates to the –l string. You have now sufficiently exposed the –l argument to the user by adding help information, as well as enabled the argument to be given at the command line with no other required arguments.

Next, you will create some new functionality: you will add a feature to enable the user to see clustered catalog server information.

Adding features: -catserv

The xsadmin sample application already provides information regarding the placement of shards and the location of servers (that is, what host they are running on), but it does not provide any details on the status and whereabouts of catalog servers. While you must know at least one catalog server end point in order to run the xsadmin tool (because the JMX interface runs in the catalog servers), you might not be so sure of the location of the other catalog servers that make up the catalog server cluster. You will add this functionality to the xsadmin sample application.

First, you need to introduce the new flags for the argument that will be used to represent the catalog server option. In this case, you’ll use the string value -catserv. You will need to create this variable on the Options and CmdLineParser classes.

To add the variable to the Options class, simply add this line:

boolean catServer;

to the list of class-level variables already defined in the class (similar to trustType, password, port, and showContainers). Second, you need to define a class-level variable on the CmdLineParser class as well that defines the actual string value to represent the option. You can do this by adding this line:

final static String catServer = "-catserv";

to the list of string variables already defined on the CmdLineParser class. Now that the CmdLineParser and the Options classes are now instrumented for the new argument, you need to provide some logic in the OGAdmin class that will recognize the argument and take the appropriate action.

Remember that you had to alter the logic in the main() method a bit in the previous section in order to enable the –l argument to be passed in with no other required arguments. You will need to take a similar action again to enable the new –catserv argument to be passed in with no other required arguments. The area of code you are going to alter is the same area displayed in Listing 4. Listing 7 shows the new addition in bold text.

Listing 7. newly modified main() method
* Added !o.listOG to account for the condition of a user wanting to just see the 
* list of grids and associated mapsets - who wants to specify the other options 
* for a listing????
if (!(o.showContainers || o.showHosts || o.showPrimaries || o.showUnAssigned) && 
	!o.listOG && !o.catServer) {
        // System.exit(-1);

With the change made in Listing 7, you can now pass in the –catserv argument without having to put any other argument on the command line.

Next, you need to provide some logic that will do something when this argument is passed into the application. Listing 8 shows the area of the main() method (of OGAdmin) you’re going to look at now.

Listing 8. Logic in the main() method of OGAdmin
* code that responds to -l argument - prints out grids and mapsets defined!!
if (o.listOG) {

// Show containers
if (o.showContainers) {
    printContainers(jmxProxy, o);
} else if (o.showPrimaries) {
    printPrimaries(jmxProxy, o);
} else if (o.showUnAssigned) {
    printUnassigned(jmxProxy, o);
} else if (o.showHosts) {
    printHosts(jmxProxy, o);
} else {

The code at the top of Listing 8 is the same code discussed in Listing 5 and provides the functionality for the –l argument. The next section of code determines whether the –containers, -primaries, -unassigned, or –hosts arguments have been passed into the application, and then delegates control to the appropriate method for processing by obtaining the data and formatting it for output to the console. You will add your logic for the –catserv argument right under the code shown in Listing 9.

Listing 9. Logic for -catserv argument detection
//show catserver info
if (o.catServer){

Notice that you have made reference to a method named printCatalogServers() that takes a variable named "catalogServerConnection." This method does not yet exist because you need to create it.

Create the new method and use the source code shown in Listing 10. The variable catalogServerConnection is defined a bit further up in the source code as a type of MBeanServerConnection, and is used to establish a JMX connection to the catalog server by using the JMX APIs included with Java 5 SDKs. Your printCatalogServers() method will use this connection object to obtain information regarding the catalog servers defined in the environment.

Listing 10. printCatalogServers() method
* Prints all of the catalog servers known by the catalog server this tool is run against.
private static void printCatalogServers(MBeanServerConnection catServerConn) {
	//make connection get ObjectGridServer info on catalog server
try {
	  Set<ObjectInstance> s = catServerConn.queryMBeans(new ObjectName
		("com.ibm.websphere.objectgrid:type=ObjectGridServer,*"), null);
	  Iterator<ObjectInstance> i = s.iterator();
	  System.out.println("Listing catalog servers known by this process:");
	  while (i.hasNext()){
		DynamicServerMBean dsmb = (DynamicServerMBean)JMXProxy.getProxy
		   (catServerConn, i.next().getObjectName(), DynamicServerMBean.class);
		System.out.println("Catalog Server: " + dsmb.getServerName());
		System.out.println("Running on host: " + dsmb.getHostName() + "\n");
	} catch (MalformedObjectNameException e) {
	} catch (NullPointerException e) {
	} catch (IOException e) {

The printCatalogServers() method uses the JMX connection to query the system for MBeans of the type ObjectGridServer. This type of MBean is used to represent catalog servers in a dynamic environment and container servers in a static environment (unlike previous versions of ObjectGrid). Once this MBean is located, the code then casts the MBean into a proxy object by using the JMXProxy class from the xsadmin sample application. By iterating through the list of objects returned from the JMX query, the code prints out a nicely formatted list of catalog servers by name and includes the hostname where they are running. Further information could have been added here by including the output from several of the other methods, exposed via the DynamicServerMBean object (part of the code included with the objectgrid.jar file you included in the build path).

And that’s it for the –catserv argument! Run the xsadmin application again and confirm that you have no errors. The output should be similar to that shown in Listing 11. Be sure to add in the –catserv argument to the run time definition of the application, as shown in Figure 6.

Listing 11. Successful use of the -catserv argument
Connecting to Catalog service at alaric:1099
Listing catalog servers known by this process:
Catalog Server: cat1
Running on host: alaric.mshome.net

Figure 6 Add the -catserv argument into Rational Application Developer
Figure 6 Add the -catserv argument into Rational Application Developer

Next, we’ll move on to the last piece of new functionality: the –cg feature.

Adding features: -cg

You’re almost done with your enhancements to the xsadmin sample application. For your last enhancement, you will introduce another function in the same manner as above. The –cg argument will be used to provide the user with information regarding the current state of the core groups (leaders and members). Incidentally, if zones are configured, you will be able to see the separation of the containers in the zones, because zone boundaries are core group boundaries as well. Most of the steps for this addition will be the same as before, so we’ll skim over the details.

First, add a new variable to the Options class. For this example, call it coreGroup and define it on the class with this line of code:

boolean coreGroup;

As for the CmdLineParser class, add this line to match:

final static String coreGroups = "-cg";

See the Adding features: -catserv section for detailed instructions.

After you have added the new variables to your classes, add the handler code to the main() method of the OGAdmin class. You will also need to make a small adjustment to the code shown in Listing 7. The newly inserted code appears in bold in Listing 12.

Listing 12. Add -cg to the list of standalone arguments
if (!(o.showContainers || o.showHosts || o.showPrimaries || o.showUnAssigned) 
	&& !o.listOG && !o.catServer && !o.coreGroup) {
    // System.exit(-1);

As with the catServer variable, you can specify the –cg argument at the command line without any other required arguments.

The block of code shown in Listing 13 detects the presence of the –cg argument and delegates the processing request to the appropriate method, which in this case is printCoreGroupInformation().

Listing 13. Detecting the -cg argument
//show core group info
if (o.coreGroup){

The printCoreGroupInformation() method differs a bit from the printCatalogServers() method you created earlier. The printCatalogServers() method needed the JMX connection object to be passed into it in order to query for the server MBean. In printCoreGroupInformation(), the core group information is provided by the PlacementServiceMBean object represented by the jmxProxy variable; the application casts a JMX object into a PlacementServiceMBean instance.

Your last step is to include the code for the new printCoreGroupInformation() method in the application. You can use the code shown in Listing 14.

Listing 14. printCoreGroupInformation() method
private static void printCoreGroupInformation(PlacementServiceMBean psmb) {
System.out.println("Printing core group information:");
try {
StringBuffer xml = new StringBuffer();
	xml.append("<objectgrid>\n"); //added root element to make SAX parser happy
	xml.append(	psmb.getCoreGroups());
	xml.append("</objectgrid>\n"); // added root element to make SAX parser happy
	InputSource is = new InputSource(new StringReader(xml.toString()));
	DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	factory.setNamespaceAware(true); // never forget this!
	DocumentBuilder builder = factory.newDocumentBuilder();
	Document doc = builder.parse(is);
	XPath xPath = XPathFactory.newInstance().newXPath();
	//get the core group blocks
	NodeList nodes = (NodeList) xPath.evaluate("coreGroup", doc.getFirstChild(), 
	Node node = null; //a single core group block
	Node leaderNode = null;
	Node memberNode = null;
	for (int i=0;i<nodes.getLength(); i++){
		node = nodes.item(i);
		System.out.println("\nCore Group Name  : " + node.getAttributes().
		//get listing for coreGroupLeader elements
		NodeList leaderNodes = (NodeList)xPath.evaluate("coreGroupLeader", node, 
		for (int j=0;j<leaderNodes.getLength();j++){
			leaderNode = leaderNodes.item(j);
			System.out.println("\tLeader: " + leaderNode.getAttributes().
				getNamedItem("serverName").getTextContent() + "(" +
	getTextContent() + ")");
		//get listing for coreGroupMember elements
		NodeList memberNodes = (NodeList)xPath.evaluate("coreGroupMember", node, 
		for (int k=0;k<memberNodes.getLength();k++){
			memberNode = memberNodes.item(k);
System.out.println("\tMember: " + memberNode.getAttributes().
			getNamedItem("serverName").getTextContent() + "(" +
			getTextContent() + ")");
} catch (ParserConfigurationException e) {
} catch (SAXException e) {
} catch (IOException e) {
} catch (XPathExpressionException e) {

int qStat = psmb.getQuorumActivationStatus();
switch (qStat){
   case 0:
	System.out.println("Quorum Activation Status:\n\tQuorum is disabled"); 
   case 1:
	System.out.println("Quorum Activation Status:\n\tQuorum is enabled:normal"); 
   case 2:
	System.out.println("Quorum Activation Status:\n\tQuorum is enabled:waiting 
			for quorum"); break;
   case 3:
	System.out.println("Quorum Activation Status:\n\tQuorum is overridden"); 
   case 4: 
	System.out.println("Quorum Activation Status:\n\tServer data may be 
			inconsistant"); break;
int hbfl = psmb.getHeartBeatFrequencyLevel();
switch (hbfl){
   case -1:
	System.out.println("Heartbeat Frequency Level:\n\tAgressive"); break;
   case 0:
	System.out.println("Heartbeat Frequency Level:\n\tTypical (default) "); 
   case 1:	
	System.out.println("Heartbeat Frequency Level:\n\tRelaxed "); break;

The printCoreGroupInformation() method is the most complex method you have added to the application. The first bold line in the example invokes the getCoreGroups() method on the PlacementServiceMBean instance. The getCoreGroups() method returns its information back as an XML formatted String object. The code following the first bold line processes the XML string by using the Java SAXParser object to turn the String into a Document object that can be searched. The code also creates an XPath object that will facilitate making XPath queries on the Document object.

The second and third bold lines retrieve current state values for the quorum service and the heartbeat frequency levels. Both blocks of code evaluate an int value using a switch statement that results in a human-readable string value printed to the console.

After saving all the code and running the application -- using the –cg argument only this time -- you should see output similar to that shown in Listing 15.

Listing 15. Output from -cg argument
Connecting to Catalog service at alaric:1099
Printing core group information:

Core Group Name  : Zone_AlphaCG0
	Leader: server1(alaric.mshome.net)

Core Group Name  : CoreGroup_0 CoreGroup_1
	Leader: cat1(alaric.mshome.net)

Core Group Name  : Zone_BravoCG0
	Leader: server2(alaric.mshome.net)
Quorum Activation Status:
	Quorum is enabled:normal
Heartbeat Frequency Level:
	Typical (default) 


Through an enhancement to the xsadmin sample application you have learned how to work with the JMX interfaces of IBM WebSphere eXtreme Scale. You have also gained some insight into the basic mechanisms used to process and parse command line arguments in the application. After completing these enhancements you should be comfortable enough with the sample application to continue customizing it to your own specifications, or perhaps even “webify” the application and make it available as a J2EE® Web application!



developerWorks: Sign in

Required fields are indicated with an asterisk (*).

Need an IBM ID?
Forgot your IBM ID?

Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.


All information submitted is secure.

Dig deeper into WebSphere on developerWorks

ArticleTitle=Enhancing xsadmin for WebSphere eXtreme Scale