Writing a Management Program


You can gain ultimate control over the WebSphere configuration and operational environment by programming directly to WebSphere's Java management interfaces. These interfaces conform to the JMX (Java Management Extensions) standard specification defined for Java. While similar, the information model supported by WebSphere is necessarily different from other application server products on the market (supporting different resources and extensions).

Preparing to Execute a Management Program

Most commonly you will execute your management program from outside any WebSphere server processes – essentially as a client program.

Getting an Admin Client

Before you can anything you have to get an instance of the AdminClient. This is done through a static method on the AdminClientFactory:

 private void createAdminClient() {   Properties connectProps = new Properties();   connectProps.setProperty(AdminClient.CONNECTOR_TYPE,     AdminClient.CONNECTOR_TYPE_SOAP);   connectProps.setProperty(AdminClient.CONNECTOR_HOST, "rhighlt1");   connectProps.setProperty(AdminClient.CONNECTOR_PORT, "8879");   try {     adminClient = AdminClientFactory.createAdminClient(connectProps);   } catch (ConnectorException e) {     System.out.println("Exception creating admin client:" + e);     System.exit(-1);   } } 

Notice that you supply a connection Properties object to this operation. The connection properties describe the type of connection you want to create with the target AdminService (recall that AdminService is a wrapper for the JMX server and the end-point listener for communication from admin clients) – including the address of the target service. This sample hard-codes the address of the service, but obviously you will want to devise a way in which you can get this information as configuration data; perhaps prompted from the end user or derived from other information in your topology.

Identifying MBeans

Remember the JMX MBean system is about performing operations management – starting and stopping servers and applications, setting operational attributes, etc. Operations are performed on MBeans. Thus, nearly all of the operations that you perform require that you identify the MBean that you want to operate on. MBeans are identified by an ObjectName – an object containing the fully qualified name of the MBean. The ObjectName will consist of a set of attributes that uniquely identify the MBean.

The set of attributes that uniquely identify the MBean are established at the time the MBean is registered and activated. Since the attributes and their values are somewhat arbitrary, it is a bit much to have to know the exact set of attributes for every MBean you want to use. So JMX offers a way in which you can deduce an MBean's object name from a partial list of attribute values. This is done through a query mechanism that returns, at least, a partial list of objects that match the subset of attributes that you supply to the query.

Often, the result set will only contain one MBean – the MBean that you're really interested in. In other cases, it will return a number of MBeans, but it is usually easy to search through this intermediate result to find that one that you really want. Of course, in some cases you may really want the complete set of MBeans returned from the search – even if the result set contains several or many MBeans. Perhaps the query was initiated in response to some action taken by the end administrator and you will be presenting the returned set as a scroll list on the display. In any case, the set of MBeans returned from the query are each represented by a fully qualified object name that uniquely represents each individual MBean in the set. You can use these fully qualified object names as input to other JMX operations. The following code demonstrates a query for getting the fully qualified object name for the MBean representing a particular node agent:

 String partialName = "WebSphere:type=NodeAgent,node=rhighlt1,*"; ObjectName partialObjectName = new ObjectName(partialName); ObjectName nodeAgent = null; Set nodeAgentList = adminClient.queryNames(partialObjectName, null); 

An object name is created with the partial name of the node agent, and then used as input to the query (adminClient.queryNames()) to acquire a set of ObjectNames that match that partial name. The ObjectNames returned from the query contain fully qualified MBean names.

The second argument to the query (which is null in the example) can be a query predicate object (javax.management.QueryExp) used to specify predicate to the query operation. You can get a QueryExp object from static methods on the java.management.Query object.

String-form Names

An ObjectName can have a string-form. The string-form of an ObjectName has the following syntax:

[{<nameSpace> | '*'}':']     {<attrName>'='<attrValue> {','<attrName>'='<attrValue>}* [',*']} | '*'

The nameSpace domain is optional – the wildcard * is assumed if no specific name-space is specified, meaning that all of the available name spaces will be examined for the matching attributes. While it may be convenient to wildcard the name space, this is not recommended as it is possible to introduce different MBeans with the same attributes and values with significantly different meanings. For example, you can imagine two different middleware products introducing MBeans representing servers by the name of "server1". But an application server in WebSphere is unlikely to have the same meaning as some other server in another middleware product. The namespace for WebSphere is called, appropriately, "WebSphere". (Notice the capitalization – all tokens in the MBean object name are case-sensitive.)

The namespace is separated from the attribute list by a colon (:).

The attribute list is zero or more name-value pairs, separated by commas. The last entry in the list can be a wildcard (*), indicating that no other attributes should be considered when evaluating this name to the actual name of the MBean. If the wildcard is omitted, then an ObjectName must contain exactly the attributes specified for it to be considered the same MBean.

Other than the trailing wildcard, no other order is assumed for the attributes in the list – they can be specified and will be presented in any order.

Getting a Node Agent

Building on the query described above, the process of getting a node agent, then, is just a matter of selecting an ObjectName from the returned set:

 private ObjectName getNodeAgent(String nodeName) {   try {     String partialName = "WebSphere:type=NodeAgent,node=" + nodeName + ",*";     ObjectName partialObjectName = new ObjectName(partialName);     ObjectName nodeAgent = null;     Set nodeAgentList = adminClient.queryNames(partialObjectName, null);     if (!nodeAgentList.isEmpty()) {       nodeAgent = (ObjectName) nodeAgentList.iterator().next();     } else {       System.out.println("Node agent was not found.");       System.exit(-1);     }     return nodeAgent;   } catch (MalformedObjectNameException e) {     System.out.println("MalformedObjectNameExc getting the NodeAgent: " + e);     System.exit(-1);   } catch (ConnectorException e) {     System.out.println("ConnectorExc getting the NodeAgent: " + e);     System.exit(-1);   }   return null; } 

Many ObjectNames could be returned from the query – if there were many NodeAgent type MBeans with the same node name, for example. However, in this case we know that only one node agent is allowed per node, and since we explicitly specified the node name we're interested in, then only one ObjectName should be returned – or, at least, we only look for the first name in the set.

Starting a Server

Once you've obtained the node agent, you can use it to start an application server on that node:

 private void startServer(ObjectName nodeAgent, String serverName) {   String opName = "launchProcess";   Object params[] = { serverName };   String signature[] = { "java.lang.String" };   boolean launched = false;   try {     System.out.println("Starting " + serverName);     Boolean b = (Boolean) adminClient.invoke(nodeAgent, opName,                                               params, signature);                launched = b.booleanValue();     if (launched) {       System.out.println(serverName + " was launched");     } else {       System.out.println(serverName + " was not launched");     }   } catch (Exception e) {     System.out.println("Exception invoking launchProcess:" + e);   } } 

The server is started by invoking the launchProcess operation on the NodeAgent object. This operation takes the server name as an argument. Since the launchProcess operation is overloaded on the NodeAgent MBean (there are two forms of the launchProcess operation), you have to provide a signature specification to help differentiate which of the overloaded operations you want to perform.

If you wanted to start the server and only wait a specific amount of time, let's say 20 seconds, before going on to the next thing, you can use the form of launchProcess that takes a wait-time as an argument:

private void startServer(ObjectName nodeAgent, String serverName) {     String opName = "launchProcess";   Object params[] = { serverName, new Integer(20) };   String signature[] = { "java.lang.String", "java.lang.Integer" };   boolean launched = false;   try {     System.out.println("Starting " + serverName);     Boolean b = (Boolean) adminClient.invoke(nodeAgent, opName,                                              params, signature);     launched = b.booleanValue();     if (launched) {       System.out.println(serverName + " was launched");     } else {       System.out.println(serverName + " was not launched in the specified " +                                        "time.");     }   } catch (Exception e) {     System.out.println("Exception invoking launchProcess:" + e);   } }

Notice the inclusion of the additional Integer argument, and its specification in the signature.

Getting a Server

Getting a server is similar to getting a node, although the MBean ObjectName for the server is different:

 private ObjectName getServer(String nodeName, String serverName) {   try {     String query = "WebSphere:type=Server,node=" + nodeName +                     ",process=" + serverName + ",*";     ObjectName queryName = new ObjectName(query);     ObjectName server = null;     Set s = adminClient.queryNames(queryName, null);     if (!s.isEmpty()) {       server = (ObjectName) s.iterator().next();     } else {       System.out.println("Server was not found.");       System.exit(-1);     }     return server;   } catch (MalformedObjectNameException e) {     System.out.println(e);     System.exit(-1);   } catch (ConnectorException e) {     System.out.println(e);     System.exit(-1);   }   return null; } 

You will discover that the hardest part about using JMX is figuring out the primary attributes of the MBean ObjectNames, and the operations and their signatures supported by MBeans. The latter can be got from the Javadocs of MBeans supported by WebSphere. The following is the operation list taken from the Javadoc for the Server:

 getProductVersion - Gets the XML Version data for the specified product.
return type: java.lang.String
parameters:
productID (java.lang.String) – ID String for the desired product. getComponentVersion - Gets the XML Version data for the specified component.
return type: java.lang.String
parameters:
componentID (java.lang.String) – ID String for the desired component. getEFixVersion - Gets the XML Version data for the specified efix.
return type: java.lang.String
parameters:
efixID (java.lang.String) – ID String for the desired efix. getPTFVersion - Gets the XML Version data for the specified PTF.
return type: java.lang.String
parameters:
ptfID (java.lang.String) – ID String for the desired PTF. getExtensionVersion - Gets the XML Version data for the specified extension.
return type: java.lang.String
parameters:
extensionID (java.lang.String) – ID String for the desired extension. getVersionsForAllProducts - Gets the XML Version data for the all installed products.
return type: java.lang.String;
parameters:
getVersionsForAllComponents - Gets the XML Version data for the all installed components.
return type: java.lang.String;
parameters:
getVersionsForAllEFixes - Gets the XML Version data for the all installed efixes.
return type: java.lang.String;
parameters:
getVersionsForAllPTFs - Gets the XML Version data for the all installed PTFs.
return type: java.lang.String;
parameters:
getVersionsForAllExtensions - Gets the XML Version data for the all installed extension.
return type: java.lang.String;
parameters:
stop - Stop the server process.
return type: void
parameters:
stopImmediate - Stop the server process without going through application shutdown.
return type: void
parameters:
stop - Stop the server process and callback.
return type: void
parameters:
callback (java.lang.Boolean) – perform callback to requester.
port (java.lang.Integer) – port number for callback.

As a general rule you should get operation information about your MBeans from the product Javadoc – at least those that are introduced by WebSphere. If you don't find it in the WebSphere InfoCenter, you should be able to find it in the web/mbeanDocs directory off the product install-root. Launch the index.html file in this directory in your browser and you will see a list of all of the MBeans. You can then navigate to the attribute, operation, and notification specifications for the MBean.

Stopping a Server

Stopping a server is an operation that you can invoke on the Server MBean itself (as opposed to the NodeAgent as in the case of starting the server):

 private void stopServer(ObjectName server) {   String opName = "stop";            try {     adminClient.invoke(server, opName, null, null);     System.out.println("server was stopped");   } catch (Exception e) {     System.out.println("Exception invoking stop server:" + e);   } } 

In this case, the stop operation is overloaded, but one version of its signature does not take any arguments, and so you can pass null for the parameter and signature arguments of the invoke() method.

Handling Notifications

You can register a notification listener with the AdminClient. This is useful for getting notified of changes in the state of the system – when servers and applications start and stop, when nodes are added and removed, etc. You can register for any of the notifications that any MBean generates – again look at the Javadoc for the MBeans to find out what notifications are produced by that MBean. The following notifications are produced by the Server MBean:

  • j2ee.state.starting – published by the Server MBean when the corresponding server has been started

  • j2ee.state.running – indicates that the corresponding server is fully up and running

  • j2ee.state.stopping – is published to note that the corresponding server is shutting down.

  • j2ee.state.stopped – published when the server has fully stopped

To listen for notifications you must create a listener object that implements the javax.management. NotificationListener interface, and in doing so implements the handleNotification() method:

 public class PlantsAdminNotifyListener implements NotificationListener {   public void handleNotification(Notification ntfyObj, Object handback) {     System.out.println("Notification received:");     System.out.println("  type = " + ntfyObj.getType());     System.out.println("  message = " + ntfyObj.getMessage());     System.out.println("  source = " + ntfyObj.getSource());     System.out.println("  seqNum = " +                            Long.toString(ntfyObj.getSequenceNumber()));     System.out.println("  timeStamp = " + new Date(ntfyObj.getTimeStamp()));   } } 

You can register this notification listener with a specific MBean through the AdminClient interface:

 public void registerNotificationListener(ObjectName nodeAgent) {   try {     PlantsAdminNotifyListener notifyListener =        new PlantsAdminNotifyListener();     adminClient.addNotificationListener(nodeAgent, notifyListener, null, null);   } catch(InstanceNotFoundException e) {     System.out.println( "InstanceNotFoundException registering listener:" + e);   } catch(ConnectorException e) {     System.out.println("ConnectorException registering listener:" + e);   } } 

At this point, your notification listener (notifyListener in the above example) will be called whenever the NodeAgent you've registered with changes state.

Filtering Notifications

Having registered for notifications, you will receive all notifications – whether you're interested in them or not. You can, however, filter which notifications are handed back to you. This is done with a javax.management.NotificationFilter object. JMX provides pre-defined implementations of NotificationFilters:

  • javax.management.NotificationFilterSupport
    Allows you to filter notifications by the name of the notification. You can provide full notification name (for example, "websphere.process.running"), or a name prefix (for example, "websphere.process"). By default, all notifications will be disabled with the NotificationFilterSupport until you enable them with by invoking the enableType operation on the filter.

  • javax.management.AttributeChangeNotificationFilter
    Enables you to filter attribute change notifications by specific attribute name, or attribute name prefix.

These usually provide all of the filtering support you will need. However, if you need to do something else, you can create your own filter implementation, derived from the NotificationFilter interface, and registered in place of any of the pre-defined filters listed above.

The following exemplifies creating a filter, setting its constraints, and registering it along with your notification listener:

public void registerNotificationListener(ObjectName nodeAgent) {   try {     NotificationFilterSupport myFilter = new NotificationFilterSupport();     myFilter.enableType("websphere.process.running");     PlantsAdminNotifyListener notifyListener =        new PlantsAdminNotifyListener();     adminClient.addNotificationListener(nodeAgent, notifyListener,        myFilter, null);     System.out.println("Notification listener registered.");   } catch(InstanceNotFoundException e) {     System.out.println( "InstanceNotFoundException registering listener:" + e);   } catch(ConnectorException e) {     System.out.println("ConnectorException registering listener:" + e);   } }

Communicating Handbacks

On occasion, you will want to pass in information, at the time you register for notifications, which is handed back to the notification listener. This can be done with a Handback object – an object that you create, and register along with your notification listener, which will be handed back to you on any notifications published to your listener:

public void registerNotificationListener(ObjectName nodeAgent) {   try {     NotificationFilterSupport myFilter = new NotificationFilterSupport();     myFilter.enableType("websphere.process.running");     myFilter.enableType("websphere.process.starting");     String lookFor = "websphere.process.running";     adminClient.addNotificationListener(nodeAgent, this, myFilter, lookFor);     System.out.println("Notification listener registered.");   } catch(InstanceNotFoundException e) {     System.out.println( "InstanceNotFoundException registering listener:" + e);   } catch(ConnectorException e) {     System.out.println("ConnectorException registering listener:" + e);   } }

The hand-back object can be any valid Java object, including a String – as in this example. If you need to make it more complicated then you can create your own object and pass that as well.

Once you've passed the hand-back object on registration, it will be passed back to the notification listener on each notification:

 public void handleNotification(Notification ntfyObj, Object lookFor) {   System.out.println("Notification received:");   System.out.println("  type = " + ntfyObj.getType());   System.out.println("  message = " + ntfyObj.getMessage());   System.out.println("  source = " + ntfyObj.getSource());   System.out.println("  seqNum = " +                          Long.toString(ntfyObj.getSequenceNumber()));   System.out.println("  timeStamp = " + new Date(ntfyObj.getTimeStamp()));           System.out.println(">>> Looking for: " + lookFor.toString());   if (ntfyObj.getType().startsWith(lookFor.toString())) this.notified = true; } 

Remember that the handback handed in is typed to be a Java object. You need to be sure that you test for the proper type before using it in your listener.




Professional IBM WebSphere 5. 0 Applicationa Server
Professional IBM WebSphere 5. 0 Applicationa Server
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 135

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net