In Part 2 of this article series, we learned how WebSphereTM Application Server V5 Systems Management has at its core a JavaTM Management Extentions (JMX) server that provides a standard interface to manage the application server. In Part 3, we will describe in detail how to handle notifications, with emphasis on using notifications to determine when servers are started and stopped.
To show a real example of how notifications can be used, we present a Swing-based administrative client which allows you to start and stop servers, as well as monitor their current state. It also shows all the notifications which are being emitted from various parts of the system. We will first describe how to run the system, and in the following sections explain how it works. The source code can be obtained from the download section at the bottom of this article. (The program requires WebSphere Application Server V5.0.1 or later, and you must use the version of Java that ships with WebSphere.)
To run the program,
download
the
servermanager.jar
file in a location such as
c:\temp
, set your classpath as shown below, and start the
WebSphereServerManager
:
set CLASSPATH=%WAS_HOME%\lib\admin.jar;%WAS_HOME%\lib\wasjmx.jar;%WAS_HOME%\lib\
namingclient.jar; %WAS_HOME%\lib\txClientPrivate.jar;%WAS_HOME%\properties;c:\temp\servermanager.jar
%WAS_HOME%\java\bin\java WebSphereServerManager <hostname> <portnumber> <conntype>
The three parameters after the program name (
WebSphereServerManager
) contain the information needed to connect to a standalone server (for a WebSphere Application Server Base installation) or a deployment manager (in a WebSphere Application Server Network Deployment installation):
-
The hostname to connect to (for example,
localhost). -
The port to connect to (Using the RMI connector:
2809for Base or9809for Network Deployment. Using the SOAP connector:8880for Base or8879for Network Deployment). -
The connector type to use,
RMIorSOAP;RMIis recommended as explained below .
After the program is started, the first thing to do is add a server by right-clicking on the WebSphere node to bring up a pop-up menu. If running a standalone installation, select Add server and enter the name of the server you connected to (for example,
server1
). After you add the server, you should see that the current state of the server is RUNNING (Figure 1). On the top right pane, you will see the type of each notification which this server has received. Since there are no processes sending notifications to the server, it contains only those that have originated from the server. If you select one of the notifications, all the information from that notification is displayed in the bottom right pane.
Figure 1: WebSphere Server Manager in a Base installation
In a standalone installation, notifications are not often emitted. To get a sample notification to be sent, use the
wsadmin
utility to enter these commands:
wsadmin> set notificationService [$AdminControl queryNames type=NotificationService,*]
wsadmin> $AdminControl invoke $notificationService emitNotification
{test.sample.notification "This is my notification"}
In a Network Deployment installation, instead of selecting Add server you would select Add cell and provide the name of your cell. From there you would pop-up the menu on the cell and select Add node and provide the name of your node. Finally, select Add server from the node and provide the name of your server (Figure 2). You should get three notifications every minute if you have not modified the default node synchronization interval.
Figure 2. WebSphere Server Manager is a Network Deployment installation
You can also start and stop servers from the pop-up menu. This changes the state of the server as displayed in the server tree, and also shows all of the notifications which are emitted. Note that you can only start a managed process, since there is no MBean interface to start deployment managers, node agents, or unmanaged processes.
Information on starting and stopping servers can be found in
Part 2
. In the example code, the
ServerManager
class starts and stops a particular server. You can see that approximately the same code was used in
Part 2
for the
getNodeAgentMBean
method. The code to launch the process uses an overloaded
invokeLaunchProcess
operation that accepts an
Integer
for the amount of time to wait until the server is
launched. We pass zero (0) for this value because we
will be using notifications to determine when the
server is actually running; this ensures that the
client does not become inactive while starting the
server.
String opName = "launchProcess";
String signature[] = { "java.lang.String", "java.lang.Integer" };
Object params[] = { serverName, new Integer(0) };
Boolean b = (Boolean) adminClient.invoke(getNodeAgentMBean(), opName,
params, signature);
The
invokeStop
method stops the server by invoking the
stop
operation on the Server MBean:
private void invokeStop() throws Exception {
// Use the stop operation on the Server MBean to stop
// the given server
String opName = "stop";
String signature[] = null;
String params[] = null;
adminClient.invoke(getServerMBean(), opName, params, signature);
}
To start the server, the
launchProcess
operation is invoked on the NodeAgent MBean, but to stop a server, you invoke the
stop
operation on the Server MBean you would like to stop. The
ServerManager
class can only start ManagedProcesses (there is no way to start other servers with JMX), but you can stop any type of server.
The
launchProcess
operation can be performed synchronously or asynchronously, but the
stop
operation is always asynchronous. This leads to the problem of not knowing when the process is fully stopped. One way of finding out could be to periodically search for the Server MBean, and when it cannot be found, the process is stopped. However, we can solve this problem with event notifications.
When certain events occur in the system, notifications are emitted to all listeners. Listeners can be registered in the same process as the server or in a remote process on the same or different machine. Registering a listener on a remote process simply requires obtaining an AdminClient and calling the
addNotificationListener
method. The following is an example which would
listen to all the error and warning messages from
server1:
1 ObjectName queryMBean = new ObjectName("WebSphere:type=RasLoggingService,process=server1,*");
2 // ... initialize adminClient ...
3 ObjectName rasMBean = (ObjectName) adminClient.queryNames(queryMBean, null).iterator().next();
4
5 NotificationListener listener = new NotificationListener() {
6 public void handleNotification(Notification n, Object handback) {
7 System.out.println("Got notification: " + n);
8 }
9 };
10
11 NotificationFilterSupport filter = new NotificationFilterSupport();
12 filter.enableType(NotificationConstants.TYPE_RAS_FATAL);
13 filter.enableType(NotificationConstants.TYPE_RAS_ERROR);
14
15 Object myHandback = null;
16
17 adminClient.addNotificationListener(rasMBean, listener, filter, myHandback);
In the above code:
- Line 17 performs the listener registration. It accepts four parameters, the last two of which are optional. These parameters are initialized in the preceding lines.
-
Lines 1-3 create an
ObjectNamefor theRasLoggingServiceMBean. A notification is emitted from a particular MBean, called the source . In this case, we want to listen to notifications whose source is theRasLoggingServiceon server1. An AdminClient is initialized as described in Part 2 . -
Lines 5-9 create an implementation of the class
NotificationListener, which has a singlehandleNotificationmethod. This method is called when a notification is emitted. The first parameter is theNotificationobject which was emitted, and the second is the handback , an opaque object which can be used if some sort of context is needed. The exact handback object passed during listener registration is passed on eachhandleNotificationcall for the registered listener. -
Lines 11-13 create a standard implementation of the
NotificationFilterinterface, an optional parameter for listener registration. Only notifications which the filter allows are passed to the listener. TheNotificationFilterSupportclass allows you to filter notifications based on type ; in this case, onlywebsphere.ras.fatalandwebsphere.ras.errornotifications are accepted. The WebSphere-provided classNotificationConstantscontains useful constants for notifications. - Line 15 initializes the handback object, which is the same object passed on line 6. In this case we don't need a handback object, so we use null.
To register a notification listener in the server process, you could use a servlet and perform the same general steps as above. However, the
AdminService
class is used instead of an AdminClient.
Removing a listener involves a similar call:
adminClient.removeNotificationListener(rasMBean, listener);
Here we pass the same ObjectName and listener which we used to register the listener.
We have already mentioned two attributes that a notification contains: a source and type. Although these are by far the two most useful pieces of information, there are others. The following is a list of the attributes a notification contains; although you cannot access them directly as attributes, they all have Get methods:
source:
|
The MBean which the notification was emitted from; this is always an
ObjectName
when using the AdminClient or AdminService classes, but can be a reference to an actual MBean if registering with the internal MBeanServer (not covered here).
|
type:
|
The type of a notification is an ordered set of dot-separated strings, generally hierarchical in nature. Notifications defined by WebSphere Application Server always begin with "
websphere.
" or "
ws.
", while notifications defined by the JMX infrastructure begin with "
jmx.
". When using the
NotificationFilterSupport
, you can enable a type prefix to receive all notifications with that type. For example, if we had wanted to listen to ALL notifications which begin with
websphere.ras
, we could have just passed
NotificationConstants.TYPE_RAS
(which resolves to "
websphere.ras
").
|
sequenceNumber:
|
All notifications have a sequence number, which is of type
long
. This can be used for sorting notifications in the proper order, since the notification model does not guarantee order (although they generally are).
|
timeStamp:
|
The time in milliseconds that the notification was emitted, represented by the number of milliseconds since January 1, 1970 00:00:00 (the same as
System.currentTimeMillis()
).
|
message:
| An optional message which may describe the notification in detail. The majority of WebSphere Application Server notifications do not contain a message. |
userData:
|
An optional Object which may contain additional data in the notification. Many WebSphere Application Server notifications have a userData object; often this is a Properties object, but this also is not a rule (for example,
websphere.ras
notifications contain a
com.ibm.ejs.ras.MessageEvent
object).
|
WebSphere Application Server notification enhancements
Extended Listener Registration
The standard JMX way to add listeners has limitations. One is that the MBean must be present on the system to add a listener to it. Another is that if you want to add a listener to multiple MBeans, you have to register multiple times. WebSphere Application Server provides additional registration methods which allow you to do both of these:
void addNotificationListenerExtended(ObjectName name,
NotificationListener listener, NotificationFilter filter,
Object handback);
void removeNotificationListenerExtended(NotificationListener listener);
As you can see, the parameters passed on the
registration are the same. However, the value you can
pass as the
name
parameter is different; instead of passing a full ObjectName, you can pass a partial ObjectName which uses the same syntax as that in
queryNames
. So for the example above, instead of passing
rasMBean
into
addNotificationListener
, we could have directly passed the partial
queryMBean
ObjectName into
addNotificationListenerExtended
, saving the
queryNames
call.
The other advantage of the extended registration method is that it will add listeners to MBeans which do not yet exist. So if a listener was registered to a set of MBeans, additional MBeans added to that same set would have the listener automatically added to it. It follows that you could pass a partial ObjectName which does not resolve to anything yet to
addNotificationListenerExtended
, and when that MBean gets activated, you will immediately receive notifications; if this was passed to
addNotificationListener
, an
InstanceNotFoundException
would be thrown.
The listener removal method is slightly different from the standard remove method, in that it does not take an
ObjectName
. Instead, all MBeans which were added with that particular listener will be removed. The different API is to make it clear that you cannot add a listener to a set of MBeans, and then remove the listener from a subset of those MBeans.
It is important to be aware that the
removeNotificationListenerExtended(NotificationListener)
method will be deprecated in a future release. In its place is a remove that exactly matches the standard remove method (it accepts an ObjectName and NotificationListener). This allows you to add a listener on two sets of MBeans (with two
addNotificationListenerExtended
calls) and remove it from only one set. It does NOT, however, allow you to remove the listener from a subset of the MBeans you added it to; the ObjectName given on remove must be exactly the same as that given on add. In this way it is more consistent with the standard add/remove listener operations.
Notifications in a Network Deployment installation
By itself, an application server only emits notifications to listeners registered locally (another MBean, for example) and clients registered remotely, as described above. In a Network Deployment installation however, all notifications from the application server are also sent to the node agent on the same machine. In the same way, all notifications in the node agent are sent to the deployment manager. We say that notifications are "propagated to the upstream server", as illustrated in Figure 3; arrows represent notifications which flow to the upstream server. This is an incredibly useful addition, as it allows you to register a single notification listener with the deployment manager to get notifications from MBeans on remote servers.
Figure 3. Notification flow for a Network Deployment installation
In WebSphere Application Server Version 5.0.1, notifications are not actually propagated upstream unless a listener is added. So if there is no listener for a particular notification, it will not actually be propagated. There is no external difference between the notifications emitted in Versions 5.0 and 5.0.1, although network traffic is reduced in Version 5.0.1.
The WebSphere Server Monitor application presented in this article subscribes to all notifications in a particular server, cell or node. The purpose for this is to allow you to see all the notifications which are being emitted. This should not be done in a production cell, as it causes ALL notifications from ALL servers to be sent to the deployment manager. As nodes are added, this can begin to swamp your network with all the notifications flowing. However, for the purpose of our example it is useful to illustrate all the notifications emitted.
The
ServerMonitor
object is created when a cell, node, or server object is added to the tree. One of its purposes is to register for all notifications which occur on that cell, node, or server. It does this in the
addListener
method:
private void addListener() throws ConnectorException {
ac.addNotificationListenerExtended(getMBeansListenedTo(),
this, null, null);
}
private ObjectName getMBeansListenedTo() {
if (mbeansListenedTo == null) {
StringBuffer buf = new StringBuffer();
buf.append("WebSphere:*");
if (cellName != null) {
buf.append(",cell=");
buf.append(cellName);
}
if (nodeName != null) {
buf.append(",node=");
buf.append(nodeName);
}
if (serverName != null) {
buf.append(",process=");
buf.append(serverName);
}
try {
mbeansListenedTo = new ObjectName(buf.toString());
} catch (MalformedObjectNameException exc) {
// ignore
}
}
return mbeansListenedTo;
} |
The main part of this code is simply to create the
partial MBean
ObjectName
. If listening to a cell, only the
cellName
attribute will be set, and so we might listen to
WebSphere:*,cell=mycell
; since there is always exactly one cell, this matches all notifications emitted from the system. If listening to a server, all attributes will be set, so we might listen to
WebSphere:*,cell=mycell,node=mynode,process=server1
; this will match all notifications emitted from
server1
running in the
mynode
node. The listener registration itself is very simple, passing
this
as the
NotificationListener
. Which means that
this object
implements the
handleNotification
method:
public void handleNotification(Notification n, Object handback) {
listModel.addElement(n);
}
All notifications simply get added to
listModel
, an instance of
NotificationListModel
. This class has three purposes:
- Limit the number of notifications we save to 100.
-
Extend the
javax.swing.DefaultListModelclass to make the job of displaying notifications easy. -
Wrapper each notification in a
NotificationWrapper. The reason for this is that thetoStringimplementation in theNotificationclass does not display the type of the notification, which is arguably the most important part. So we override that method with an implementation which returns the notification's type and the time at which we received the notification.
This class also provides a method
toDetailedString
which returns a String containing all the data in
the notification:
public String toDetailedString() {
StringBuffer buf = new StringBuffer();
buf.append("type = " + n.getType() + "\n");
buf.append("message = " + n.getMessage() + "\n");
buf.append("source = " + n.getSource() + "\n");
buf.append("seqNum = " + Long.toString(n.getSequenceNumber()) + "\n");
buf.append("timeStamp = " + new Date(n.getTimeStamp()) + "\n");
buf.append("userData = " + n.getUserData() + "\n");
if (n.getUserData() instanceof MessageEvent) {
buf.append(" (MessageEvent = " +
((MessageEvent) n.getUserData()).
getLocalizedMessage(Locale.getDefault()) + ")\n");
}
return buf.toString();
} |
Note that for
websphere.ras
notifications which contain a
MessageEvent
as the userData, we invoke the
getLocalizedMessage
simply to display a readable version of the actual notification data.
Using notifications to monitor servers
We now have enough knowledge to be able to monitor servers. First, we describe what notifications are actually emitted when a server is started and stopped:
-
When a server is starting, the Server MBean emits a
j2ee.state.startingnotification. -
When it is completely started, it emits a
j2ee.state.runningnotification. -
When a
stopoperation is issued, aj2ee.state.stoppingnotification is emitted. -
When it is completely stopped, it emits a
j2ee.state.stoppednotification.
In a Network Deployment environment, the "parent" server emits certain notifications on behalf of the "child" server. When an application server (child) starts, the NodeAgent MBean (parent, running in the node agent process) usually emits a
websphere.process.starting
notification. It also emits
websphere.process.running
,
websphere.process.stopping
, and
websphere.process.stopped
notifications shortly after the application server emits the
j2ee.state
notifications. In the same way, the DeploymentManager MBean (running in the deployment manager process) emits
websphere.process
notifications when the node agent starts or stops. The
userData
attribute contains a Properties object which contains the name of the process started (key
NotificationConstants.KEY_PROCESS_NAME
), and for the node agent, the name of the node (key
NotificationConstants.KEY_NODE_NAME
). Table 1 shows the notifications which WebSphere Application Server emits (additional notifications might be added, so this may not be a complete list).
| MBean type | Notifications emitted | When emitted |
| ApplicationManager |
websphere.admin.appmgmt
| An application is installed or uninstalled |
| Cluster |
websphere.cluster
| Cluster is starting, running, stopping or stopped |
| Cluster |
websphere.cluster.partial
| Some cluster members are running, some are not |
| ConfigRepository |
websphere.repository
| Changes made to config repository |
| DeploymentManager |
websphere.process
| Node agent starting, running, stopping or stopped |
| Discovery |
websphere.discovery.agent
*
| Upstream process is added or removed |
| Discovery |
websphere.discovery.process
*
| Downstream process is added or removed |
| NodeAgent |
websphere.process
| Managed process starting, running, stopping or stopped |
| NodeSync |
websphere.nodesync
| Node synchronization is started or completed |
| NotificationService |
websphere.addnode
or
.removenode
| Messages emitted during addNode or removeNode |
| RasLoggingService |
websphere.ras
| All messages added to activity log |
* These notifications are only used internally by WebSphere Application Server; they should not be used by other external software products
It was stated earlier that the
websphere.process.starting
notification is usually emitted. Whether this notification is emitted or not depends on how the server was started. If the
launchProcess
operation was used to start the process, the
websphere.process.starting
notification is always emitted. If the startServer command is used to start the process, the
websphere.process.starting
notification is not emitted. Since the only way to start the node agent is with the startNode command, a
websphere.process.starting
notification is never emitted from the DeploymentManager MBean.
The reason for sending these notifications becomes apparent when you think about timing issues. You cannot add a listener before a server is completely started. Only after it is running can you add a listener to that server, and at that point the
j2ee.state.starting
and
running
notifications have already been emitted. Similarly, if you have a listener already registered, you might receive a
stopping or stopped
notification, depending on how fast the server actually stops (remember notifications are asynchronous). By registering a listener on the upstream server, you can be assured that you will receive notification when a downstream server is started or stopped.
In the sample code, the
StateMonitor
class monitors when servers are started and stopped. To monitor a managed application server (in Network Deployment) or node agent, the class uses the
websphere.process
notifications, since they are more reliable than
j2ee.state
notifications. To monitor an unmanaged application server (Base) or deployment manager, it uses the
j2ee.state
notifications because
websphere.process
notifications are unavailable. Some
interesting points:
-
The
determineCurrentStatemethod determines if the server is currently running or stopped, based on the existence of the Server MBean: if it finds the MBean, then it is running; if not, then it is stopped. Note that if the server is not defined, it will still be considered stopped. -
The
monitor Process_Type Processadds the listener to the appropriate MBean (the server if listening toj2ee.statenotifications, or the upstream process MBean if listening towebsphere.processnotifications). We use the extended add method so that we can listen to a server even if it is currently stopped (in which case the MBean is not yet activated). -
Two methods are used to create the filter:
createJ2EEStateFilterandcreateWebSphereProcessFilter. It is usually best to pass a filter during registration, even if the current implementation only emits a certain type of notification. This protects you from unknown notifications which could be implemented in the future, and that your program might not be able to handle. Note that we use the constants defined inNotificationConstantshere. -
The
handleNotificationmethod delegates to two other methods, based on what type of process we are monitoring. ThehandleWebSphereProcessNotificationmethod is noteworthy, in that since a particularServerMonitorcould receive a notification for a server it was not monitoring for, we need to decide if the notification is important based on theuserDataattribute. Only if the name (server name or node name) matches the server form we are monitoring do we continue and actually change state.
At the beginning of this article, we suggested using the RMI connector to run the WebSphere Server Manager instead of the SOAP connector. This requires some explanation. The SOAP connector has the advantage of having a better chance of making it through a firewall (since it is HTTP traffic) than RMI/IIOP. If there is a firewall in your installation, you will need to use SOAP instead of RMI. However, you will generally receive notifications faster with RMI than with SOAP. This is because the RMI uses a "push" model while SOAP uses a "pull" model.
When the RMI connector is used, a remote object is created on the client side and on the stub passed to the server side. Whenever a notification is received on the server, it is almost immediately sent (or "pushed") to the client and handed to the registered listeners. Unfortunately, this is not allowed with SOAP, as HTTP is a request/response protocol. With SOAP, at regular intervals, the client requests any notifications from the server for this listener. If there are any, they are returned from (or "pulled" from) the server and then handed to the listeners. This occurs approximately every 20 seconds, but can be more frequent if a large number of notifications are being received.
Since notifications can take up to 20 seconds to be received when using the SOAP connector, it is recommended that the RMI connector be used to receive notifications, when possible. To see the actual difference in times, you can run the sample code with both the SOAP and RMI connector and compare the results. The time the notification is received on the client is displayed on the top right pane, and the time the notification was actually sent is displayed on the bottom right pane, as seen in Figures 1 and 2. By comparing these two values, you will get an idea of how long notifications take to be received.
Emitting your own notifications
Notifications are always emitted from MBeans. This generally means that to send a notification, you would need to create your own MBean and register it with the MBeanServer. (Registering your own MBeans will be described in Part 4 of the article series.) However, there is a way to send notifications without actually writing an MBean. This is done using the NotificationService MBean which exists on each server.
The NotificationService MBean contains an operation which allows client processes to emit notifications. By invoking the
emitNotification
method, a client can specify the type of notification, and optionally a message and userData, to be sent by the NotificationService MBean. The source of the MBean cannot be specified; it is always the NotificationService MBean itself. The following code uses the
emitNotification(String notificationType, String message)
operation to emit a notification:
ObjectName queryMBean = new ObjectName("WebSphere:type=NotificationService,process=server1,*");
// ... initialize adminClient ...
ObjectName notifMBean = (ObjectName) adminClient.queryNames(queryMBean, null).iterator().next();
String notificationType = "mycompany.myresource.myevent";
String message = "An event from myresource has occurred";
Object[] params = new Object[] { notificationType, message };
String[] paramTypes = new String[] { "java.lang.String", "java.lang.String" };
adminClient.invoke(notifMBean, "emitNotification", params, paramTypes);
WebSphere Application Server uses this method internally to allow the admin console to display the status of
addNode
or
removeNode
commands. Each message which is displayed on the console is actually a notification emitted from the command.
Another operation on the NotificationService MBean is
propagateNotifications
. This is used internally by downstream servers to propagate notifications to upstream servers. It should not be used by other applications.
In this article we learned about the WebSphere Application Server notification system, and how you can register to receive notifications of events which occur on your system. We also examined a program with which you can start and stop servers and monitor their progress, as well as view all the notifications sent through the system. With this knowledge, you are well on your way to being able to develop nearly any management application which exists outside a server. In Part 4, Leigh Williamson will describe how you can write your own MBeans to extend the WebSphere Application Server itself.
| Name | Size | Download method |
|---|---|---|
| servermanager.jar | 0.1 MB | FTP |
| servermanager-src.jar | 0.1 MB | FTP |
Information about download methods
-
WebSphere Application Server V5 InfoCenter
- WebSphere Application Server javadoc
- JMX javadoc (from Tivoli's TMX4J JMX implementation)
- WebSphere MBean javadoc
-
Java Management Extensions home page
-
Tivoli TMX4J JMX implementation
-
JMX articles:
-
JMX books:
- Java and JMX: Building Manageable Systems
- JMX: Managing J2EE with Java Management Extensions
- Java Management Extensions
Shawn Lauzon is a software engineer at IBM in the WebSphere Systems Management area in Austin, Texas. He wrote the implementation of the Notification Service for WebSphere Application Server Version 5.0. Previously, he worked on WebSphere Connection Pooling and Business Rule Beans. You can contact Shawn at lauzon@us.ibm.com.





