InfoCenter Home >
9: Tuning the product >
9.2: Performance monitoring infrastructure client package
9.2: Performance monitoring infrastructure client package
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.
PmiTester
The following instructions step you through how to run PmiTester on the machine where WebSphere Application Server is installed:
- Start the administrative server and application server.
- Set the performance level(s) through the administrative console or Resource Analyzer.
- Run the following script on Windows NT. (%1 is the machine where the administrative server is running and
%2 is the port number):
call %~dp0setupCmdLine.bat
%JAVA_HOME%\bin\java-Xminf0.15 -Xmaxf0.25-
Dws.ext.dirs=%WAS_HOME%/classes;%WAS_HOME%/lib/ext;%WAS_HOME%/lib;%WAS_HOME%/web/help;%WAS_HOME%/properties%CLIENTSAS% -Dserver.root=%WAS_HOME% -jar
%WAS_HOME%/lib/bootstrap.jar com.ibm.websphere.pmi.PmiTester %1%2
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.perfServer.*;
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 organization and implementation
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.
Statistical data on a sample space consists of the
number of elements in the sample set, the sum of the elements, and the sum of
squares. These values can be used to obtain the mean, the variance and
the standard deviation of the mean. An example of statistical data is
the response time for each invocation of an enterprise bean.
Load data monitors a value as a function of time.
Example uses include tracking the number of threads or the number of service
requests in a queue. Load data tracks the current value, the time the
value was reached and the integral over time of the value. These
values can be used to obtain the weighted average for the level over a period
of time. An example of load data is the average size of a database
connection pool during a specified time interval.
Group data is a collection of performance data intended to be
used by groups. It enables servers to create sets of performance data
that can be retrieved by clients with a single call.
How data is organized
Data is organized by modules. Each module has a configuration file in
extensible markup language (XML) format that determines its
organization. The configuration file lists a unique identifier for each
piece of performance data in the module. A client can use the
data's unique ID to retrieve the data's static information. The
server then sends the dynamic information associated with that data to the
client.
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.
PMI client interfaces
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.
How to use WSCP to set PMI
To learn more about WSCP, see the following information about WSCP usage.
PMI interfaces
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 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:
- If collection1 and collection2 represent the same
collection (that is, if they are instances of the same PerfDescriptor object,
with collection2 representing a more recent version of the
PerfDescriptor object than collection1), the update method performs
the following tasks:
- If any member of collection2 does not have a corresponding
member in collection1, the update method creates a child collection
of collection1 that contains the member from
collection2.
- For each member of collection2 that has a corresponding member
in collection1, the update method updates the member in
collection1 with the corresponding data in
collection2.
The update method then returns a value of true to the
caller.
- If collection1 and collection2 do not represent the
same collection, the update method performs the following tasks:
- For any member of collection1 that has a corresponding member
in collection2, the update method updates the member in
collection1 with the corresponding data in
collection2.
- If collection2 is a descendant of collection1, the
update method creates a child collection of collection1 and updates
each member of the child collection with the corresponding data in
collection2.
If neither of these conditions is met, the update method returns a value
of false.
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: Look up a PerfRetrieve session bean home and
// create a bean object. Do all initialization (that is,
// get all configuration 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 nodes in the domain, then 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 to the next listMembers call until it
// returns null (that is, when the leaf node is reached).
// 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 getAdminState(String nodename, String serverName) throws PmiException;
// Get module configurations, which contains all the static
// information for the 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 performance data.
//The following modes are available: single pd versus an array of pds
//Recursive versus nonrecursive
//recursive means getting data for each subgroup instead of aggregate data
CpdCollection get(PerfDescriptor pd, boolean recursive) throws PmiException;
CpdCollection[] get(PerfDescriptor pd, boolean recursive, int time);
CpdCollection[] gets(PerfDescriptorList pds, boolean recursive);
CpdCollection[] gets(PerfDescriptorList pds, boolean recursive,
int time);
// 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 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);
}
|
Using the PMI client interfaces
This section discusses the use of the PMI client interfaces in
applications. The basic programming model is as follows:
- A client uses the CpdCollection interface to retrieve an initial
collection, or snapshot, of performance data from the server. This
snapshot, which is called Snapshot in this example, is provided in
a hierarchical structure as described in Data organization and hierarchy, and contains the current values of all performance data
collected by the server. The snapshot maintains the same structure
throughout the lifetime of the CpdCollection instance.
- The client processes and displays the data as
specified. Processing and display objects (for example, filters and
GUIs) can register as CpdEvent listeners to data of interest; see The CpdEventListener and CpdEvent interfaces for details. When the client receives updated data,
all listeners are notified.
- When the client receives new or changed data, the client can simply display the new CpdCollection instance
through its hiearchy. When it is necessary to update the Snapshot collection, the client can use the update method to update Snapshot with the
new data.
Snapshot.update(S1);
// ...later...
Snapshot.update(S2);
- Step 2 and 3 are repeated through the lifetime of the
client.
Here is a list of sample PMI client code:
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 admin server and
// perfServer are 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",
"com.ibm.websphere.pmi.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());
}
}
|
|
|