4.8 Using Model MBeans

Let's review what we know about model MBeans, and then we'll go over some examples and strategies for using them.

The MBeanServer functions as a factory for model MBeans. Therefore, model MBean instances should be created and maintained by the MBeanServer. Using the factory allows the RequiredModelMBean class implementation to vary depending on the needs of the environment in which the MBeanServer is installed. Your application that requests the instantiation of RequiredModelMBean does not have to be aware of the specifics of the RequiredModelMBean implementation. There are many potential implementation differences between JMX and JVM environments, including persistence, transactional behavior, caching, performance requirements, location transparency, remotability, and so on. RequiredModelMBean is responsible for implementing and managing these differences internally. Keep in mind that the MBeanServer that creates RequiredModelMBean may be specifically designed to support a particular RequiredModelMBean class. In fact, if you supply your own RequiredModelMBean implementation and try to use it, you may run into compatibility problems.

Because the JMX implementation provides the model MBean implementation, your application does not have to implement the model MBean, but just customize and use it. Your application's instrumentation code is consistent and minimal. You get the benefit of default policy and support for event logging, data persistence, data caching, and notification handling. In your application, you initialize your model MBean and pass in your identity, management interface, and any policy overrides . You can add custom attributes to the model MBean during execution; therefore information specific to the application can be modified without interruption during runtime. The model MBean then sets the behavior interface for the MBean and does any setup necessary for event logging and handling, data persistence and caching, and monitoring for your application's model MBean instance. The model MBean default behavior and simple APIs are intended to satisfy the management needs of most applications, but they also allow more complex application management scenarios.

You should have one instance of a model MBean for each instance of a resource (application, device, and so forth) to be managed in the system. These instances define the specific characteristics of operations, invocations, event trigger rules, event types, expiration rules, event logging, persistence, and so on for a given resource managed by the MBeanServer. Each instance of a model MBean may have completely different attributes, operations, and policies because they may manage completely unrelated resources.

In the following sections we will implement the time of day (todd) server example from Chapter 1 using model MBeans and showing various approaches for doing so. This would be useful if the todd server were already implemented and deployed such that going back into the implementation and adding instrumentation would be difficult and time-consuming .

We are going to look at two styles of model MBeans we can create: static and dynamic. Static model MBeans have their ModelMBeanInfo set during development through the ModelMBeanInfo and descriptor programming APIs. Dynamic MBeans create ModelMBeanInfo during execution from information that is available only while a system is running ”that is, an XML file or interaction with another runtime system.

4.8.1 Creating Static Model MBeans

Static model MBeans have ModelMBeanInfo that is known and set during development. The developer knows what the attributes, operations, and policies will be and uses the ModelMBeanInfo APIs to set them. This type of model MBean can be instantiated with a new operation or a create on the MBeanServer.

Here is an example of a static model MBean approach in the todd server. Here is the todd server without an MBean being implemented as part of the todd application class. The main loop and Server constructor have been pulled out for discussion later:

  package  jnjmx.ch4;  // Create model MBeans for Server and Session from Server main // Create ModelMBeanInfo from program APIs  import  java.util.SortedSet;  import  java.util.TreeSet;  import  java.lang.reflect.Constructor;  import  javax.management.*;  import  javax.management.modelmbean.*;  public class  Server {  private  MBeanServer mbs;  private  SessionPool sessions;  private  SortedSet connectionQueue;  private  Listener listener;  private boolean  active;  static boolean  tracing =  false;   private long  tzero;  private int  connections;   // MAIN LOOP WILL GO HERE   // SERVER CONSTRUCTOR WILL GO HERE  public   void  activateSession(Connection k) {     Session s;  synchronized  (sessions) {  while  ((s = sessions.reserve()) ==  null  ) {  try  {           sessions.wait();         }  catch  (InterruptedException x) {           // see if a session is available         }       }     }     s.activate(k);     connections++;   }   /**    * Connections attribute getter    * @returns total number of connections handled    */  public  Integer getConnections() {  return   new  Integer(connections);   }   /**    * Sessions attribute getter    * @returns number of active sessions    */  public  Integer getSessions() {  int  as = sessions.getAvailableSessions().intValue();  int  sz = sessions.getSize().intValue();  return   new  Integer(sz - as);   }   /**    * Uptime attribute getter    * @returns number of milliseconds since the server was started    */  public  Long getUptime() {  return   new  Long(System.currentTimeMillis() - tzero);   }  public   boolean  isActive() {  return  active;   }   /**    * Shut down the server, killing the process and any active    * sessions    */  public   void  shutdown() {     System.exit(0);   }   /**    * Start a listener thread that will queue incoming connections    */  public   void  start() {     listener =  new  Listener(connectionQueue);     listener.start();   }   /**    * Stop the server's listener thread; active sessions continue    * to handle requests    */  public   void  stop() {     listener.stopListening();   }  public  Connection waitForConnection() {     Connection k;  synchronized  (connectionQueue) {  while  (connectionQueue.isEmpty()) {  try  {           connectionQueue.wait();         }  catch  (InterruptedException x) {           // See if the queue is still empty         }       }       k = (Connection) connectionQueue.first();       connectionQueue.remove(k);     }  return  k;   } 

Here is the SessionPool class without an integrated MBean:

  package  jnjmx.ch4;  import  java.util.HashSet;  import  java.util.Set;  public   class  SessionPool  {  private   static   final   int  POOLSIZE = 8;  private  Set sessions;  private   int  size;  public  SessionPool() {  this  (POOLSIZE);   }  public  SessionPool(  int  size) {  this.  size = size;     sessions =  new  HashSet(  this.  size);     fill();   }  public   synchronized   void  grow(  int  increment) {  for  (  int  i = 0; i < increment; i++) {       Session s =  new  Session(  this  );       sessions.add(s);     }     size = size + increment;   }  public  Integer getSize() {  return   new  Integer(size);   }  public   synchronized  Integer getAvailableSessions() {  return   new  Integer(sessions.size());   }  public   synchronized   void  release(Session session) {     sessions.add(session);     notify();   }  public   synchronized  Session reserve() {  while  (sessions.isEmpty()) {  try  {         wait();       }  catch  (InterruptedException x) {         // see if the set is still empty       }     }     Session s = (Session) sessions.iterator().next();     sessions.remove(s);  return  s;   }  private   void  fill() {  for  (  int  i = 0; i < size; i++) {       Session s =  new  Session(  this  );       sessions.add(s);     }   } } 

Here's the main program loop with a model MBean added for the todd and session pool management. Note that ModelMBeanInfo is defined in the program and set using the ModelMBeanInfo APIs. To make any adjustments would require recompiling the resource. In this example the main loop is responsible for instantiating the server and its model MBean. In the next code block we will see where the server's constructor is responsible for instantiating the session pool and its model MBean:

  public   static   void  main(String[] args)  throws  Exception {  try  {   /* management stuff */   /** Find an MBeanServer for our MBean */   MBeanServer mbs = MBeanServerFactory.createMBeanServer();   /** Instantiate the todd server */   Server server =  new  Server(mbs);   /** Create a name for the MBean */   ObjectName son =  new  ObjectName("todd:id=Server");   /** Create an unconfigured RequiredModelMBean instance in the   * MBeanServer */     RequiredModelMBean serverMMBean = (RequiredModelMBean)     mbs.instantiate("javax.management.modelmbean.RequiredModelMBean");   /** Set the configuration of the ModelMBean through ModelMBeanInfo    ** This method is below */   ModelMBeanInfo serverMMBeanInfo =       server.createServerModelMBeanInfo(server, son);   serverMMBean.setModelMBeanInfo(serverMMBeanInfo);   /** Set the todd server as the managed resource   serverMMBean.setManagedResource(server,"ObjectReference");   /** Register the model MBean that is now ready to run with the   * MBeanServer */   ObjectInstance registeredServerMMBean =     mbs.registerMBean((Object) serverMMBean, son);   mbs.invoke(son, "start",  new  Object[] {},  new  String[] {});   // executes method on MBean   System.out.println("starting connection loop");  while  (server.isActive()) {     Connection k = server.waitForConnection();     server.activateSession(k);     System.out.println("*");   }   }  catch  (Exception e) {     System.out.println("todd Server failed with " +         e.getMessage());   }  } 

Here is the Server constructor that shows how the session pool and the session pool's model Bean are instantiated:

  public  Server(MBeanServer mbs)  throws  Exception {  this.  mbs = mbs;   connectionQueue =  new  TreeSet();   connections = 0;   sessions =  new  SessionPool();            // create session pool   ObjectName spon =  new  ObjectName("todd:id=SessionPool");   // name of mbean   // Instantiate the model MBean   RequiredModelMBean sessionMMBean = (RequiredModelMBean)     mbs.instantiate     ("javax.management.modelmbean.RequiredModelMBean");   // Set MBeanInfo   ModelMBeanInfo sessionMMBInfo =         createSessionModelMBeanInfo(sessions, spon);   sessionMMBean.setModelMBeanInfo(sessionMMBInfo);   // Set the managed resource   sessionMMBean.setManagedResource(sessions, "ObjectReference");   // Register the model MBean with the MBeanServer   ObjectInstance registeredSessionMMBean =         mbs.registerMBean((Object) sessionMMBean,spon);   System.out.println("created Session ModelMBean");   active =  true;  tzero = System.currentTimeMillis(); } 

The Server model MBean has operations start() , stop() , and shutdown() . It has attributes Connections , Sessions , and Uptime . Here are the routines to set ModelMBeanInfo :

 // Create the ModelMBeanInfo instance for the todd server  ModelMBeanInfo createServerModelMBeanInfo(Server managedServer,     ObjectName serverMMBeanName) {   Class serverClass =  null;   try  {     serverClass = Class.forName("jnjmx.ch4.Server");   }  catch  (Exception e) {     System.out.println("Server Class not found");   }   // Set the MBean descriptor   Descriptor mmbDescription =  new  DescriptorSupport(  new  String[] {       ("name="+serverMMBeanName),        // server MBean name       "descriptorType=mbean",       "displayName=toddServerManager",       "log=T",                           // log all notifications       "logFile=jmxserver.log",           // in jmxmain.log       "currencyTimeLimit=10"});          // cache all attribute                                          // values for 10 seconds   // Define attributes in ModelMBeanAttributeInfo instances   ModelMBeanAttributeInfo[] mmbAttributes =  new  ModelMBeanAttributeInfo[3];   // Declare Connections attribute   Descriptor connectionsDesc =  new  DescriptorSupport(  new  String[] {       "name=Connections",             // attribute name       "descriptorType=attribute",       "displayName=todd connections",       "getMethod=getConnections",     // call getTime operation                                       // for gets       "currencyTimeLimit=-1"});       // don't cache time value   mmbAttributes[0] =  new  ModelMBeanAttributeInfo("Connections",        "java.lang.Integer",           // attribute type is String        "todd Server connections",     // description of attribute  true,   false,   false,  connectionsDesc);              // descriptor for attribute   // Declare Sessions attribute   Descriptor sessionsDesc =  new  DescriptorSupport(  new  String[] {       "name=Sessions",            // attribute name       "descriptorType=attribute",       "displayName=todd server sessions",       "getMethod=getSessions",    // call operation for gets       "currencyTimeLimit=5"});    // cache value for 20 seconds   mmbAttributes[1] =  new  ModelMBeanAttributeInfo("Sessions",       "java.lang.Integer",      // type for sessions is integer       "todd Server sessions",  true,   false,   false,  sessionsDesc);            // descriptor for sessions   // Declare Uptime attribute   Descriptor uptimeDesc =  new  DescriptorSupport(  new  String[] {       "name=uptime",              // attribute name       "descriptorType=attribute",       "displayName=todd server sessions",       "getMethod=getUptime",      // call operation for gets       "currencyTimeLimit=0"});    // don't cache uptime   mmbAttributes[2] =  new  ModelMBeanAttributeInfo("uptime",       "java.lang.Integer",      // type for alarm is string       "todd Server length of time up",  true,   false,   false,  uptimeDesc);        // descriptor for uptime   // Declare constructors for managed resource   ModelMBeanConstructorInfo[] mmbConstructors =  new  ModelMBeanConstructorInfo[1];   Constructor[] myConstructors = serverClass.getConstructors();   Descriptor mmBeanDesc =  new  DescriptorSupport(  new  String[] {       "name=ServerClass",       "descriptorType=operation",              "role=constructor" });   mmbConstructors[0] =  new  ModelMBeanConstructorInfo("Server(): Constructs a todd Server",       myConstructors[0],       mmBeanDesc);   // Define operations in ModelMBeanOperationInfo instances   /* Operations: start, stop, shutdown    * getUptime, getConnections, getSessions    */   // Declare getValue operation String getValue()   // Set parameter array   ModelMBeanOperationInfo[] mmbOperations =  new  ModelMBeanOperationInfo[6];   // Declare start() operation void start()   // Set parameter array   MBeanParameterInfo[] parms =  null;  Descriptor startDesc =  new  DescriptorSupport(  new  String[] {       "name=start",                // operation/method name       "descriptorType=operation",       "class=server",              // class to run operation on       "role=operation" });         // this is an operation   mmbOperations[0] =  new  ModelMBeanOperationInfo("start",  // name       "start server",               // description       parms ,                       // parameters for method start       "java.lang.boolean",          // return type start value        MBeanOperationInfo.ACTION,   // start changes state        startDesc);                  // descriptor for start   Descriptor stopDesc =  new  DescriptorSupport(  new  String[] {       "name=stop",                 // operation/method name       "descriptorType=operation",       "class=server",              // class to run operation on       "role=operation" });         // this is an operation   mmbOperations[1] =  new  ModelMBeanOperationInfo("stop",   // name       "stop server",               // description       parms ,                      // parameters for method       "java.lang.boolean",         // return type       MBeanOperationInfo.ACTION,   // stop changes state       stopDesc);                   // descriptor for stop   Descriptor shutdownDesc =  new  DescriptorSupport(  new  String[] {       "name=shutdown",             // operation/method name       "descriptorType=operation",       "class=server",              // class to run operation on       "role=operation" });         // this is an operation   mmbOperations[2] =  new  ModelMBeanOperationInfo("shutdown",                  // name       "shutdown server",           // description       parms ,                      // parameters for method       "java.lang.boolean",         // return type       MBeanOperationInfo.ACTION,   // changes state       shutdownDesc);               // descriptor   // Declare getConnections operation String getConnections()   Descriptor getConnectionsDesc =  new  DescriptorSupport(  new  String[] {       "name=getConnections",       "descriptorType=operation",       "class=Server",              // class to run operation on       "role=getter"});             // this is a getter operation   MBeanParameterInfo[] noParms =  null;  mmbOperations[3] =  new  ModelMBeanOperationInfo("getConnections", // name       "get Connections attribute",   // description       noParms,                   // null parameter list,       "java.lang.Integer",       // return type is Integer       MBeanOperationInfo.INFO,   // does not change state       getConnectionsDesc);       // descriptor for getConnections   // Declare getSessions operation - void getSession()   Descriptor getSessionsDesc =  new  DescriptorSupport(  new  String[] {       "name=getSessions",           // name       "descriptorType=operation",       "class=Clock",                // target class for method       "role=getter"});              // operation is a setter   mmbOperations[4] =  new  ModelMBeanOperationInfo("getSessions",                // name       "get Sessions attribute",     // description       noParms,                      // parameters       "java.lang.Integer",          // no return value       MBeanOperationInfo.INFO,      // operation changes state       getSessionsDesc);             // setSessions descriptor   // Declare getUptime operation   Descriptor getUptimeDesc =  new  DescriptorSupport(  new  String[] {       "name=getUptime",             // name       "descriptorType=operation",       "class=Server",               // target class       "role=getter"});              // operation is a getter   mmbOperations[5] =  new  ModelMBeanOperationInfo("getUptime",             // name       "get uptime attribute",  // description       noParms,                 // no parameters (null)       "java.lang.Integer",     // return type is String       MBeanOperationInfo.INFO, // operation does not change state       getUptimeDesc);          // uptime descriptor   // Define no notifications in ModelMBeanNotificationInfo   ModelMBeanNotificationInfo[] mmbNotifications =  new  ModelMBeanNotificationInfo[0];     // Create ModelMBeanInfo     ModelMBeanInfo mmBeanInfo =  new  ModelMBeanInfoSupport("Server",       "ModelMBeanInfo for managing a todd Server",       mmbAttributes,       mmbConstructors,       mmbOperations,       mmbNotifications);  try  {     mmBeanInfo.setMBeanDescriptor(mmbDescription);   }  catch  (Exception e) {     System.out.println("CreateServerMBeanInfo failed with " +         e.getMessage());   }  return  mmBeanInfo;   } 

The Session model MBean has operation grow() and attributes availableSessions and size :

 ModelMBeanInfo createSessionModelMBeanInfo(SessionPool          mmBResource, ObjectName mmbName) {   // Create the ModelMBeanInfo instance for the session pool   Class targetClass =  null;   try  {     targetClass = Class.forName("jnjmx.ch4.SessionPool");   }  catch  (Exception e) {     System.out.println("Server Class not found");   }   // Set the MBean descriptor   Descriptor mmbDescription =  new  DescriptorSupport(  new  String[] {       ("name="+mmbName),           // MBean name       "descriptorType=mbean",       ("displayName=Session Pool Manager"),       "log=T",                     // log all notifications       "logfile=jmxsession.log",    // in jmxmain.log       "currencyTimeLimit=10"});    // cache all attribute values                                    // for 10 seconds   ModelMBeanAttributeInfo[] mmbAttributes =  new  ModelMBeanAttributeInfo[2];   // Declare Connections attribute   Descriptor sizeDesc =  new  DescriptorSupport(  new  String[] {       "name=Size",         // attribute name       "descriptorType=attribute",       "displayName=todd size",       "getMethod=getSize" });   mmbAttributes[0] =  new  ModelMBeanAttributeInfo("Size",        "java.lang.Integer",      // attribute type is String        "todd Server size",      // description of attribute  true,   false,   false,  sizeDesc);        // descriptor for attribute   // Declare availSessions attribute   Descriptor availSessionsDesc =  new  DescriptorSupport(  new  String[] {       "name=AvailableSessions",         // attribute name       "descriptorType=attribute",       "displayName=todd server available sessions",       "getMethod=getAvailableSessions", // call operation for gets       "currencyTimeLimit=5"});   mmbAttributes[1] =  new  ModelMBeanAttributeInfo("Sessions",       "java.lang.Integer",      // type for sessions is integer       "todd Server available sessions",  true,   false,   false,  availSessionsDesc);      // descriptor for sessions   // Declare constructors for MBean   Constructor[] constructors = targetClass.getConstructors();   ModelMBeanConstructorInfo[] mmbConstructors =  new  ModelMBeanConstructorInfo[1];   Descriptor mmBeanDesc =  new  DescriptorSupport(  new  String[] {       "name=SessionClass",       "descriptorType=operation",       "role=constructor" });   mmbConstructors[0] =  new  ModelMBeanConstructorInfo("SessionPool(): Constructs a todd Server",       constructors[0],       mmBeanDesc);   ModelMBeanOperationInfo[] mmbOperations =  new  ModelMBeanOperationInfo[3];   // Declare grow() operation void grow()   // Set parameter array   MBeanParameterInfo[] noParms =  null;  Descriptor growDesc =  new  DescriptorSupport(  new  String[] {       "name=grow",               // operation/method name       "descriptorType=operation",       "class=server",            // class to run operation on       "role=operation" });       // this is an operation   mmbOperations[0] =  new  ModelMBeanOperationInfo("grow", // name       "grow session pool",        // description       noParms ,       "java.lang.boolean",       MBeanOperationInfo.ACTION,  // changes state       growDesc);                  // descriptor for enable   // Declare getSize operation  String getSize()   Descriptor getSizeDesc =  new  DescriptorSupport(  new  String[] {       "name=getSize",       "descriptorType=operation",       "class=Sessions",      // class to run operation on       "role=getter"});       // this is a getter operation   mmbOperations[1] =  new  ModelMBeanOperationInfo("getSize", // name       "get Size attribute",     // description       noParms,                  // null parameter list,       "java.lang.Integer",      // return type is Integer       MBeanOperationInfo.INFO,  // does not change state       getSizeDesc);             // descriptor for getConnections   // Declare getAvailableSessions operation - void getSession()   Descriptor getAvailableSessionsDesc =  new  DescriptorSupport(  new  String[] {       "name=getAvailableSessions",    // name       "descriptorType=operation",       "class=Sessions",               // target class for method       "role=getter"});                // operation is a setter   mmbOperations[2] =  new  ModelMBeanOperationInfo("getSessions",               // name       "get Sessions attribute",    // description       noParms,                     // parameters       "java.lang.Integer",         // no return value       MBeanOperationInfo.INFO,     // does not change state       getAvailableSessionsDesc);   // setAvailableSessions                                    // descriptor   ModelMBeanNotificationInfo[] mmbNotifications =  new  ModelMBeanNotificationInfo[0];   // Create ModelMBeanInfo   ModelMBeanInfo mmBeanInfo =  new  ModelMBeanInfoSupport("Session",       "ModelMBeanInfo for managing todd Sessions",       mmbAttributes,       mmbConstructors,       mmbOperations,       mmbNotifications);  try  {     mmBeanInfo.setMBeanDescriptor(mmbDescription);   }  catch  (Exception e) {     System.out.println("CreateServerMBeanInfo failed with " +       e.getMessage());   }  return  mmBeanInfo;   } 

4.8.2 Creating Dynamic Model MBeans

Dynamic model MBeans have ModelMBeanInfo that is known and set during the runtime. Either introspection or external files are used to set this ModelMBeanInfo . The developer may use a service to create a ModelMBeanInfo instance. One thing to keep in mind is that ModelMBeanInfo for a newly instantiated model MBean includes all the methods on the model MBean. You will need to override this ModelMBeanInfo to remove methods you do not want adapters to have, like setManagedResource() .

The example that follows is of a dynamic model MBean approach using an XML to MBeanInfo service as described earlier. Basically the main loop from the previous example uses the XML service to populate ModelMBeanInfo . Now we can change the management interface by changing the XML file and and without having to recompile the source. This is a more flexible and dynamic model.

Here's the main program loop and Server constructor with a model MBean added for the todd and session pool management primed by the XML service:

  private static  XMLService XMLPrimer;  public   static   void  main(String[] args)  throws  Exception {   /* management stuff */   /** Find an MBeanServer for our MBean */   MBeanServer mbs = MBeanServerFactory.createMBeanServer();   // Instantiate the XML service   ObjectName sn =  new  ObjectName("todd:id=XMLPrimer");   XMLPrimer =  new  XMLService(sn);   String serverMBeanInfoFile = "ServerMBean.xml";   /** Instantiate the todd server */   Server server =  new  Server(mbs);   /** Create a name for the MBean */   ObjectName son =  new  ObjectName("todd:id=Server");   /** Set the configuration of the model MBean through the      * XMLPrimer service, which sets ModelMBeanInfo from an      * XML file    ** */   RequiredModelMBean serverMMBean = (RequiredModelMBean)     XMLPrimer.createMBeanFromXMLFile(serverMBeanInfoFile, son);   /** Create an unconfigured RequiredModelMBean instance in the       MBeanServer */   /** Set the todd server as the managed resource   serverMMBean.setManagedResource(server,"ObjectReference");   /** Register the model MBean that is now ready to run with the    * MBeanServer */   ObjectInstance registeredServerMMBean =     mbs.registerMBean((Object) serverMMBean, son);   /* server stuff */   mbs.invoke(son, "start",  new  Object[] {},  new  String[] {});  while  (server.isActive()) {     Connection k = server.waitForConnection();     server.activateSession(k);   }   }  catch  (Exception e) {     System.out.println("todd Server failed with " +       e.getMessage());   }  }  public  Server(MBeanServer mbs)  throws  Exception {  this.  mbs = mbs;   connectionQueue =  new  TreeSet();   connections = 0;   sessions =  new  SessionPool();   ObjectName spon =  new  ObjectName("todd:id=SessionPool");   String sessionMBeanInfoFile = "SessionMBean.xml";   RequiredModelMBean sessionMMBean = (RequiredModelMBean)     XMLPrimer.createMBeanFromXMLFile(sessionMBeanInfoFile, spon);     sessionMMBean.setManagedResource(sessions, "ObjectReference");      ObjectInstance registeredSessionMMBean =         mbs.registerMBean((Object) sessionMMBean,spon);   active =  true;  tzero = System.currentTimeMillis(); } 
4.8.2.1 Creating Model MBeans from the Managed Resource

Model MBeans may be instantiated, customized, and registered by the managed resources themselves . This will usually be done during initialization of the managed resource. The managed resource then updates the data in the model MBean whenever an update is necessary. In this case managedResource will be set to this() so that all the operations are delegated back to the object that is creating the model MBean. Here is an example of a self-managing service ”the Server class that creates its own model MBean:

  package  jnjmx.ch4;  import  java.util.SortedSet;  import  java.util.TreeSet;  import  java.lang.reflect.Constructor;  import  javax.management.*;  import  javax.management.modelmbean.*; // Managed server creates model MBeans and ModelMBeanInfo using // XML files // In this example we show how to create the same model MBeans // using an XML service to create ModelMBeanInfo // Once again, the main loop of the Server (4) instantiates the // server // The server's constructor instantiates the session pool and the // server's model MBean // SessionPool's constructor instantiates SessionPool's model MBean  public   class  Server {  private  MBeanServer mbs;  private  SessionPool sessions;  private  SortedSet connectionQueue;  private  Listener listener;  private   boolean  active;  static   boolean  tracing =  false;   private   long  tzero;  private   int  connections;  private static  XMLService XMLPrimer;  public   static   void  main(String[] args)  throws  Exception {       /* server stuff */     Server server =  new  Server();     server.start();  while  (server.isActive()) {       Connection k = server.waitForConnection();       server.activateSession(k);     }     }  catch  (Exception e) {       System.out.println("todd Server failed with " +           e.getMessage());     }    }  public  Server()  throws  Exception {     /** Find an MBeanServer for our MBean */     MBeanServer mbs = MBeanServerFactory.createMBeanServer();     // Instantiate the XML service     ObjectName sn =  new  ObjectName("todd:id=XMLPrimer");     XMLPrimer =  new  XMLService(sn);     ObjectInstance registeredXMLService =          mbs.registerMBean((Object) XMLPrimer, sn);     connectionQueue =  new  TreeSet();     connections = 0;     sessions =  new  SessionPool();     active =  true;  tzero = System.currentTimeMillis();     /** Create a name for the MBean */     ObjectName son =  new  ObjectName("todd:id=Server"); /** Set the configuration of the model MBean through the  * XMLPrimer service, which sets ModelMBeanInfo from an  * XML file ** */     String serverMBeanInfoFile = "jnjmx.ch4/ServerInfo.xml";       ModelMBean serverMMBean = (ModelMBean)       XMLPrimer.createMBeanFromXMLFile(serverMBeanInfoFile,            "Server" ,  this  );     /** Register the model MBean that is now ready to run with     * the MBeanServer */     ObjectInstance registeredServerMMBean =         mbs.registerMBean(serverMMBean, son);   }   // The rest of the methods are the same as in previous examples   } 

Here is the session class with an integrated model MBean:

  package  jnjmx.ch4;  import  java.util.HashSet;  import  java.util.Set;  import  java.util.ArrayList;  import  javax.management.*;  import  javax.management.modelmbean.*;  public   class  SessionPool  {  private   static   final   int  POOLSIZE = 8;  private  Set sessions;  private   int  size;  private  MBeanServer mbs;  public  SessionPool() {  this  (POOLSIZE);   }  public  SessionPool(  int  size) {  this.  size = size;     sessions =  new  HashSet(  this.  size);     fill();     createSessionPoolMBean();   }  private   void  createSessionPoolMBean() {  try  {     // Change to use existing MBeanServer and existing XMLService     // through the MBeanServer     ArrayList mbsList = MBeanServerFactory.findMBeanServer(  null  );  if  ((!mbsList.isEmpty() && (mbsList.get(0) !=  null  )))       mbs = (MBeanServer) mbsList.get(0); // use first MBeanServer  else  {       System.out.println("SessionPool can't find an MBeanServer");       System.exit(0);     }     ObjectName xmlServiceName =  new  ObjectName("todd:id=XMLPrimer");     XMLService XMLPrimer =  new  XMLService(xmlServiceName);     ObjectName spon =  new  ObjectName("todd:id=SessionPool");        String sessionXMLFile = "jnjmx.ch4/SessionInfo.xml";        // using the XMLService MBean created by Server to load        // ModelMBeanInfo       ModelMBean sessionMMBean = (ModelMBean) mbs.invoke(xmlServiceName,          "createMBeanFromXMLFile",  new  Object[] {sessionXMLFile,                "SessionPool", (Object)  this  },  new  String[] { "java.lang.String",                "java.lang.String",                "java.lang.Object"});        ObjectInstance registeredSessionMMBean =          mbs.registerMBean((Object) sessionMMBean,spon);     }  catch  (Exception e) {      System.out.println("SessionPool MBean creation failed with "        + e.getMessage());     }   } // The rest of the methods are the same as in the previous example // of SessionPool } 
4.8.2.2 Creating Model MBeans by an External Force: Assigning a Managed Resource

An application can create model MBeans to manage a completely separate resource. The program must have a reference to the managed resource for the model MBean that it can set in the managedResource attribute. The program is also responsible for inspecting the managed resource or another configuration file and creating the attributes, operations, and notifications. A program may instantiate model MBeans for lots of managed resources in the system. Usually this is done when a system is initialized or a management system is initialized . Another common scenario is that this program is a connector between an existing proprietary management system and a JMX-based management system. The Apache manager examples at the beginning of this chapter are excellent examples of a program creating model MBeans for external managed resources.

4.8.3 Adding Custom Descriptors

Applications using model MBeans and adapter MBeans can add their own descriptor fields to the model MBean descriptor. When would this be useful?

Applications using model MBeans could add their own management metadata that was unique to their own custom, specific management system, such as display information or roles. One interesting bit of metadata that we suggest all developers should consider adding to their attribute descriptors is an attribute classification, much like the operation role. Attributes should be classified as descriptive, configuration, capability, state, or metric. This classification of attributes is consistent with the one defined by the CIM Model. [21]

Taking the earlier TotalAccesses attribute as an example, we classify this attribute as a metric:

 // Custom descriptor example  Descriptor totalAccessesCustomDesc =  new  DescriptorSupport(); totalAccessesCustomDesc.setField("name","TotalAccesses"); totalAccessesCustomDesc.setField("descriptorType","attribute"); totalAccessesCustomDesc.setField("displayName","NumberChanges"); totalAccessesCustomDesc.setField("getMethod","getTotalAccesses"); totalAccessesCustomDesc.setField("setMethod","setTotalAccesses"); totalAccessesCustomDesc.setField("classification","metric"); // custom descriptor 

Adapter MBeans that translate model MBeans to represent resources into their own management systems may cache hints to help with this translation in the descriptor. For example, they may add the SNMP OID to the descriptor or the CIM name for the resource. Or they may add a business domain (e.g., for Accounting Department) or application domain (e.g., for WebSphere) to assist with context and scope.

4.8.4 Overriding the RequiredModelMBean Class

Because the RequiredModelMBean class is an implementation of the model MBean that is provided with every JMX implementation, it is reasonably safe to extend the RequiredModelMBean class and add or override behavior. For example, if you wanted to persist your RequiredModelMBean data to an XML file database rather than to a serialized object file, you would need to override the load() and store() methods of RequiredModelMBean . Here is an example of how you could do this:

  package  jnjmx.ch4;  import  javax.management.*;  import  javax.management.modelmbean.*;  public   class  XMLModelMBean  extends  RequiredModelMBean { /**    * Constructor for XMLModelMBean    *  @throws  MBeanException    *  @throws  RuntimeOperationsException    */  public  XMLModelMBean()  throws  MBeanException,     RuntimeOperationsException {  super  ();   }  public  XMLModelMBean(String filename, String mbeanName)  throws  MBeanException, RuntimeOperationsException {  super  ();  try  {       load(filename, mbeanName);     }  catch  (Exception e) {       // didn't find the file with primer data; that's OK     }   }   /**    * Constructor for XMLModelMBean    *  @param  arg0    *  @throws  MBeanException    *  @throws  RuntimeOperationsException    */  public  XMLModelMBean(ModelMBeanInfo arg0)  throws  MBeanException, RuntimeOperationsException {  super  (arg0);  try  {       load();     }  catch  (Exception e) {       // didn't find the file with primer data; that's OK     }   }   /**    * @see javax.management.DynamicMBean#getAttribute(String)    */  public  Object getAttribute(String arg0)  throws  AttributeNotFoundException, MBeanException,       ReflectionException {  return   super.  getAttribute(arg0);   }   /**    *  @see  javax.management.DynamicMBean#getAttributes(String[])    */  public  AttributeList getAttributes(String[] arg0) {  return   super.  getAttributes(arg0);   }   /**    *  @see  javax.management.DynamicMBean#invoke(String, Object[],    * String[])    */  public  Object invoke(String arg0, Object[] arg1, String[] arg2)  throws  MBeanException, ReflectionException {  return   super.  invoke(arg0, arg1, arg2);   }   /**    *  @see  javax.management.DynamicMBean#setAttributes(AttributeList)    */  public  AttributeList setAttributes(AttributeList arg0) {  return   super.  setAttributes(arg0);   }   /**    * This version of load() expects a file name and an MBean name    * in the file in the format required by the Jakarta Modeler    */  public   void  load(String filename, String name)  throws  MBeanException, RuntimeOperationsException,     InstanceNotFoundException   {  try  { // Look for file of that name       XMLService XMLPrimer =  new  XMLService();       ModelMBeanInfo newInfo = (ModelMBeanInfo)         XMLPrimer.createMBeanInfoFromXMLFile(filename, name);       setModelMBeanInfo(newInfo);     }  catch  (Exception e)     {       System.out.println("load(): Persistent MBean XML file was not found");     }   }  public   void  load()  throws  MBeanException, RuntimeOperationsException,      InstanceNotFoundException   {     Descriptor mmbDesc = ((ModelMBeanInfo)       getMBeanInfo()).getMBeanDescriptor();     // We will use persistLocation to be the directory for the     // XML file     // We will use persistName to be the file to save the XML data     // for the MBean to     String persistDir = (String)       mmbDesc.getFieldValue("persistLocation");     String persistFile = (String)       mmbDesc.getFieldValue("persistName");     String currName = (String) mmbDesc.getFieldValue("name");  if  ((persistDir ==  null  )  (persistFile ==  null  ))     { // Persistence not supported for this MBean; return       // without error  return;  }     String loadTarget = persistDir.concat("/" + persistFile);     load(loadTarget, currName);   }  public   void  store()  throws  MBeanException, RuntimeOperationsException,      InstanceNotFoundException   {     /* Store in a file with name = MBean name in directory */     /* For this example, we always persist the MBean; in a real     * override of this method, you need to honor the persistence     * policy descriptors:  */     /* persist policy:        persist if persistPolicy != never         persistPolicy == always         persistPolicy == onTimer && now > lastPersistTime +          persistPeriod         persistPolicy == NoMoreOftenThan && now > lastPersistTime +          persistPeriod        don't persist if persistPolicy == never         persistPolicy == onUpdate         persistPolicy = onTimer && now < lastPersistTime +          persistPeriod     */     /* You should also remember to */     /* set the lastPersistTime on attribute */     /* Check to see if should be persisted */  boolean  MBeanPersistItNow =  true;  // always persist  if  (getMBeanInfo() ==  null  )     {  throw   new  RuntimeOperationsException(  new  IllegalArgumentException("ModelMBeanInfo must not be " +             "null"),         ("Exception occured trying to set the store data for " +          "the RequiredModelMBean"));     }     Descriptor mmbDesc = ((ModelMBeanInfo)       getMBeanInfo()).getMBeanDescriptor();  if  (MBeanPersistItNow ==  true  )     {  try  {         // Get directory         String persistDir = (String)           mmbDesc.getFieldValue("persistLocation");         String persistFile = (String)           mmbDesc.getFieldValue("persistName");         String persistTarget = persistDir.concat("/" +           persistFile);         // Call another method in this app to write MBeanInfo as a         // database record         XMLService XMLPrimer =  new  XMLService();         XMLPrimer.writeXMLFile(  this,  persistTarget);       }  catch  (Exception e)       {         System.out.println("store(): Exception storing MBean " +             "into file for RequiredModelMBean " +             e.getClass() + ":" + e.getMessage());         e.printStackTrace();       }     } } } 

If you can put the XMLModelMBean class in the class path of the MBeanServer, then when you instantiate or create the new model MBean, it will look like this (snipped from the earlier integrated model MBean example):

 ...  public  XMLServer(MBeanServer mbs)  throws  Exception {  this.  mbs = mbs;     connectionQueue =  new  TreeSet();     connections = 0;     sessions =  new  SessionPool();     ObjectName spon =  new  ObjectName("todd:id=SessionPool");     XMLModelMBean sessionMMBean = (XMLModelMBean)       mbs.instantiate("jnjmx.ch4.XMLModelMBean",  new  Object [] {"jnjmx.ch4/SessionInfo.xml", "SessionPool"},  new  String[] {"java.lang.String", "java.lang.String"});       sessionMMBean.store();     sessionMMBean.setManagedResource(sessions, "ObjectReference");     ObjectInstance registeredSessionMMBean =     mbs.registerMBean((Object) sessionMMBean,spon);     active =  true;  tzero = System.currentTimeMillis();   } ... 

Or you can use the create operation:

  public  XMLServer(MBeanServer mbs)  throws  Exception {  this.  mbs = mbs;   connectionQueue =  new  TreeSet();   connections = 0;   sessions =  new  SessionPool();   ObjectName spon =  new  ObjectName("todd:id=SessionPool");   XMLModelMBean sessionMMBean = (XMLModelMBean)     mbs.createMBean("jnjmx.ch4.XMLModelMBean",  new  Object [] {"jnjmx.ch4/SessionInfo.xml", "SessionPool"},  new  String[] {"java.lang.String", "java.lang.String"});   sessionMMBean.setManagedResource(sessions, "ObjectReference");   ObjectInstance registeredSessionMMBean =      mbs.registerMBean((Object) sessionMMBean,spon);   active =  true;  tzero = System.currentTimeMillis(); } 

If you can't update the class path of the MBeanServer, you will have to instantiate XMLModelMBean with a new operation in the scope of your application and then register it with the MBeanServer like this:

 XMLModelMBean myMMB = new XMLModelMBean();  mbs.register(myMMB); 


Java and JMX. Building Manageable Systems
Javaв„ў and JMX: Building Manageable Systems
ISBN: 0672324083
EAN: 2147483647
Year: 2000
Pages: 115

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