Author: [email protected]>
<Sun release in fall 2000 the final specification, API and Reference Implemenation to the Java Management Extention(JMX) . The idea behind this is to provide an API to which the component vendors can make their components manageable and the management tools vendor can use this API to manage these components.
Therefore the whole JMX is separated into 3 parts:
Components implement a certain API to offer their management API to the JMX world. There are 3 ways: through an Interface, through a API descriptions (Open MBean) and through a Model MBean (but for this have a look at the spec).
JMX Agent which contains a MBean Server, certain services like dynamic download, timers, relations etc. and at least one Connector or Adaptor.
Management Tool using a Connector or Adaptor to manage the components of the JMX Agent the tool is connected to.
At the moment (8th of September 2000) JBoss uses the final release JMX API for its services defined in the jboss.conf file (in there you see that also HTML Adaptor and the JMX Connector are manageable components). In addition JBoss use the MBean Server implementation and the HTML adaptor from the JMX-RI. The JMX Connector also follows the JMX final spec and API.
You use JMX first when you start JBoss because the Main class loads the <mbean> tags from the jboss.jcml file and hand it over to the MBeanServer which loads the MBean dynamically (originally in JMX MLET tags are used to dynamically load a MBean by the MBeanServer but they were troublesome use). Afterwards it went through the loaded MBeans and starts all the loaded MBeans.
Afterwards you can use JMX either trough the JMX HMTL Adaptor on port 8082 or through the new JMX Connector. The JMX HTML Adaptor is provided by the JMX-RI and the source code is not available (it is part of Sun's JDMK which you have to buy when you want to get the source as far as I know). The JMX Connector is part of the JBoss code and should be considered as first draft because the Connector is mentioned within the spec by not further specified (Sun's JDMK also has a RMI-Connector but JDMK is very pricy).
Finally JMX is used within the shutdown hook and ServiceControl MBean to terminate all the services before JBoss is terminated itself (whatever this means) by going through all available MBeans and send them the stop signal (call the appropriate method). This let you shutdown JBoss gracefully even programatically.
According to the JMX spec the Connector should allow a management tool to work on a MBeanServer and its MBeans from another JVM which can be on the same computer or a remote computer. One particular Connector is bound to its protocol it supports but a MBeanServer can offer more than one (a JMX agent has to offer at least an Adaptor or a Connector) supporting different protocols. Because the spec does not say much about Connectors I take the freedom and implemented the actual Connector within JBoss to lay the base for a remote JBoss management which is a little bit more comfortable than the HTML Adaptor.
By the way I will take this opportunity to thanks Rickard Öberg for his support.
These are my goals for a JMX Connector:
According to the spec the JMX Connector should offer the client a Proxy for a remote MBean but then the MBean proxy must be available at compile time and this compete with the JMX agent requirements that an JMX agent has to support dynamic loading of MBeans therefore this is not supported now.
The server-side implementation is loaded and started by the MBeanServer which should become available for remote management. For this we have the necessary MBean service classes, the Connector implementation and an Object Handler class. The Object Handler class is a serializable class allowing the remote client to deal with remotely instantiated classes. This eliminates problems with not serializable classes and with the unique identification of serialized classes (on a round trip you get a copy of the original instance).
The Object Handler is also used to avoid troubles with not serializable classes used as a Handback object in the Notification handling. This class allows the client to work on the JMX Connector as he would work on a local MBeanServer.
The client-side implementation can either be used directly by instantiating the RMIClientConnectorImpl or by using the Connector Factory. The client-side Connector is more or less a MBeanServer which sends the request over the supported protocol to the server-side connector and returns the returned object back to the caller. There are a few methods which cannot be supported and therefore throw a unsupported operation exception.
To make it clear and also for documentation purpose the client-side connector implements the RemoteMBeanServer Interface. At the moment I want still keep this interface even when MBeanServer is now an interface too because which all good programming techniques it is (at least at the moment) not possible to make it 100% transparent (but see later under limitations).
When I started with the JMX Connector I had a management tool in mind like the network administration tool from CA or the proposed AppCenter from Inprise. Therefore I want to make it as easy as possible for the client to connector as many remote MBeanServers as he/she wants and which any protocol available. The client should never have to worry about the protocol or to know which classes are behind. That's why I created the Connector Factory which allows the client to search for all the remote available MBeanServers and their supported protocols. The user only has to select a server and then a protocol and the Connector Factory returns the appropriate instance of the RemoteMBeanServer interface.
The JMX Connector Test Client is first a test tool that the JMX Connector is working and second a demonstration how to use it. The test tool first starts a local MBeanServer and register the Connector Factory as first and then only MBean. Now the test client ask the Connector Factory for all available, remote MBeanServers and let the user select one, then it asks the Connector Factory for all available Connectors or more precise all the supported protocols of the available Connectors. Now the user can select the protocol and the Test Client loads and starts the appropriate Connector (if available) and register it as a new MBean at the local MBeanServer. Afterwards it asks the Connector for all available MBeans on the remote server, displays it wit all the attributes and operations on this remote MBean. At the end it will try to register to all remote MBeans a notification listener which will inform the client about notification send by the MBean. That's why the test client will still run after finishing. When the user terminates the Test Client it will remove all the notification listeners from the remote MBeanServer and terminate the Test Client.
Instantiate the RMIClientConnectorImpl.
RemoteMBeanServer lConnector = new RMIClientConnectorImpl("server-name" );
Use either instance or its interface RemoteMBeanServer or MBeanServer. If you got back an instance you can now work on the remote MBeanServer like it would be a local one.
Look up for the available MBeans, its attributes and operations. You can now retrieve and set the attributes or perform an operation on the remote MBean.
If you register a Notification Listener then stop this instance before terminating the program otherwise the remote MBeanServer will throw an exception when this Notification Listener is called lConnector.stop();
First you have to make sure that the JNDI property: java.naming.provider.url points to the JNDI server your JMX Connectors are registered to. At the moment you can only have one JMX Connector running at the same computer (but serveral can be registered at the same JNDI server) and you can only have one JNDI server.
import com.sun.management.jmx.MBeanServerImpl; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; import javax.management.Notification; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.ReflectionException; import javax.management.RuntimeErrorException; import javax.management.RuntimeMBeanException; import javax.management.RuntimeOperationsException; import javax.naming.InitialContext; import org.jboss.jmx.interfaces.RemoteMBeanServer; import org.jboss.jmx.client.RMIClientConnectorImpl;
Instantiate a local MBeanServer (MBeanServerImpl)
final MBeanServer lLocalServer = new MBeanServerImpl();The local variable is made final because it is needed in the shutdown hook.
Load the logger MBean (is needed now because the Connector Factory is a standard JBoss MBean but maybe I should make it to a normal MBean to make it leaner).
lLocalServer.createMBean( "org.jboss.logging.Logger", new ObjectName( "DefaultDomain :name=Logger" ) );
Load and start the ConnectorFactory MBean
final ObjectInstance lFactoryInstance = lLocalServer.createMBean( "org.jboss.jmx.client.ConnectorFactoryService", new ObjectName( "DefaultDomain:name=ConnectorFactory" ) );
Look for the list of remote Connectors at a given JNDI server (lContext.getEnvironment() returns the actual properties from a given InitialContext).
Hashtable lProperties = lContext.getEnvironment(); ConnectorFactoryImpl.JBossConnectorTester lTester = new ConnectorFactoryImpl.JBossConnectorTester(); Iterator lConnectors = (Iterator) lLocalServer.invoke( lFactoryInstance.getObjectName(), "getConnectors", new Object[] { lProperties, lTester }, new String[] { lProperties.getClass().getName(), lTester.getClass().getName() } );
Create a connection to the selected Connector (lConnectorName is an instance returned by the previous retrieved iterator). The ConnectorName contains the information about the server, protocol and the JNDI name of a found JMX Connector.
RemoteMBeanServer lConnector = (RemoteMBeanServer) lLocalServer.invoke( lFactoryInstance.getObjectName(), "createConnection", new Object[] { lConnectorName }, new String[] { lConnectorName.getClass().getName() } );
Use the new Connector MBean on the local MBeanServer to get and set the attributes and perform operation on the chosen MBeans on the remote MBeanServer.
Iterator i = pConnector.queryMBeans( null, null).iterator(); while( i.hasNext() ) { MBeanInfo info = pConnector.getMBeanInfo( ( (ObjectInstance) i.next()).getObjectName() ); MBeanAttributeInfo[] aInfos = info.getAttributes(); ... MBeanOperationInfo[] oInfos = info.getOperations(); }
Register a Notification Listener on a remote MBean and wait for notification events sent from the remote MBean. The NotSerializableHandback is a helper class to be a serializable proxy for a Handback which maybe is not serializable.
Iterator i = pConnector.queryMBeans( null, nullitemizedlist).iterator(); int j = 0; while( i.hasNext() ) { ObjectInstance lBean = (ObjectInstance) i.next(); try { pConnector.addNotificationListener( lBean.getObjectName(), (NotificationListener) new Listener(), (NotificationFilter) null, new NotSerializableHandback( lBean.getObjectName() + "" + j++ ) ); ...But when you terminate the connector you have to remove the connection by using the Connector Factory to remove all the Notification Listener from the remote MBeanServer.
lLocalServer.invoke( lFactoryInstance.getObjectName(), "removeConnection", new Object[] { lConnectorName }, new String[] { lConnectorName.getClass().getName() } );
This list contains all the stuff to be done to make the JMX Connector full fledged:
This list contains all the stuff to be done around JMX
If anything is wrong or not correct please contact me at [email protected]. Also if you want to know more in detail or have a request for changes in the JMX Connector.