Create a custom administrative client to simplify system administration in WebSphere Application Server V8.5

Using the Admin Command Framework offerings in WebSphere Application Server V8.5

The Admin Command Framework (ACF) in IBM WebSphere Application Server V8.5 provides user friendly, task-oriented commands for performing administrative tasks. Because it’s a framework, all commands follows the same syntax and are easy to use. With these commands, WebSphere Application Server offers you the ability to perform administrative tasks for configuration, operations, and other environmental functions through JMX (Java Management Extensions) APIs that you can use to create a custom administrative client best suited for your environment.

Intended primarily as a reference guide, this article will help you utilize the command framework offerings in an administrative client, ultimately simplifying the details related to configuration topology, schema, directory structure, and other operational specifics that is usually required knowledge when using wsadmin commands.

This article explains how you can use a custom JMX client to invoke different types of ACF commands and command variations, including how to invoke:

Some setup is required, and so the next section provides some information and guidance to help you get started.

Preparing to use commands

One basic thing you should know is that ACF commands are categorized as admin commands and task commands:

  • An admin command is the base command type. All ACF commands are of type admin.
  • Task commands are extensions of the admin command. A task command implements complex admininistrative operations in one or more command steps.
  • The steps implemented by a task command can be of two kinds:
    • A command step is simply an admin command that is executed as part of a task command.
    • A table step takes input parameters in the form of a table, with multiple rows and columns. Each parameter in a table step represents a column. Each set of values assigned to step parameters represent one row. Multiple sets of parameter values can be assigned to form a table with many rows.

Certain admin and task commands are asynchronous; the results of executing these commands will be emitted through command notifications. AsyncCommandClient is a helper class provided by ACF to wrap the asynchronous command to make it behave as synchronous. This enables the client to have a single implementation for both synchronous and asynchronous commands.

This article discusses both asynchronous and synchronous commands and uses AsyncCommandClient to process and execute both types of commands.

There is a level of setup required before you can begin to use ACF commands in your WebSphere Application Server environment. You need to:

  1. Create AdminClient

    To invoke the ACF commands on the server, the JMX client needs to establish a connection with the server using the AdminClient interface provided by WebSphere Application Server (Listing 1).

    Listing 1
    Properties props = new Properties();
    props.setProperty(AdminClient.CONNECTOR_HOST, host);
    props.setProperty(AdminClient.CONNECTOR_PORT, port);
    try {
    	this.adminClient = AdminClientFactory.createAdminClient(props);
    } catch (ConnectorException e) {
    	throw e;
  2. Create a session and ConfigService

    A session will be required to work on the configuration data, and ConfigService will be required to save the configuration changes made in the session (Listing 2).

    Listing 2
    this.session = new Session();
    this.cfgService = new ConfigServiceProxy(adminClient);
  3. Create CommandManager

    In order to manipulate the commands on the client side, and for the command to invoke the operation on the server, the client needs a command manager. The command manager provides the ability to query for the commands and their metadata, and to create the command on the client (Listing 3).

    Listing 3
    this.cmdMgr = CommandMgr.getCommandMgr(adminClient);

    CommandManager will take the AdminClient that was created above as input and will register it with its instance. All further operations — such as querying for a command and invoking the command operation on the server — will be done using the AdminClient registered with the CommandManager on the server to which the AdminClient connection has been established.

Executing a simple admin command

The first example of a simple admin command uses the listNodes command, which lists the nodes in a WebSphere Application Server cell domain. The listNodes command is not asynchronous and does not take any parameters as input. To execute this command, you:

  1. Create the command

    The command has to be created using the command manager that was initially instantiated. Specify the session in the command; it is a best practice for a JMX client to have its own session and use it with the operations that involves configuration read or write (Listing 4).

    Listing 4
    AdminCommand cmd = cmdMgr.createCommand("listNodes");
  2. Execute the command

    Because listNodes does not take any parameters, no further processing is required. You can go ahead and execute the command using AsyncCommandClient helper (Listing 5). (Although listNodesis is not an async command, the AsyncCommandClient helper is used as a general practice.)

    Listing 5
    AsyncCommandClient  asyncCmdClientHelper = 
    new AsyncCommandClient(session, null);
  3. Print the result

    The results of running the command are sent so that the client can retrieve the results using the AdminCommand.getResult() API. The API will return an instance of CommandResult, which will indicate whether execution of the command was successful; if successful, the results can be retrieved using the CommandResult.getResult() API; otherwise, in case of failure the exception can retrieved using CommandResult.getException() API (Listing 6).

    Listing 6. Print admin command
    CommandResult result = cmd.getCommandResult(); 
    if (result.isSuccessful()) {
    	System.out.println("Successfully executed the command");
    	System.out.println("Result: ");
    	Object resultData = result.getResult();
    	if (resultData instanceof Object[]) {
    		Object[] resDataArr = (Object[])resultData;
    		for (Object resData : resDataArr) {
    	} else {
     } else {
    	System.out.println("Failed to execute the command");

    The listNodes command returns the results in a string array. The sample iterates through and displays the results data (Listing 7). Depending on the result data type, other commands are handled accordingly.

    Listing 7. Command output
    Executing listNodes command
    Successfully executed the command

Executing a task command (no parameters)

The listBLAs command is an asynchronous task command. It can accept optional parameters, but we will omit them in this first example.

The steps to run an admin command also apply to running a task command. However, because listBLAs is also asynchronous, an additional call is required to process the task parameters. Even though the parameters in this case are optional, it is still mandatory to invoke parameter processing, which validates and enables the parameters before the command is executed.

To run the listBLAs command without parameters, you perform the steps as above, with one new step added (new steps added to the execution procedure are shown in bold type):

  1. Create the command
  2. Process the task command parameters

    Listing 8 shows the call to the AdminCommandClient helper class to process the task parameters. Although also an asynchronous operation, AsyncCommandClient performs the same function for synchronous command implementations.

    Listing 8

    Listing 9 shows the complete code snippet for executing the listBLAs command without parameters.

    Listing 9
    AdminCommand cmd = cmdMgr.createCommand("listBLAs");
    AsyncCommandClient  asyncCmdClientHelper = 
    new AsyncCommandClient(session, null);
    CommandResult result = cmd.getCommandResult(); 

    In Listing 10, the listBLAs command returns all the BLAs defined in the cell.

    Listing 10
    Executing listBLAs command
    Successfully executed the command
  3. Execute the command
  4. Print the result

Executing a task command with parameters

Now, let’s run the listBLAs command again, this time with parameters. The command has two optional parameters, blaID and includeDescription, both of which we will use in this example. The steps to execute listBLAs are the same as before, with the addition of another step to set the parameters:

  1. Create the command
  2. Set the parameters in the command

    You can set the parameters for a command using the AdminCommand.setParameter() API. In this example, the command parameter names and values are stored in a string array such that the ith element is the parameter name and the (i+1)th element is the parameter value (Listings 11 and 12).

    Listing 11
    commandClient.listBLAs(new String[] {"blaID", "DefaultApplication", 
    "includeDescription", "true"});
    Listing 12
    private void listBLAs(String[] params) {
    	try {
    		//create command
     	//set command parameters
    	for (int i=0; i<params.length; i++) {
    			String paramName = params[i];
    			String paramValue = null;
    			if (i+1 < params.length){
    				paramValue = params[i];
    			cmd.setParameter(paramName, paramValue);
    	// process and execute the command 
    	} catch (Throwable e) {

    In case of asynchronous task commands, the processing of parameters should be called after the parameters are set; otherwise, the command assumes there are no parameters and the parameters that are set after processing will be ignored. If the parameters are optional, the command will still execute successfully, since having no parameters is a valid condition.

    Listing 13 shows the command result.

    Listing 13
    Executing listBLAs command with parameters
    Successfully executed the command
  3. Process the task command parameters
  4. Execute the command
  5. Print the results

Executing an async command and receiving notifications

Asynchronous commands send their results to the client through notifications. In addition, some commands send the status or informational messages to the client via command notifications while in progress.

When an asynchronous command is executed through the AsyncCommandClient helper, it registers for command notifications with the server to receive the notifications. However, AsyncCommandClient will not forward the notifications to the client by default. The client must implement the notification listener AsyncCommandHandlerIF and register the notification listener with AsyncCommandClient to receive the notifications in JMX client (Listing 14).

Listing 14
class AsyncCmdHandler implements AsyncCommandHandlerIF {
public void handleNotification(CommandNotification notification) {
		// Add your own code here to handle the received notification.
	       System.out.println("Notification received: " + notification);

The notification listener registers with AsyncCommandClient when the helper class is instantiated (Listing 15).

Listing 15
AsyncCmdHandler handler = new AsyncCmdHandler();
AsyncCommandClient  asyncCmdClientHelper = 
new AsyncCommandClient(session, handler);

Listing 16 shows the command result.

Listing 16
Executing viewBLA command
Notification received: CommandNotification:Command Name=viewBLA, command Status=
Completed, Command Step Name=, subtaskStatus=Completed, session id=1359293709793,
result=CommandResultImpl:{result=Operation done!, throwable=null, warnings=[]}, 
message=Operation Completed
Successfully executed the command
Operation done!

Executing a task command with steps

Task commands can have zero or more steps; a step is an operation of a task command. This example uses the editBLA command, a task command with an optional table step.

Unlike command parameters, table steps do not accept parameters directly. Rather, parameters are defined in a table that is generated by the command. The table will have one or more rows. Each row will have a set of values (parameters in columns), and one or more fields in the set will be used as a key to identify the row and update the editable fields in the row. The editable fields in the row are the input parameters for the step.

This time, two steps are added to the command execution sequence, one to retrieve the step, and another to set the parameters in the table:

  1. Create the command
  2. Set the parameters in the command
  3. Process the task command parameters
  4. Retrieve the step from the command

    The step can be retrieved from the command instance using either of these two APIs: getCommandStep() or gotoStep(). Both APIs will return the step instance, but internally the command will have a cursor; in gotoStep(), the command will move the cursor to the step, whereas in getCommandStep(), the API helps to traverse through the steps based on a condition and sequence.

  5. Iterate through the rows of the step
    1. Identify the row that matches key field(s)
    2. Set the parameter for the matching row

    The getNumberOfRows() API provides the number of rows in the table of the step, n. Using that, you can iterate through the 0 to (n-1) rows of the table. The value set for a particular parameter in a table row can be retrieved using the getParameter() API by passing the parameter name and the row index (for example, 0… (n-1)). Similarly, if the parameter field is editable, the value for it can be set using the setParameter() API.

    The editBLA command has a table step BLAOptions with parameters name (the key field to identify the row), description, and scope, where description and scope are the editable fields. In this example, you will edit the description of a BLA through the BLAOptions step. The data for the step will be passed as Properties, with the key to identify the row as key and value as value (Listing 17).

    Listing 17
    Properties stepParams = new Properties();
    stepParams.setProperty("DefaultApplication", "testingBLADescription");
    new String[] {"blaID", "DefaultApplication"}, "BLAOptions", stepParams);

    Here, DefaultApplication in stepParams is the key, which will be the value of the name parameter in a row for which the description parameter has to be set to testingBLADescription. The implementation in this example to set the description is to get the BLAOptions step from the command using getCommandStep() and iterate through the rows in the parameters table. While iterating, use getParameter() to get the name parameter of the row. If it has a value in stepParams, get that value and set it for the description parameter using setParameter() by passing the same row index (Listing 18).

    Listing 18
    CommandStep step = ((TaskCommand) cmd).getCommandStep(stepName);
    for (int i = 0; i < step.getNumberOfRows(); i++) {
    	Object paramKey= step.getParameter("name", i);
    	Object paramValue = stepParams.get(paramKey);
    	if (paramValue != null) {
    		step.setParameter("description", paramValue, i);

    Listng 19 shows the command result.

    Listing 19
    Executing editBLA command
    Successfully executed the command
    Operation done!
  6. Execute the command
  7. Print the results

Executing a command with target object

The next example executes a command that acts on a specific target object, such as an existing WebSphere Application Server configuration. The command that executes on a target object will decide the flow, and its steps and parameters will be based on the target object that is set. The command used for this example is showServerInfo, and the target object is the server configuration.

The steps to execute this type of command are:

  1. Create the command
  2. Query for target object using ConfigService

    The server configuration can be queried using the ConfigService.resolve() API (Listing 20).

    Listing 20
  3. Set the target object in the command

    The resultant Object Name is set as target object in the command using the setTargetObject() API (Listing 21).

    Listing 21
    ObjectName targetObj = getTargetObject(targetObjStr);
    Listing 22
    private ObjectName getTargetObject(String query) {
    //	Assumption: Query will return a valid single target object 
    	try {
    		return cfgService.resolve(session, query)[0];
    	} catch (ConfigServiceException e) {
    		// TODO Auto-generated catch block
    	} catch (ConnectorException e) {
    		// TODO Auto-generated catch block
    	return null;

    Listing 22 shows the command result.

    Listing 23
    Executing showServerInfo command
    Successfully executed the command
    {cell=balnachiV85Cell01, serverType=APPLICATION_SERVER,, node=balnachiV85Node01, server=server1}
  4. Set command and step parameters, and process it, if any
  5. Execute the command
  6. Print the results

Executing a task command with steps interactively

This example is a compilation of all the scenarios that discussed thus far. Additionally, you’ll see how you can get those parameters interactively, and then execute the command.

The advantage of executing a command interactively is that the command can prompt the user about the required data and then get the data. This example shows how you would get the parameter information from the command and step, and use that information to prompt the user for parameter values.

Each command and step will use the getCommandMetadata() API, which will provide the list of parameters and its metadata. Also, if a target object is required the API will provide the description of the target object that is expected.

The command used in this example is createDatasource, which requires the JDBCProvider as target object and generates a parameters table for the configureResourceProperties step based on the JDBCProvider target object, along with the parameters of the command.

For the purpose of this example, the interactive operations are split into simple methods. The first step to execute the command is setting the target object, if the command accepts it. The command metadata has two APIs, isTargetObjectAllowed() and isTargetObjectRequired(). The first API determines if the command accepts any target objects, and the second determines if the target object is mandatory to execute the command. The getTargetObjectTitle() API of the metadata command will give a description of the target object that the command is looking for.

In this example, the command createDatasource expects the JDBCProvider as the target object. The command prompts the user with the description, takes the JDBCProvider name and path as string, and resolves it to the valid WebSphere Application Server configuration using ConfigService in the helper method getTargetObject(). The command prompts for the JDBCProvider target object, resolves it as a valid configuration, and sets it on the command (Listing 24). Otherwise, execution fails since the target object is required in this case.

Listing 24
private void setTargetObjectInteractive(AdminCommand cmd, CommandMetadata cmdMetadata) 
throws Exception {
    	ObjectName targetObject = null;
        if (cmdMetadata.isTargetObjectAllowed()){
        	String targetObjStr = prompt(cmdMetadata.getTargetObjectTitle() + ": ", 
        	if (targetObjStr != null) {
        		targetObject = getTargetObject(targetObjStr);
        if(targetObject == null && cmdMetadata.isTargetObjectRequired()) {
        	throw new Exception("Target Object is not valid");
        if (targetObject != null) {
        	System.out.println("Setting target object: " + targetObject);
Listing 25
The JDBC provider that is the target.: Server=server1:JDBCProvider=DB2 Using IBM JCC 
Setting target object: Websphere:_Websphere_Config_Data_Display_Name=DB2 Using IBM JCC 

The next step in interactive command execution is to prompt for the command parameters. The command metadata getParameters() API will provide the list of the parameters’ metadata (ParameterMetadata), iterate through them, and prompt for the parameter values. The APIs to get each parameter name, its description, whether it is required, and any default value are getName(), getDescription(), isRequired(), and getDefault(), respectively. The example in Listing 26 constructs the key using this data and prompts the user for the input values. If a parameter is required, a non-null value is required before moving on to the next parameter. If the user does not specify any value for a parameter but a default value is defined, then the default value will be used.

Listing 26
private void setCommandParametersInteractive(AdminCommand cmd, CommandMetadata 
cmdMetadata) throws InvalidParameterValueException, InvalidParameterNameException {
        Iterator<ParameterMetadata> paramsMetadata = cmdMetadata.getParameters()
        while (paramsMetadata.hasNext()) {
        	ParameterMetadata paramMatadata =;
        	String paramName = paramMatadata.getName();
        	String paramDesc = paramMatadata.getDescription();
        	String paramValue = paramMatadata.getDefaultValue();
        	boolean isRequired = paramMatadata.isRequired();
        	String promptKey = constructPromptKey(paramName, paramValue, paramDesc, 
        	while (true) {
        		String newValue = prompt(promptKey, paramValue);
        		//repeat prompt until the required parameter is set
	        	if (isRequired && newValue == null) {
	        	if(newValue !=  paramValue){
	        		cmd.setParameter(paramName, newValue);
Listing 27
*The name of the Datasource. (name) [] : MyClientDB
*The Java Naming and Directory Interface (JNDI) name for this Datasource. (jndiName) [] :
The description for the Datasource. (description) [] : 
The category that can be used to classify or group the resource. (category) [] : 
*The name of the DataStoreHelper implementation class that extends the capabilities 
of the implementation class of the JDBC driver to perform functions that are specific 
to the data. (dataStoreHelperClassName) [] :
The alias used for database authentication at run time.  This alias is only used when the 
application resource reference is using res-auth=Application. 
(componentManagedAuthenticationAlias) [] : 
Specifies if this Datasource is used for container-managed persistence of enterprise .
The default value is true. (containerManagedPersistence) [true] : 
The alias used database authentication during XA recovery processing. When this property 
is specified, the default value is the alias for application authentication. 
(xaRecoveryAuthAlias) [] :

If the command is an asynchronous task command, the command parameters are processed after they have been set. Because createDatasource is not a task command, the parameter processing is skipped in this example.

The next step is to iterate through the command steps and prompt for the step parameters. If the step is a simple command step, the interactive operation will be same as for command parameters. For a table step, however, using the parameter name in the metadata will not be helpful because the table step parameters will be in the form of a table. In this case, prompting with the data in the key fields of a row would be more meaningful for getting the data for editable fields.

Similar to the command parameter metadata, step parameter metadata will indicate if a parameter in a row is a key field or read-only field; if both are false it is an editable field. The value of a parameter in the row can be retrieved using the getParameter() API.

The example in Listing 28 will iterate through each row in the table, identify the editable fields in the row, get the values of key and read-only parameters, construct the key, and then use the key to prompt for editable field values.

Listing 28
private void setTableStepParametersInteractive(CommandStep step, CommandStepMetadata 
stepMetadata) throws InvalidParameterNameException, IndexOutOfBoundsException, 
InvalidParameterValueException {
	System.out.println("\nExecuting " + step.getName() + " step ");
	List stepParamsMdata = stepMetadata.getParameters();
	ParameterMetadata[] stepParamMetadata = new 
	for (int i=0; i<step.getNumberOfRows(); i++) {
		StringBuilder buffer = new StringBuilder();
		List<Integer> valueField = new ArrayList<Integer>();
		//construct the key field
		for (int j=0; j<stepParamMetadata.length; j++){
			boolean isKeyField = stepParamMetadata[j].isKeyField();
			boolean isReadonly = stepParamMetadata[j].isReadonly();

			if (!isKeyField && !isReadonly) {

			//Construct the data in key and read only fields as prompting key
			String paramName = stepParamMetadata[j].getName();
			String paramValue = (String) step.getParameter(paramName, i);
			String paramDesc = stepParamMetadata[j].getTitle();
			String promptKey = constructPromptKey(paramName, paramValue, 
paramDesc, (isKeyField ||isReadonly));
		//iterate through editable parameters and prompt for its data
		for (int k=0; k<valueField.size(); k++) {
			ParameterMetadata editParamMData = stepParamMetadata[valueField.
			String valueParamName = editParamMData.getName();
			String defaultValue = (String) step.getParameter(valueParamName, 
			String promptKey = constructPromptKey(valueParamName, 
defaultValue, editParamMData.getDescription(), editParamMData.isRequired());
			String newValue = prompt(promptKey, defaultValue);
			if (newValue != defaultValue) {
				step.setParameter(valueParamName, newValue, i);
Listing 29
Executing configureResourceProperties step 
*The name of the property. (name) [databaseName] : 
*The type of the property. (type) [java.lang.String] : 
The value for the resource property.  This is a required parameter. (value) [] : myDB2
*The name of the property. (name) [driverType] : 
*The type of the property. (type) [java.lang.Integer] : 
The value for the resource property.  This is a required parameter. (value) [4] : 
*The name of the property. (name) [serverName] : 
*The type of the property. (type) [java.lang.String] : 
The value for the resource property.  This is a required parameter. (value) [] : localhost
*The name of the property. (name) [portNumber] : 
*The type of the property. (type) [java.lang.Integer] : 
The value for the resource property.  This is a required parameter. (value) [50000] :

As with all other commands, this command is executed using AsyncCommandClient helper.

Listing 30
Successfully executed the command


IBM WebSphere Application Server offers multiple ways to administer its environment and one of the most customizable ways of administration is creating a JMX client specific to the environment. The Admin Command Framework provides a convenient way of efficiently performing administrative tasks while simplifying the presentation of the WebSphere Application Server configuration model and topology for the user. This article covered typical scenarios related to using the Admin Command Framework commands and how to invoke admin commands through a JMX client.

Downloadable resources

Related topics

ArticleTitle=Create a custom administrative client to simplify system administration in WebSphere Application Server V8.5