The Performance Monitoring Infrastructure (PMI) is a set of packages and libraries designed to assist with gathering, delivering, processing and displaying performance data in WebSphere Application Server Advanced Edition domains. This section discusses the client packages of the PMI application programming interface (API) and describes how to use them to write WebSphere Application Server clients that collect and display performance data from servers.
The perf.jar file is required for client applications using PMI client APIs. The perf.jar file is distributed with WebSphere and is also a part of WebSphere Java thin client package. You can get it from either a WebSphere Application Server installation or WebSphere Java Thin Application Client installation. Refer InfoCenter articles 4.7.3 and 4.7.6 for more information.
The following is sample code to show how to use PmiClient to collect PMI data. Use the administrative console to set instrumentation level (a level other than NONE) first.
The end-to-end code path is as follows:
PmiTester > PmiClient > Collector > Administrative server > Application server
Sample code:
package com.ibm.websphere.pmi;
import com.ibm.websphere.pmi.*;
import com.ibm.websphere.pmi.server.*;
import com.ibm.websphere.pmi.client.*;
import com.ibm.ws.pmi.server.*;
import com.ibm.ws.pmi.server.modules.*;
import com.ibm.ws.pmi.wire.*;
import java.util.ArrayList;
public class PmiTester implements PmiConstants {
/** a test driver
* If there is any argument:
* args[0] - node name
* args[1] - port number
*
*/
public static void main(String[] args) {
String hostName = null;
String portNumber = null;
if (args.length >= 1)
hostName = args[0];
if (args.length >= 2)
portNumber = args[1];
try {
PmiClient pmiClnt = new PmiClient(hostName, portNumber);
PerfDescriptor[] nodePds = pmiClnt.listNodes();
if (nodePds == null) {
System.out.println("no nodes");
return;
}
String nodeName = nodePds[0].getName();
System.out.println("after listNodes: " + nodeName);
PerfDescriptor[] serverPds = pmiClnt.listServers(nodePds[0].getName());
System.out.println("after listServers");
if (serverPds == null || serverPds.length == 0) {
System.out.println("NO app server in node");
return;
}
for (int j=0; j<serverPds.length; j++) {
System.out.println("server " + j + ": " + serverPds[j].getName());
// Option: you can call createPerfLevelSpec and then setInstrumentationLevel to set the level
// for each server if you want. For example, to set all the modules to be LEVEL_HIGH for the server j,
// uncomment the following.
// PerfLevelSpec[] plds = new PerfLevelSpec[1];
// plds[0] = pmiClnt.createPerfLevelSpec(null, LEVEL_HIGH);
// pmiClnt.setInstrumentationLevel(serverPds[j].getNodeName(), serverPds[j].getServerName(), plds, true);
// First, list the PerfDescriptor in the server
PerfDescriptor[] myPds = pmiClnt.listMembers(serverPds[j]);
// check returned PerfDescriptor
if (myPds == null) {
System.out.println("null from listMembers");
continue;
}
// you can add the pds in which you are interested to PerfDescriptorList
PerfDescriptorList pdList = new PerfDescriptorList();
for (int i=0; i<myPds.length; i++) {
// Option 1: you can recursively call listMembers for each myPds
// and find the one you are interested. You can call listMembers
// until individual data level and after that level you will null from listMembers.
// e.g., PerfDescriptor[] nextPds = pmiClnt.listMembers(myPds[i]);
// Option 2: you can filter these pds before adding to pdList
System.out.println("add to pdList: " + myPds[i].getModuleName());
pdList.addDescriptor(myPds[i]);
if ( i % 2 == 0)
pmiClnt.add(myPds[i]);
}
// call gets method to get the CpdCollection[] corresponding to pdList
CpdCollection[] cpdCols = pmiClnt.gets(pdList, true);
if (cpdCols == null) {
// check error
if (pmiClnt.getErrorCode() >0)
System.out.println(pmiClnt.getErrorMessage());
continue;
}
for (int i=0; i<cpdCols.length; i++) {
// simple print them,br>
//System.out.println(cpdCols[i].toString());
// Or call processCpdCollection to get each data
processCpdCollection(cpdCols[i], "");
}
// Or call gets() method to add the CpdCollection[] for whatever there by calling pmiClnt.add().
System.out.println("\n\n\n ---- get data using gets(true) ----- ");
cpdCols = pmiClnt.gets(true);
if (cpdCols == null) {
// check error
if (pmiClnt.getErrorCode() >0)
System.out.println(pmiClnt.getErrorMessage());
continue;
}
for (int i=0; i<cpdCols.length; i++) {
// simple print out the whole collection
System.out.println(cpdCols[i].toString());
// Option: refer processCpdCollection to get each data
}
}
} catch (Exception ex) {
System.out.println("Exception calling CollectorAE");
ex.printStackTrace();
}
}
// show the methods to retrieve individual data
private static void processCpdCollection(CpdCollection cpdCol, String indent) {
CpdData[] dataList = cpdCol.dataMembers();
String myindent = indent;
System.out.println("\n" + myindent + "--- CpdCollection " + cpdCol.getDescriptor().getName() + " ---");
myindent += " ";
for (int i=0; i<dataList.length; i++) {
CpdValue cpdVal = dataList[i].getValue();
if (cpdVal.getType() == TYPE_STAT) {
CpdStat cpdStat = (CpdStat)cpdVal;
double mean = cpdStat.mean();
double sumSquares = cpdStat.sumSquares();
int count = cpdStat.count();
double total = cpdStat.total();
System.out.println(myindent + "CpdData id=" + dataList[i].getId()
+ " type=stat mean=" + mean);
// you can print more values like sumSquares, count,etc here
} else if (cpdVal.getType() == TYPE_LOAD) {
CpdLoad cpdLoad = (CpdLoad)cpdVal;
long time = cpdLoad.getTime();
double mean = cpdLoad.mean();
double currentLevel = cpdLoad.getCurrentLevel();
double integral = cpdLoad.getIntegral();
double timeWeight = cpdLoad.getWeight();
System.out.println(myindent + "CpdData id=" + dataList[i].getId()
+ " type=load mean=" + mean + " currentLevel=" + currentLevel);
// you can print more values like sumSquares, count,etc here
} else if (cpdVal.getType() == TYPE_LONG) {
CpdValue cpdLong = (CpdValue)cpdVal;
long value = (long)cpdLong.getValue();
System.out.println(myindent + "CpdData id=" + dataList[i].getId()
+ " type=long value=" + value);
} else if (cpdVal.getType() == TYPE_DOUBLE) {
CpdValue cpdDouble = (CpdValue)cpdVal;
double value = cpdDouble.getValue();
System.out.println(myindent + "CpdData id=" + dataList[i].getId()
+ " type=double value=" + value);
} else if (cpdVal.getType() == TYPE_INT) {
CpdValue cpdInt = (CpdValue)cpdVal;
int value = (int)cpdInt.getValue();
System.out.println(myindent + "CpdData id=" + dataList[i].getId()
+ " type=int value=" + value);
}
}
// recursively go through the subcollection
CpdCollection[] subCols = cpdCol.subcollections();
for (int i=0; i<subCols.length; i++) {
processCpdCollection(subCols[i], myindent);
}
}
private static void report(CpdCollection col) {
System.out.println("\n\n");
if (col==null) {
System.out.println("report: null CpdCollection");
return;
}
System.out.println("report - CpdCollection ");
printPD(col.getDescriptor());
CpdData[] dataMembers = col.dataMembers();
if (dataMembers != null) {
System.out.println("report CpdCollection: dataMembers is " + dataMembers.length);
for (int i=0; i<dataMembers.length; i++) {
CpdData data = dataMembers[i];
printPD(data.getDescriptor());
}
}
CpdCollection[] subCollections = col.subcollections();
if (subCollections != null) {
for (int i=0; i<subCollections.length; i++) {
report(subCollections[i]);
}
}
}
private static void printPD(PerfDescriptor pd) {
System.out.println(pd.getFullName());
}
}
PMI follows a client/server architecture. In PMI terms, a server is any application that uses the PMI API to collect performance data; servers can include application servers, HTTP servers, and Java applications. A client is an application that receives performance data from a server or servers and processes the data; clients can include graphical user interfaces (GUIs) that display performance data in real time, applications that monitor performance data and trigger different events according to the current values of the data, or any other application that needs to receive and process performance data. The end-to-end view of performance data retrieval is shown here:
Each piece of performance data has two components, a static component and a dynamic component. The static component consists of a name and an ID to identify the data, as well as other descriptive attributes that assist the client in processing and displaying the data. The dynamic component consists of information that changes over time, such as the current value of a counter and the time stamp associated with that value.
Performance data is classified into the following four types:
Numeric data consists of a single numeric value such as an integer, a long, or a double. It is used to represent data such as counts and sizes.
A server can track many instances of each type of performance data. For example, a number of pieces of performance data tracking the average response time of bean methods. In this case, each piece of performance data shares the same ID, and the server sends additional identifying information (for example, the bean's home name) along with the performance data so that clients can distinguish among the different instances.
PMI interfaces with WebSphere administration utilities to enable administrators to control the amount and level of performance data collected. You can access the PMI administrative interface by using the administrative console.
This section discusses PMI's client implementation, including the organization of data sent to clients and the interfaces clients use to retrieve and process performance data from servers. Performance data used by PMI's client implementation is referred to as client performance data (CPD).
PMI data is provided to clients in a hierarchical structure. The CpdSnapshot object is the root of the hierarchy. Descending from the CpdSnapshot object are node information, server information, module information, and PerfCollection and CpdData objects. See the diagram below referring to data hierarchy. Note that the node-information and server-information objects contain no performance data.
Each time a client retrieves performance data from a server, the data is returned in a subset of this structure; the form of the subset depends on the data that is retrieved. You can update the entire structure with new data or update only part of the tree, as needed.
The PMI client package exports the CpdCollection, CpdData, and CpdValue interfaces to provide performance data to interested clients. The PMI API provides the PmiClient interface to enable clients to receive performance data from servers. For details on these interfaces, see The CpdCollection interface, The CpdData and CpdValue objects, and The PmiClient class. In addition, PMI provides the CpdEventListener and CpdEvent interfaces for clients to notify the GUI program when new or changed data is retrieved by the client. These event and listener interfaces are used within the client JVM process. No server side registration is supported. See The CpdEventListener and CpdEvent interfaces for details. Finally, PMI provides the CpdFamily class to assist with displaying data in table form. See The CpdFamily class for details.
The CpdCollection interface is the base interface to PMI. It organizes performance data in the hierarchy described in data organization and hierarchy. Each member of the hierarchy is an instance of CpdCollection that contains a number of data members and a number of CpdCollection children.
The CpdCollection interface extends two other PMI interfaces, CpdXML and CpdEventSender. These interfaces are defined as follows:
The following are definitions of the CpdCollection, CpdXML and CpdEventSender interfaces:
public interface CpdCollection extends Serializable, CpdXML, CpdEventSender { public PerfDescriptor getPerfDescriptor(); public String getDescription(); public int numDataMembers(); public CpdData[] dataMembers(); public CpdData getData(int index); public int numSubcollection(); public CpdCollection[] subcollections(); public CpdCollection getSubcollection(int i); public CpdCollection findCollection(PerfDescriptor pd); public void addSubcollection(CpdCollection col); public CpdCollection getParent(); public void update(CpdCollection other); public CpdCollection reset(); public void update (CpdCollection other, boolean keepOld); public int getLevel(); public void update(CpdCollection other, boolean keepOld); // default is removing old entry, available in 4.02+ public void update(CpdCollection other, boolean keepOld, boolean recursiveUpdate); // default is recursive update, avaialbe in 4.02+ public int getLevel(); // available in 4.0.2+ } public interface CpdXML { public String toXML(); public void fromXML(String xmlStr); } public interface CpdEventSender extends Cloneable { public void addCpdEventListener(CpdEventListener al); public void removeCpdEventListener(CpdEventListener al); public void notifyListeners(CpdEvent evt); public void notifyListeners(int evt_type); } |
The update method updates collections of data. When the boolean parameter keepOld is true, the update will not remove the old members which are not in the new collection anymore. To illustrate the functionality of this method, assume that the collection1.update(collection2) statement is used to update a data collection named collection1 with the data in a collection named collection2. In this case, the update method works as follows:
The update method then returns a value of true to the caller.
If neither of these conditions is met, the update method returns a value of false.
By default, the update method will update all the subcollections recursively and remove the old entry. However, you can always pass more parameters to the update method and specify the way you like.
The PerfDescriptor interface is used to specify the data that the client is interested in. It includes methods that return node name, server name, module name, collection name, and full name. Its definition is as follows:
public interface PerfDescriptor extends Serializable { public int getType(); // Types include node, server, module, instance, // and data public String getNodeName(); public String getServerName(); public String getModuleName(); public String getName(); // Returns node, server, module, instance, // or data name, depending on type public String getFullName(); // Returns a name in the following form: // node.server.module.instance.data public String[] getPath(); public boolean equals(PerfDescriptor pd); public boolean isDescendingFrom(PerfDescriptor pd); public int[] getDataIds(); // Returns all data IDs (null, one, or multiple) // in the descriptor } |
The PerfDescriptorList class is used to gather data from multiple PerfDescriptor instances. It includes methods to add, remove and get PerfDescriptor instances. Its definition is as follows:
public class PerfDescriptorList { public boolean addDescriptor(PerfDescriptor pd); // If pd is not in the // list, add it and return true; otherwise, return false public boolean removeDescriptor(PerfDescriptor pd); // If pd is in the // list, remove it and return true; otherwise, return false public int numDescriptors(); // Return the number of PerfDescriptor // instances in the list public PerfDescriptor[] getDescriptors(); // Return all PerfDescriptors // in an array } |
The CpdData object is the lowest level in the CPD hierarchy. Each CpdData instance contains all the static information for the performance data as well as a getValue method to return the data's dynamic information in the form of an instance of the CpdValue object. The CpdData interface provides an update method to take a reference to a new version of a piece of data and update the current object with the new value. The value is updated only if the new data has the same name as the original object. The CpdData interface also includes an addListener interface to enable data objects to register as event listeners; see The CpdEventListener and CpdEvent interfaces for details. The CpdData interface extends the CpdXML and CpdEventSender interfaces, which are shown in the definition located in that section.
The definition of CpdData is as follows:
public interface CpdData extends Serializable, CpdXML, CpdEventSender { public PerfDescriptor getDescriptor(); public String getDescription(); public void setValue(CpdValue value); public void update(CpdData other); public CpdValue getValue(); public Object getParent(); public void setParent(Object parent); public boolean reset(); public int getId(); } |
A variety of data types extend the CpdValue interface. The interface provides the getValue, getTime, delta, and rate methods to work with data values. The definition of CpdValue is as follows:
public inteface CpdValue extends Serializable, Cloneable { public int getType(); public long getTime(); public double getValue(); public CpdValue delta(CpdValue prev); // return the difference public CpdValue rate(CpdValue prev); // return the rate of the difference public void combine(CpdValue other); // add another value to this value public Object clone(); public int getId(); } |
Each client value type extends the CpdValue interface. The specific
types are listed in Table 1.
Table 1. CpdValue types and associated methods
Type | Method | Description |
---|---|---|
CpdInt | int intValue() | Value as an int |
CpdLong | long longValue() | Value as a long |
CpdDouble | double doubleValue() | Value as a double |
CpdStatData | double mean() | Mean of the sample set |
int count() | Element count | |
double sumSquares() | Sum of squares of the elements | |
double variance() | Variance | |
double standardDeviation() | Standard deviation | |
double confidence(int level) | Confidence interval of the mean | |
CpdLoad | double mean() | Time-weighted average value |
double getCurrentLevel() | Last data point | |
long getWeight() | Measured time period |
The getValue method retrieves the value and, if possible, converts it to a double value. If it cannot make the conversion, it returns Double.NaN. The values returned by getValue can be used for displaying and graphing data.
The getTime method returns the server time associated with the data.
The delta method takes the current value and a previous value of a piece of data, and returns an object that represents the change between the values. The delta method also returns a deltaTime value, which represents the time associated with the delta value and the current value of the data. The delta method is defined for all objects listed in Table 1. For CpdStatData, the delta between two values provides the statistics on all members of the current sample set, not on members of any previous set. The delta method is also defined for groups. For two groups, g1 and g2, the object returned by the statement g1.delta(g2) is a group whose members include all members common to both g1 and g2. For each member m1 of group g1 with a corresponding value of m2 in g2, the corresponding delta value is represented by m1.delta(m2).
The rate method returns the rate of change. This method is defined for the CpdInt, CpdLong, and CpdDouble types. If the rate cannot be calculated (for instance, if the method is used with the CpdStatData or CpdLoad types), the original value is returned.
For the CpdLoad object, the mean method returns the time-weighted average of the value being tracked. It is computed by dividing the integral value by the delta time. If the delta time is 0 (zero), the difference between the object's current time and its creation time is used.
The PmiClient class is used by clients to access performance data. It looks up session beans and invokes remote APIs, thus freeing the programmer from having to implement these tasks manually. A client can create an instance of PmiClient and call all subsequent methods on that object. The PmiClient object converts wire-level data to a client-side data collection hierarchy and exports methods for clients to create PerfDescriptor objects if the objects' names are known. If you know the static names for the node, server, module, instance, or data, you can call pmiClient.createPerfDescriptor to obtain the PerfDescriptor. Otherwise, you can get the names by issuing the listNodes, listServers, and listMembers methods on PmiClient. Be careful when calling method setInstrumentationLevel. This method will change the level at the server side. It means it will affect other clients monitoring the same server.
The definition of PmiClient is as follows:
public class PmiClient { // Constructor: lookup PerfRetrieve session bean home and create an bean object. // Take care of all the initilization (e.g., get config files). // default is localhost with 900 port number // default jndi name for perfRetrieveHome is "PerfRetrieveHome" PmiClient() throws RemoteException; PmiClient(String hostName) throws RemoteException; PmiClient(String hostName, String port) throws RemoteException; // the top level collection of the data hierarchy tree CpdCollection createRootCollection(); // The following methods serve as wrapper methods for the remote methods // in PerfRetrieve so that users do not need to worry about remote APIs or // wire level data // list all the nodes in the domain, //call PerfDescriptorInstance.getName() to get the node names PerfDescriptor[] listNodes() throws PmiException; // list all the servers in a specific node - pd is the one returned from listNodes // call PerfDescriptorInstance.getName() to get the server names PerfDescriptor[] listServers(String nodeName) throws PmiException; PerfDescriptor[] listServers(PerfDescriptor pd) throws PmiException; // list the perf members in a server. // The returned PerfDescriptor can be passed for next listMembers call until it // returns null (ie, we have reach the leaf node). // Call PerfDescriptorInstance.getName() to get the current member name PerfDescriptor[] listMembers(PerfDescriptor pd) throws PmiException; // Support for RA to get the admin state of nodes and servers // Those admin states will be updated and cached when // listNodes/Servers/Members are called int getAdminState(String nodeName) throws PmiException; int getAdminServerState(String nodeName, String serverName) throws PmiException; // Get module configs - contains all the static info for data // See Chapter 2 for PmiModuleConfig PmiModuleConfig[] static getConfigs() throws PmiException; PmiModuleConfig[] static getConfigs(String nodeName) throws PmiException; PmiModuleConfig static getConfig(String moduleID) throws PmiException; // add PerfDescriptor to PmiClient and call gets() later to retrieve data void add(PerfDescriptor pd); // Retrieve perf data. // There are different mode: single pd vs an array of pds // recursive vs non-recusive // recursive means getting data for each subgroup instead of aggregate data CpdCollection get(PerfDescriptor pd, boolean recursive) throws PmiException; CpdCollection[] gets(PerfDescriptorList pds, boolean recursive) throws PmiException; CpdCollection[] gets(PerfDescriptor[] pds, boolean recursive) throws PmiException; CpdCollection[] gets(boolean recursive) throws PmiException; // set/get Instrumentation level. // Note that this will change the level setting at app server - it may impact other PMI // clients that retrieve PMI data from the app server at the same time public PerfLevelSpec[] getInstrumentationLevel(String nodeName, String serverName) ; public void setInstrumentationLevel(String nodeName, String serverName, PerfLevelSpec[] specs, boolean recursive) // convert data ID and name public static String getDataName(String moduleID, int dataId); public static int getDataId(String moduleID, String name); // methods to create a PerfDescriptor - used when a user knows the static names public static PerfDescriptor createPerfDescriptor() { public static PerfDescriptor createPerfDescriptor(String[] dataPath); public static PerfDescriptor createPerfDescriptor(String[] dataPath, int dataId); public static PerfDescriptor createPerfDescriptor(String[] dataPath, int[] dataIds); public static PerfDescriptor createPerfDescriptor(PerfDescriptor parent, String name); public static PerfDescriptor createPerfDescriptor(PerfDescriptor parent, int dataId) ; public static PerfDescriptor createPerfDescriptor(PerfDescriptor parent, int[] dataIds) ; // Create PerfLevelSpec public PerfLevelSpec createPerfLevelSpec(String[] dataPath, int level) ; public PerfLevelSpec createPerfLevelSpec(int level) ; // for the whole app server // APIs accepts a fully qualified String seperated by "/". // For example, nodeName/serverName/moduleName/instanceName. // Note: data name cannot be in qualifiedPath. You have to pass a separate dataId if // you need a data level perf descriptor. public PerfDescriptor createPerfDescriptor(String qualifiedPath); public PerfDescriptor createPerfDescriptor(String qualifiedPath, int dataId); } // Retrieve performance data in XML format String getXML(PerfDescriptor pd, boolean recursive); String getXML(PerfDescriptor pd, boolean recursive, int time); String getXML(PerfDescriptorList pds, boolean recursive); String getXML(PerfDescriptorList pds, boolean recursive, int time); // Convert data ID and name public static String getDataName(String moduleID, int dataId); public static int getDataId(String moduleID, String name); // Methods to create a PerfDescriptor, used when you know // static names public PerfDescriptor createPerfDescriptor(){ public PerfDescriptor createPerfDescriptor(String[] dataPath); public PerfDescriptor createPerfDescriptor(String[] dataPath, int dataId); public PerfDescriptor createPerfDescriptor(String[] dataPath, int[] dataIds); public PerfDescriptor createPerfDescriptor(PerfDescriptor parent, String name); public PerfDescriptor createPerfDescriptor(PerfDescriptor parent, int dataId); public PerfDescriptor createPerfDescriptor(PerfDescriptor parent, int[] dataIds); } } |
The PMI client package provides event and listener interfaces to inform clients (for instance, a GUI display) when new or changed data is available. The CpdEventObject interface, which extends java.util.EventObject, is the parent to the PMI event and listener interfaces. The CpdEventListener interface, which extends CpdEventObject, is the interface that objects need to implement to receive performance data events. Objects can use the addListener method to register as event listeners. The definition of the method is as follows:
void addListener(CpdEventListener listener);
The definitions of the CpdEventListener and CpdEvent interfaces are as follows:
public interface CpdEventListener { public void CpdEventPerformed(CpdEvent evt); } public class CpdEvent { final static int EVENT_NEW_MEMBER = 0; final static int EVENT_NEW_SUBCOLLECTION = 1; final static int EVENT_NEW_DATA = 2; private int type; private Object source = null; public CpdEvent(Object source, int type); public CpdEvent(int type); public Object getSource(); public int getType(); } |
The PMI client package provides event and listener interfaces to inform clients (for instance, a GUI display) when new or changed data is available. The CpdEventObject interface, which extends java.util.EventObject, is the parent to the PMI event and listener interfaces. The CpdEventListener interface, which extends CpdEventObject, is the interface that objects need to implement to receive performance data events. Objects can use the addListener method to register as event listeners. The definition of the method is as follows:
void addListener(CpdEventListener listener);
The definitions of the CpdEventListener and CpdEvent interfaces are as follows:
public interface CpdEventListener { public void CpdEventPerformed(CpdEvent evt); } public class CpdEvent { final static int EVENT_NEW_MEMBER = 0; final static int EVENT_NEW_SUBCOLLECTION = 1; final static int EVENT_NEW_DATA = 2; private int type; private Object source = null; public CpdEvent(Object source, int type); public CpdEvent(int type); public Object getSource(); public int getType(); } |
The PMI client provides the CpdFamily class to simplify displaying data in a table. When two data objects have the same module identifier, they are in the same family and can be displayed in the same table by using this class. The definition of CpdFamily is as follows:
public class CpdFamily { static public boolean isSameFamily(CpdData d1, CpdData d2); static public boolean isSameRow(CpdData d1, CpdData d2); static public boolean isSameColumn(CpdData d1, CpdData d2); static public boolean getRow(CpdData d1); static public boolean getColumn(CpdData d1); static public boolean getFamilyName(CpdData d1); } |
This section discusses the use of the PMI client interfaces in applications. The basic programming model is as follows:
Snapshot.update(S1); // ...later... Snapshot.update(S2);
import com.ibm.websphere.pmi.*; import com.ibm.websphere.pmi.server.*; import com.ibm.websphere.pmi.client.*; public class PmiTest implements PmiConstants { // A test driver // If arguments are provided: // args[0] = node name // args[1] = port number // args[2] = The JNDI name of PerfRetrieve // // Note: This will not work unless an administrative server is running // public static void main(String[] args) { String hostName = null; String portNumber = null; String homeName = null; if (args.length >= 1) hostName = args[0]; if (args.length >=2) portNumber = args[1]; if (args.length >=3) homeName = args[2]; PmiClient pmiClnt = new PmiClient(hostName, portNumber, homeName); // Root of PMI data tree CpdCollection rootCol = pmiClnt.createRootCollection(); // Set performance descriptor (pd) list // pdList will include all PerfDescriptors for data retrieval PerfDescriptorList pdList = new PerfDescriptorList(); try { // If you want to query PmiClient to find the PerfDescriptor // you need, you can go through listNodes, listServers, and // listMembers to list all the PerfDescriptors and extract // the one you want. PerfDescriptor[] nodePds = pmiClnt.listNodes(); String nodeName = nodePds[0].getName(); System.out.println("after listNodes:" + nodeName); PerfDescriptor[] serverPds = pmiClnt.listServers( nodePds[0].getName()); System.out.println("after listServers"); if (serverPds == null || serverPds.length == 0) { System.out.println("NO app server in node"); return; } // For a simple test, get from the first server PerfDescriptor[] myPds = pmiClnt.listMembers(serverPds[0]); // You can add all pds to PerfDescriptorList for (int i = 0; i < myPds.length; i++) { if (myPds[i].getModuleName().equals( "com.ibm.websphere.pmi.beanModule") || myPds[i].getModuleName().equals( "com.ibm.websphere.pmi.connectionPoolModule") || myPds[i].getModuleName.equals( "com.ibm.websphere.pmi.webAppModule")) pdList.addDescriptor(myPds[i]); } // Or, if you know the data path you want, you can create your own String[] thisPath = new String[]{"thisNode", "thisServer", "transactionModule"}; // Suppose you are interested only in dataIds 1, 2, and 3 PerfDescriptor thisPd = pmiClnt.createPerfDescriptor(thisPath, new int[]{1, 2, 3}); pdList.addDescriptor(thisPd); } catch (Exception ex) { System.out.println("Exception calling CollectorAE"); ex.printStackTrack(); } // Retrieve the data in pdList CpdCollection[] cpdCols = null; try { for (int i = 0; i < 10; i++) { java.lang.Thread.sleep(1000); cpdCols = pmiClnt.gets(pdList, true); if (cpdCols == null || cpdCols.length == 0) { System.out.println( "PMI data return null--possible wrong pds"); } for (int j = 0; j < cpdCols.length; j=++) { rootCol.update(cpdCols[j]); report(cpdCols[j]); } } } catch (Exception ex { System.out.println("Exception to call thread sleep"); } } // Simple method to make sure we are getting the correct CpdCollection private static void report(CpdCollection col) { System.out.println("\n\n"); if (col == null) { System.out.println("report: null CpdCollection"); return; } System.out.println("report--CpdCollection "); printPD(col.getDescriptor()); CpdData[] dataMembers = col.dataMembers(); if (dataMembers != null) { System.out.println("report CpdCollection: dataMembers is " + dataMembers.length); for (int i = 0; i < dataMembers.length; i++) { CpdData data = dataMembers[i]; printPD(data.getDescriptor()); } } CpdCollection[] subCollections = col.subcollections(); if (subCollections != null) { for (int i = 0; i < subCollections.length; i++) { report(subCollections[i]); } } } // Simple method to write the full name of a pd private static void printPD(PerfDescriptor pd) { System.out.println(pd.getFullName()); } } |