MX4J provides a way to generate source code of MBean interfaces and descriptions using some custom javadoc comments in source code. This source generation is done with the help of XDoclet. It is recommended to look at the example included in the distribution for getting started with this feature.
In order to generate the source code, XDoclet must be copied into the directory where all libraries are. This is usually the lib subdirectory of the project which will be referred as the Ant variable ${lib} from now on. A path must be defined for the Ant task. An example is given below:
Example 7.6. Defining the xdoclet classpath and Ant task.
<path id="xdoclet"> <pathelement location="${lib.dir}/xjavadoc.jar"/> <pathelement location="${lib.dir}/xdoclet.jar"/> <pathelement location="${lib.dir}/xdoclet-jmx-module.jar"/> <pathelement location="${lib.dir}/xdoclet-mx4j-module.jar"/> <pathelement location="${lib}/log4j.jar"/> <pathelement location="${ANT_HOME}/lib/ant.jar"/> <pathelement location="${build}"/> </path> <taskdef name="jmxdoclet" classname="xdoclet.jmx.JMXDocletTask"> <classpath refid="xdoclet"/> </taskdef>
Let's suppose now that the Ant compilation target is called compilation. The easiest way to generate the source code of the MBean interface and description is to make the compilation depending on the target generateJMX defined by:
Example 7.7.
<target name="generate-jmx" depends="init"> <!-- Generate the MBean interfaces and descriptions --> <jmxdoclet sourcepath="${src}" destdir="${src}" classpathref="xdoclet" force="yes"> <fileset dir="${src}"> <include name="com/xtremejava/webos/**" /> </fileset> <!-- Create the {0}MBean interface for the MBean --> <mbeaninterface/> <!-- Create the MX4J specific description adaptor class for the MBean --> <mx4jdescription /> <!-- Generate the mlet file --> <mlet destinationFile="mbeans.mlet" destdir="conf"/> </jmxdoclet> </target>
A few javadoc tags can be used in order to specify how to generate the interface and the description of your MBean.
Table 7.1. List of Javadoc tags
Javadoc Tag Name | Meaning |
---|---|
@jmx:mbean | Tag used in order to define the name of the MBean and its description. Must be defined at class level. |
@jmx:managed-constructor | Tag used in order to define the name of the constructor and its description. Must be defined at constructor level. |
@jmx:managed-constructor-parameter | Tag used in order to define the name of a constructor attribute, it's index, and its description. Must be defined at constructor level. |
@jmx:managed-operation | Tag used in order to define the name of an operation and its description. Must be defined at method level. |
@jmx:managed-operation-parameter | Tag used in order to define the name of an operation attribute, it's index, and its description. Must be defined at method level. |
@jmx:managed-attribute | Tag used in order to define the description of an attribute. Must be defined at method level. Note: the getter description has priority over the setter description. |
@jmx:mlet-entry | Tag used in order to generate the mlets file. All classes having this tags will have the result merge in one file. Must be defined at class level. |
This example will cover the usage of the FilePersister with MLets. It will give a good overview of how to use MLets into the bargain :-). What we will do is create two MBeans the one extends FilePersister, so that it can load and store Objects. The other is a standard MBean which will ask the FilePersisterMBean to store it, The interesting thing about this example is that the two mbeans are loaded by two differnet MLets from two different jar files. One note of importance any object to be stored must implement the interface Serializable. Let us begin.
We are going to write an MBean which extends FilePersister and pass any calls made to it to its parent class.
Example 7.8. MBeanOne implementation
public class MBeanOne extends FilePersister implements Serializable { public MBeanOne(String location, String name) throws MBeanException { super(location, name); } public void store(Object mbean)throws MBeanException, InstanceNotFoundException { store(mbean); } public Object load()throws MBeanException, RuntimeOperationsException, InstanceNotFoundException { return load(); } }
Now to do the mbean that will ask the MBeanOne to store it.
Example 7.9. MBeanTwo implementation
public class MBeanTwo implements MBeanTwoMBean, Serializable { // constructor... see example //we are now going to invoke MBeanOne through the MBeanServer public void storeIt(MBeanServer server, ObjectName name) { server.invoke(name, "store", new Object[]{this}, new String[]{"java.lang.Object"}); } public Object loadIt(MBeanServer server, ObjectName name) { Object me = null; try { me = (MBeanTwo)server.invoke(name, "load", new Object[0], new String[0]); } catch (Exception ex) { ex.printStackTrace(); } return me; } }
The "main" class will now create and register two MLets, each MLet will load its own MBean from separate jar files
Example 7.10. The FilePersisterAgent
// Create the MBeanServer // Build the ObjectNames for the MLets // Register the MLets MLet mlet1 = new MLet(); m_server.registerMBean(mlet1, mName1); mlet1.addURL(jarOneUrl); MLet mlet2 = new MLet(); m_server.registerMBean(mlet2, mName2); mlet2.addURL(jarTwoUrl); // We now have access to the MBeans, so instantiate them m_server.createMBean(mbeanClassName, mbeanObjectName, mLetObjectName, params, signature); // As above but the other mbean is now registered using the othe MLet object name as the third parameter m_server.createMBean(.....); // Now invoke the storage of one MBean by the other m_server.invoke(mbeanName2, "storeIt", new Object[] {m_server, mbeanName1}, new String[]{"javax.management.MBeanServer", "javax.management.ObjectName"}); // Now load it Object a = m_server.invoke(mbeanName2, "loadIt", new Object[] {m_server, mbeanName1}, new String[]{"javax.management.MBeanServer", "javax.management.ObjectName"}); // And finally a test to see that the objects are equal if(a.getClass().getName() == mbeanClass2) System.out.println("Objects are equal and the same");
Once you have the files and compiled them you will need to build the jars holding the mbeans start a command prompt (windows) cd to the examples/classes directory and type in the following commands:
Example 7.11.
jar cvf one.jar examples/tools/persister/MBeanOne.class // and then jar cvf two.jar examples/tools/persister/MBeanTwo.class examples/tools/persister/MBeanTwoMBean.class
Now delete the MBeanOne.class and MBeanTwo.class (we do not want them in the classpath :-). Once this is done add four application parameters
You are now ready to start the agent! Have fun !!