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 MBeansStatic 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 MBeansDynamic 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 ResourceModel 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 ResourceAn 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 DescriptorsApplications 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 ClassBecause 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); |