Score big with JSR 77, the J2EE Management Specification

Standardize J2EE server management with JSR 77

The J2EE (Java 2 Platform, Enterprise Edition) specification should ease enterprise computing; we should be able to simply develop enterprise applications and deploy them into a J2EE-compliant product. But the reality is different because the J2EE specification does not go far enough. Many application server features are vendor specific, and, to avoid vendor lock-in, we need further standardization. One particular aspect of standardization is J2EE server management, an aspect covered by the J2EE Management Specification, Java Specification Request (JSR) 77. The J2EE Management Specification abstracts the manageable parts of the J2EE architecture and defines an interface for accessing management information. This helps system administrators integrate J2EE servers into a system management environment and also helps application developers create their own management tools.

In this article, I briefly introduce the Java Management Extension (JMX), the basis of JSR 77. I then follow with a description of the J2EE management model and, through code examples, introduce the Management EJB. Finally, I give a brief overview of SNMP (Simple Network Management Protocol) and CIM/WBEM (Common Information Model/Web-Based Enterprise Management), which you can also use with JSR 77.

JMX

The J2EE Management Specification is based on JMX, whose foundation is the managed bean, or MBean. MBeans are objects that run inside a server and provide access for server management. An MBean provides attributes, operations, and notifications. A client (e.g., a management console) can read and change the attributes, invoke operations, and receive notifications when certain events occur.

MBeans belong to the JMX specification's instrumentation level. They are registered at an MBean server, which represents the agent level. JMX does not specify the distributed services level, or how the managing clients access an MBean. Therefore, you need a connector or protocol adapter that exposes the MBeans to clients. Clients could then use existing management protocols like SNMP and CIM/WBEM to access the MBeans and integrate your JMX-enabled application into an enterprisewide system management architecture.

J2EE management model

JMX defines only the general mechanism for managing a Java-based system. It doesn't define the management of a concrete system. A J2EE server is a concrete system, and JSR 77 defines a concrete object model. This J2EE management model contains managed objects models for all well-known concepts from the J2EE world, such as a JVM, EJB (Enterprise JavaBean), and EJB module. The managed objects are not defined as Java interfaces.

All managed objects derive common features from a base model called J2EEManagedObject, shown in Figure 1.

Figure 1. J2EEManagedObject

An important attribute of J2EEManagedObject is the objectName of type OBJECT_NAME; an objectName identifies an object. Here's an example of an object name's string presentation:

jboss.management.single:name=localhost,j2eeType=JVM,J2EEServer=Single

This object name is from JBoss. The string to the left of the colon (:) is the domain name, a string used as a namespace. Three key attributes follow the colon:

  1. name, the object's actual name
  2. j2eeType, the managed object's concrete type name (in the example above, we have a JVM with the name localhost)
  3. The relationship to a parent—the parent is the J2EEServer with the name Single

We will use the key attributes later to find objects on the server; for example, we could find all JVMs under the J2EEServer.

Other attributes for the J2EEManagedObject: stateManageable, statisticsProvider, and eventProvider. All these attributes are of type Boolean and indicate the existence of other features. If stateManageable is true, the object provides additional operations to start and stop its services. If statisticsProvider is true, an object can provide runtime statistics. If eventProvider is true, an event provider object enables a client to register for events and receive event notifications.

Specialized models derive from the J2EEManagedObject model. Though Figure 2 shows only a part of the hierarchy, it includes some well-known J2EE concepts.

Figure 2. Type hierarchy. Click on thumbnail to view full-size image.

In addition to having attributes, a managed object can also have relationships with other objects. You can build relationships between objects using attributes of type OBJECT_NAME or arrays of OBJECT_NAME. The relationship between the J2EEServer and the J2EEDeployedObject offers an example, where several different object types (derived from J2EEDeployedObject) can be deployed into a J2EE server. Potential object types include an enterprise application, a Web module, an EJB module, or a resource adapter module. Figure 3 shows some of the management specification's relationships.

Figure 3. Relationships in JSR 77

As Figure 3 illustrates, the J2EEServer can have a relationship with one or more JVMs, which means the J2EEServer can run in a JVM cluster. The J2EEDomain groups all J2EEServers in a management domain, so that more than one clustered J2EEServer can be managed. Many J2EEDeployedObjects can be deployed in the J2EEServer. As Figure 2 shows, a J2EEDeployedObject can be a J2EEApplication or a single J2EEModule. Also, one J2EEServer has many resource providers—J2EEResources—such as JavaMailResource, JDBCResource, and JMSResource.

The management model is much more complex; for details, see the Java Management Specification. Because this model is based on a metamodel, and no Java interfaces are specified, vendors can easily expand it with additional types and extended attributes, operations, and events on existing types. The specification explicitly allows such extension so application server vendors can add their own functionality.

Access the managed objects

You need access to the managed objects defined by the model. Therefore, the specification requires the server vendor to provide a Management EJB (MEJB) that must be deployed on the server. The MEJB uses some of JMX's classes and interfaces and acts as an interface to access managed objects as JMX MBeans. This MEJB is a stateless session bean, which is available under the JNDI (Java Naming and Directory Interface) name ejb/mgmt/MEJB. The following code snippet obtains the MEJB:

Context ctx = new InitialContext();
Object objref = ctx.lookup("ejb/mgmt/MEJB");
ManagementHome home = (ManagementHome)
    PortableRemoteObject.narrow(objref,ManagementHome.class);
Management mejb = home.create();

The MEJB's interface is very simple. It provides methods to query objects, to get all metadata for an object, to get and to change attributes, and more. Figure 4 shows the MEJB remote interface.

Figure 4. The MEJB remote interface

To find a managed object, you must use the queryNames() method, which returns a java.util.Set containing object names (javax.management.ObjectName instances) that identify the objects matching the query parameters. The class ObjectName comes from JMX. queryNames()'s first parameter is an ObjectName that specifies a query string. A second parameter is a QueryExp, which is used for more specific searches. For simple queries, the second parameter can be null. The following code uses queryNames():

String domain = mejb.getDefaultDomain();
Set names = mejb.queryNames(
  new ObjectName(domain + ":j2eeType=EJBModule,*"),
  null);
Iterator itr = names.iterator();
while(itr.hasNext()) {
  System.out.println(itr.next());
}

At the code's beginning, we call the getDefaultDomain() method; the domain name acts as a namespace for managed objects (MBeans). You can also access MBeans in other domains—which, in JBoss, is the way to obtain other, non-JSR 77 MBeans. Then we invoke the queryNames() method, which gets an ObjectName describing the objects to be returned; in this case, we want to see all EJBModules. The final code statements print the names.

Accessing the object's attributes is simple. Because an EJBModule contains EJBs, we can list all EJBs inside an EJBModule. Therefore, we must read the ejbs attribute. To read attributes with the MEJB, use the getAttribute() method, as shown below:

while(itr.hasNext()) {
  ObjectName name = (ObjectName)itr.next();
  System.out.println("EJBModule: " + name);
  ObjectName[] ejbs = (ObjectName[])mejb.getAttribute(name, "ejbs");
  for(int i = 0; i < ejbs.length; i++) {
    System.out.println("    EJB: " + ejbs[i]);
  }
}

Note that you must know an attribute's exact name. JSR 77 specifies the ejbs attribute, but vendor-specific attributes must be discovered at runtime. To obtain that information, use the getMBeanInfo() method, which returns a structure describing all attributes, operations, and events.

Manage state

Up to this point, we have only navigated through the object hierarchy. Now, I'll show you how to manage an object's state. If an object's state is manageable, the attribute stateManageable is true. In that case, the object implements the StateManageable model, which contains operations such as start() and stop(). Using these operations, we can stop and restart a JavaMailResource, for example, as shown below:

String domain = mejb.getDefaultDomain();
Set names = mejb.queryNames(new ObjectName(domain +
    ":j2eeType=JavaMailResource,*"),
    null);
Iterator itr = names.iterator();
while(itr.hasNext()) {
  ObjectName name = (ObjectName)itr.next();
  mejb.invoke(name, "stop", null, new String[0]);
  Thread.sleep(3000);
  mejb.invoke(name, "start", null, new String[0]);
}

As you saw earlier, the method queryNames() retrieves all JavaMailResources. Then, iterating over the result set, the MEJB's invoke() method invokes the stop() operation. The parameters are the object's name, the operation name, an array of arguments, and a string array describing the operation's signature (which allows overloading). Because the stop() operation has no arguments, you can pass in a null parameter and an empty string array. The JavaMailResource restarts after a three-second delay.

The StateManageable model also contains an attribute state that describes the object's current state—STARTING, RUNNING, STOPPING, STOPPED, or FAILED. In addition, the startRecursive() method starts the object and all its contained children; for example, when the method starts an enterprise application, it also starts all contained EJB and Web modules.

Event handling

In a management environment, you need to receive notifications about events that occur in the managed system. Instead of continuous polling, you should register for a selected event and receive a notification asynchronously. JSR 77 specifies an event-handling mechanism that you can use with the MEJB in a Java client.

If the attribute eventProvider is true, the managed object implements the EventProvider model, which specifies an eventTypes attribute as a list of strings. Each string describes an event type that can occur; for example, j2ee.state.stopped is an event that occurs when a managed object has stopped.

When an event occurs and a client is registered for that event, the client receives a notification object. Using the MEJB, the notification object is an instance of JMX's javax.management.Notification. To register for an event, obtain the ListenerRegistration from the MEJB. The application server vendor implements the ListenerRegistration interface and determines how to transmit the notifications to the client—the vendor could do so through RMI (Remote Method Invocation) or JMS (Java Message Service), for example.

To register interest in an event, call the method getListenerRegistry(), which returns a ListenerRegistration. A call to addNotificationListener() registers a listener for an event. The listener class must implement the NotificationListener interface.

This example registers the listener for all JavaMailResources:

NotificationListener listener = new NotificationListener() {
  public void handleNotification(Notification not, Object obj) {
    System.out.println("Event:" + not.getType());
  }
};
ListenerRegistration reg = mejb.getListenerRegistry();
String domain = mejb.getDefaultDomain();
Set names = mejb.queryNames(new ObjectName(domain + 
    ":j2eeType=JavaMailResource,*"), null);
Iterator itr = names.iterator();
while(itr.hasNext()) {
  ObjectName name = (ObjectName)itr.next();
  // We assume that eventProvider is true
  reg.addNotificationListener(name, listener, null, null);
}

By combining the code above with the previous code segment, you see that the listener is called for at every state change (stopping, stopped, starting, running). Note that the addNotificationListener() method's third parameter is an object that implements NotificationFilter, which filters the notifications sent to the client. The last parameter is the handback object, which will be passed to the NotificationListener. The handback object is optional, but you can use it to provide information about the context in which the listener has been added.

As shown above, when an event occurs, the listener prints the event type. An object can emit the following standard event types: events for state change, for creation and destruction of managed objects, and for attribute change. Server vendors can add more specific event types.

1 2 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more