5.3 The MBeanServer Interface

Now that we know how to create an MBeanServer and how to name MBeans, it's time to explore the functionality provided by the MBeanServer itself. In this section we'll examine the core of the MBeanServer interface: the methods it provides for creating and manipulating MBeans, and the methods it provides for retrieving information about itself. Subsequent sections will discuss the MBeanServer's query methods and the notification facility.

As we mentioned earlier, an MBeanServer's primary responsibility is to maintain a registry of MBeans. The registry provides a common naming model, based on object names , across all management applications and makes its MBeans, and the manageable resources they represent, available to multiple management applications. MBeans become available to JMX management applications when they are added to an MBeanServer's registry, and when an MBean is removed from the registry it is no longer available to those applications. An MBean is registered with an MBeanServer, and the attributes and methods in its management interface are accessible via MBeanServer methods.

5.3.1 MBean Lifecycle Methods

The MBeanServer provides a set of lifecycle methods. These methods provide the mechanism for adding MBeans to the MBeanServer's registry and removing MBeans from that registry. In addition, there are methods that allow management applications to instantiate new MBeans via the MBeanServer.

5.3.1.1 Instantiation

At the beginning of this chapter we said that an MBean's management lifecycle begins when it is registered with an MBeanServer. Of course an MBean has to exist before it can be registered. One obvious way to instantiate an MBean is to call one of its constructors directly. The MBeanServer also provides a suite of methods that management applications can use to create new MBeans without directly invoking a constructor:

 public Object instantiate(String classname)  public Object instantiate(String classname,                           Object[] params,                           String[] signature) public Object instantiate(String classname, ObjectName loader) public Object instantiate(String classname,                           ObjectName loader,                           Object[] params,                           String[] signature) 

If the class named in the first argument has a no-args constructor, no additional arguments are required; the designated class will be loaded and the no-args constructor invoked to create a new instance. If the class doesn't provide a no-args constructor, or if the management application needs to use a different constructor, we can implicitly specify one by providing a signature and the actual arguments to the constructor in the signature and params arguments. After the class is loaded, the constructor with the specified signature will be invoked with the values given in the params array to generate a new instance of the class.

What about the loader parameter? The loader parameter indicates the object name of the MLet (management applet) that should be used to load the specified class. (See Chapter 7 for the details on MLets, or for now, just think of them as a form of class loader.) When a loader's object name is specified, we use the MLet referred to by that name to load the class. What about when no loader is specified? In that case the MBeanServer turns to DefaultLoaderRepository . DefaultLoaderRepository is the collection of loaders that includes the class loader that loaded the MBeanServer and all of the MLets registered with the MBeanServer. When no loader is specified, the MBeanServer iterates over DefaultLoaderRepository 's collection of loaders looking for one that can load the specified class. If it finds one, the class instance is created as described already; if not, an instance of ReflectionException that wraps java.lang.ClassNotFoundException is thrown.

This is all well and good, but why bother with instantiate() ? Why not just use the class's constructor without all this indirection? The reason is that the management application's class loader may not have access to the desired class. We won't go into all the details here, but the bottom line is that the MLet mechanism allows us to specify additional code sources that the MBeanServer's instantiate() and createMBean() methods can use to load classes. So in some cases even though the application's class loader may not know how to load a given class, the MBeanServer does have the necessary information and the application can use its instantiate() method to create instances of that class.

5.3.1.2 Registration

Once we have a reference to an instance of an MBean, it can be registered through this statement:

 ObjectInstance registerMBean(Object mbean, ObjectName objname) 

The registerMBean() method takes MBean's object reference and an ObjectName instance as parameters, creates an entry associating the two in the MBeanServer's registry, and returns an instance of ObjectInstance that maps ObjectName to the underlying Java class, as discussed earlier.

5.3.1.3 Creation

The "instantiate, then register" approach just described is a natural one for Java programmers used to working with Collection classes and the like, but it has the disadvantage of leaving a "live" reference to the MBean in the management application. JMX solves this problem by providing MBeanServer methods that, from a management application's perspective, automatically instantiate and register an instance of an MBean. The signatures for these methods are shown here:

 ObjectInstance createMBean(String mbeancls,                             ObjectName objname); ObjectInstance createMBean(String mbeancls,                            ObjectName objname,                            Object[] params,                            String[] sig); ObjectInstance createMBean(String mbeancls,                            ObjectName objname,                            ObjectName loader); ObjectInstance createMBean(String mbeancls,                            ObjectName objname,                            ObjectName loader,                            Object[] params,                            String[] sig); 

The mbeancls and objname parameters that are common to all of these methods specify the fully qualified class name for the MBean and the object name under which an instance of that class is to be registered, respectively. As in the instantiate() methods, the loader parameter is used to indicate the object name of the MLet that should be used to load the MBean's class.

When the params and sig array pairs are not present, createMBean() uses Java reflection to invoke the no-args constructor on the specified class and registers the resulting instance under the given ObjectName instance. When the params and sig parameters are present, the mbeancls constructor whose parameter types match the class name strings in the sig array is invoked, again via Java reflection, with the parameters provided by the params array. Note that the class name strings in the sig array must be the fully qualified class names for the parameters; for example, if there is a String parameter in the params array, the corresponding element in the sig array must be "java.lang.String".

For example, consider the following simple MBean interface:

 public interface SimpleSwitchMBean {    public void flip();   public int getState(); } 

and the SimpleSwitch class that implements it:

 public class SimpleSwitch implements SimpleSwitchMBean {    private int state;   public SimpleSwitch() {this(0); }   public SimpleSwitch(int state) {this.state = state; }   public void flip() {state = (state == 0) ? 1 : 0; }   public int getState() {return state; } } 

The following code registers three separate SimpleSwitch MBeans with an MBeanServer:

 MBeanServer mbs = MBeanServerFactory.createMBeanServer();  // Instantiate and register ObjectName sone = new ObjectName("book:name=SwitchOne"); mbs.registerMBean(new SimpleSwitch(), sone); // Create via no-args constructor ObjectName stwo = new ObjectName("book:name=SwitchTwo"); mbs.createMBean("SimpleSwitch", stwo); // Create via specific constructor ObjectName sthree = new ObjectName("book:name=SwitchThree"); Object[] params = {new Integer(1) }; String[] sig = {"java.lang.Integer" }; mbs.createMBean("SimpleSwitch", sthree, params, sig); 

Even though the calls are relatively simple, what's going on under the covers is complex, and lots of things can go wrong. When something does go wrong, an exception is thrown to indicate there is a problem. All told, createMBean() has six possible exceptions in its throws clause, and registerMBean() has four. By far the most common are

  • ReflectionException , which wraps an exception that occurred while createMBean() was trying to invoke the MBean's constructor. Usually the wrapped exception is an instance of java.lang.ClassNotFoundException . ReflectionException provides a getTargetException() method that returns the wrapped exception.

  • MBeanException , which indicates that the MBean's constructor threw an exception. MBeanException also provides a getTargetException() method that returns the exception thrown by the constructor.

  • RuntimeOperationsException , which generally wraps an instance of IllegalArgumentException and indicates that one of the parameters of createMBean() or registerMBean() was bogus .

5.3.1.4 The MBeanRegistration Interface

Once a JMX developer has a handle on creating MBeans and adding them to an MBeanServer, he inevitably confronts one or more of the following questions:

  • How do I know when my MBean is (de)registered?

  • How does my MBean get access to the MBeanServer it's registered with?

  • How does my MBean know its name?

  • How can I prevent my MBean from being registered with an MBeanServer?

  • How can I specify an action for my MBean to take immediately after it is (de)registered?

Although these questions could be answered in a variety of ad hoc ways, the JMX specification defines the MBeanRegistration interface to address each of them in a simple, flexible, and consistent manner. The MBeanRegistration interface is composed of four methods:

 ObjectName preRegister(MBeanServer mbserver, ObjectName objname);  void postRegister(Boolean registered); void preDeregister(); void postDeregister(); 

As the names suggest, these methods are invoked before and after registration and before and after deregistration, respectively. The state chart in Figure 5.2 illustrates the invocation of each of these methods as an MBean moves through its lifecycle.

Figure 5.2. MBean Registration States and Actions

graphics/05fig02.gif

When an MBean is registered, the MBeanServer inspects it to see if it implements the MBeanRegistration interface. If it does, the MBean's preRegister() method is called with a reference to the MBeanServer it is being registered with and a proposed object name. The ObjectName instance is the parameter passed to the createMBean() or registerMBean() method that started the registration process. If that ObjectName instance is null , then the MBean must provide its own object name; otherwise the proposed name may be accepted unchanged or augmented by the MBean ”for example, by the addition of other key properties. In either case the name that is ultimately chosen and returned by preRegister() is the name under which the MBean is registered. If the MBean will need access to the MBeanServer ”for example, to inspect the attributes or invoke the methods of other MBeans ”it should save the reference provided for that purpose.

The MBeanServer catches any exception thrown by the preRegister() method. If the exception is an instance of MBeanRegistrationException , it is simply rethrown. Otherwise the actual exception is wrapped in MBeanRegistrationException , which is then thrown by the MBeanServer. When preRegister() throws an exception, the MBean is not registered with the MBeanServer.

The postRegister() method is invoked immediately after registration. If the registration succeeded, postRegister() 's registered parameter is true . If the registration failed ”for example, if preRegister() threw an exception ” registered is false . MBeans should use postRegister() to perform additional setup and configuration actions: adding notification listeners, creating additional MBeans, allocating resources, and so on.

The preDeregister() and postDeregister() methods are the deregistration analogs of preRegister() and postRegister() , respectively. The MBeanServer invokes preDeregister() prior to removing an MBean from its registry, and postDeregister() immediately after an MBean is deregistered. Exceptions thrown by preDeregister() , like those thrown by preRegister() , are caught by the MBeanServer, wrapped in MBeanRegistrationException and rethrown. If an exception is thrown by preDeregister() , the MBean is not deregistered and postDeregister() is not invoked.

Note that throwing an exception in preRegister() prevents the MBean from being registered, whereas throwing an exception in preDeregister() prevents the MBean from being deregistered. The former behavior can be useful when the MBean's environmental requirements aren't satisfied ”for example, when the database it needs to connect to isn't up, or a license for the MBean can't be obtained from a license server. The latter behavior can be used to prevent an active MBean from being deregistered until either all outstanding requests have been serviced or the service that the MBean manages has been shut down.

5.3.1.5 Deregistration

MBeans are removed from the MBeanServer's registry with the following statement:

 void unregisterMBean(ObjectName objname); 

Deregistering an MBean makes it inaccessible through the MBeanServer interface. From a JMX perspective the resource represented by the MBean is no longer manageable. Of course, if the MBean was instantiated outside the MBeanServer and then registered, any reference to it retained by the application is still valid. MBeans created by a call to one of the createMBean() methods become candidates for garbage collection.

5.3.2 MBean Access Methods

The MBeanServer provides a common interface to the MBeans in its registry. That interface consists of six methods:

 Object getAttribute(ObjectName objname, String attr);  AttributeList getAttributes(ObjectName objname, String[] attrs); void setAttribute(ObjectName objname, Attribute attr); AttributeList setAttributes(ObjectName objname,     Attribute[] attrs); Object invoke(ObjectName objname,               String method,               Object[] params,               String[] sig); MBeanInfo getMBeanInfo(ObjectName objname); 

The ObjectName parameters in these APIs refer to MBeans registered with the MBeanServer. The getAttribute() and getAttributes() methods return the values of the specified MBean's attributes, setAttribute() and setAttributes() set the values of the specified MBean's attributes, and invoke() executes an operation on the specified MBean.

Three additional convenience methods exist to simplify common management application tasks :

 ObjectInstance getObjectInstance(ObjectName objname);  boolean isInstanceOf(ObjectName objname, String cls); boolean isRegistered(ObjectName objname); 

The getObjectInstance() method returns the ObjectInstance for the specified object name or throws an InstanceNotFoundException if an MBean is not registered under that name. As we discussed earlier, ObjectInstance provides a mapping between an MBean's object name and the MBean's underlying Java class. Given an arbitrary MBean's object name, a management application can get the name of the Java class that implements it as follows :

 String cls = mbs.getObjectInstance(objname).getClassName(); 

where mbs is a reference to an MBeanServer and objname is the object name of the MBean whose implementation class we are interested in.

The isInstanceOf() method answers the question, Is the MBean associated with this object name implemented by the specified class? Like getObjectInstance() , isInstanceOf() throws an InstanceNotFoundException if an MBean is not registered under the given object name.

Finally, isRegistered() gives us a way to check whether an MBean is registered with the specified object name before invoking getObjectInstance() or isInstanceOf() .

5.3.3 MBeanServer Methods

The MBeanServer also provides a couple of convenience methods that provide access to information about the MBeanServer itself:

 public String getDefaultDomain()  public Integer getMBeanCount() 

These methods do what their names imply. The getDefaultDomain() method returns the MBeanServer's default domain string, and getMBeanCount() returns the number of MBeans currently registered with the MBeanServer. Both methods tend to be used in JMX "console" applications that provide an MBeanServer GUI.



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