SpoonJMX: a MBean generator
JMX is the specification for the management of Java-based applications. Initially adopted by the JavaEE community, JMX is now included in Java Platform 5.0 (ie Standard Edition). MBeans (Manageable Beans) are software components used for application configuration and monitoring. More on JMX ...
SpoonJMX is a tool for generating MBeans by annotating a POJO (ie. Plain-Old Java Object) according to the JSR 255.
JMX annotations
SpoonJMX uses the following annotations:
- @javax.management.ManagedResource: to annotate the class to decorate as a DynamicMBean,
- @javax.management.ManagedAttribute: to make a field as an MBean's attribute,
- @javax.management.ManagedConstructor: to instantiate the MBean for the MBeanServer,
- @javax.management.ManagedOperation: to make a method as a MBean's operation,
- @javax.management.ManagedOperationParamater: to decribe the parameters of an operation or of a constructor.
- @javax.management.ObjectNameKey: to add name-value pairs in the MBean's object name
- @javax.management.DescriptorKey: to describe properties associated to attributes and parameters
The JMX annotations are annotated with AVal annotations to help the MBean developer to set the right annotations.
SpoonJMX generation
The SpoonJMX processor can add the following interfaces (and implemented methods) to a object class: javax.management.DynamicBean, javax.management.NotificationBroadcaster, javax.management.MBeanRegistration
Compiling SpoonJMX
Download spoon-core and spoon-aval jarfiles and install within the Maven2 local repository (mvn install:install-file) or checkout the 2 projects from the Forge and build then with Maven (mvn clean install).
Build SpoonJMX with Maven2 (mvn clean install)
Examples
The files in the ./src/examples/java directory illustrate the usage of the JMXProcessor Ant task.
When compiled, the Hello.java file (see the directory src/examples/java/spoon/jmx/example/) is genareted into a DynamicMBean (see ./target/spooned.src/ for the transformed code). The example includes a simple MBeanServer (AdvancedAgent.java), which instantiates and registers 2 MBeans.
Execute the example (mvn exec:java)
To browse the example:
- use the JConsole 5 or 6 or the MC4J to connect the MBeanServer with this url service:jmx:rmi:///jndi/rmi://localhost:9999/server or with a local connection
- connect to the server (with a local connection)
MBean Server Connection
- select the MBean named spoon.example:type=hello
- select the tab Information
MBean information
- select the tab Attributes and modify the attribute counter
MBean Attributes
- select the tab Operations and execute the sayHello method
Operation
Operation
- select the tab Notification, subscribe to the notification and modify the attribute counter in the tab Attributes : the update is notified
MBean Notification history
TODOLIST
- see the TODOLIST.txt file in the project
References
- JMX Homepage
- JMX-related JSRs
- My course on JMX (mix of french and english
- Apache Felix MOSGi (MBeans are generated with an extension of SpoonJMX for OSGi : available soon !).
- Glassbox Inspector (this project combines AspectJ and JMX), https://glassbox-inspector.dev.java.net/
- Éamonn McManus, Jean-François Denise, Java Management Extensions (JMX) Technology Today and Tomorrow, Session TS-3523, JavaOne Conference 2006, http://java.sun.com/javaone/sf/2006.
- JSR 255: JavaTM Management Extensions (JMXTM) Specification, version 2.0 http://jcp.org/en/jsr/detail?id=255
Example of annotated POJO
The following POJO class Hello is annotated in order to be decorated as a DynamicMBean.
import javax.management.*;
@ManagedResource(
objectName = "spoon.example:type=hello",
description = "a simple mbean"
)
public class Hello {
@ManagedAttribute(
name = "prefix",
description = "a read write attribute",
notification = true,
mode=AccessType.READWRITE
)
private String prefix = null;
@ManagedAttribute(
name = "counter",
description = "a read only attribute",
notification = true,
mode=AccessType.READONLY
)
@Unit("Unit")
@Range(minValue=0,maxValue=10000)
private int count = 0;
@ManagedAttribute(
description = "a read only attribute"
// notification = false, // default for final field
// mode=AccessType.READONLY // default for final field
)
private final int finalatt = 0;
@ManagedAttribute(
name = "globalCounter",
description = "a read only attribute on a static field",
notification = true,
mode=AccessType.READONLY
)
private static int staticCount = 0;
/**
* Not in the MBeanInfo
*/
private int notatt = 0;
public Hello() {
prefix = "Hello ";
System.out.println("instance " + Hello.class.getName() + " with "
+ prefix);
}
@MManagedConstructor(name="Hello", description="a simple constructor")
public Hello(
@ManagedOperationParamater(name = "prefix", description = "a prefix")
String prefix) {
this.prefix = prefix;
System.out.println("instance " + Hello.class.getName() + " with "
+ prefix);
}
@ManagedOperation(name = "sayHello", description = "a simple operation")
public void sayHello(
@ManagedOperationParamater(name = "message", description = "a message")
String message
) {
System.out.println(prefix+message);
count++; // triggers off a notification
staticCount++; // triggers off a notification
}
@ManagedOperation(name = "reset", description = "reset the counter")
private void reset() {
count=0;
}
// this annotation should add a attribute "name" to the objectName after pre-registration
@ObjectNameKey("name")
private String getName() { return "hello1"; }
/**
* Not in the MBeanInfo
*
*/
public void noop() {}
}
The next code section instantiates and registeres the hello MBean with the name returned by the method preRegister of the MBeanRegistration interface. The returned objectName is the one provided by the annotation (ie. spoon.example:type=hello).
ObjectInstance objectInstance; ObjectName objectName; objectInstance = mbeanServer.registerMBean( new Hello(), null); // take the annotated objectName objectName = objectInstance.getObjectName(); if(objectName==null) print(objectName.getCanonicalName() + " registered"); ...
The next code section instanciates and registeres the hello MBean with the objectName spoon.example:type=hello2.
...
objectInstance = mbeanServer.registerMBean(
new Hello(),
new ObjectName("spoon.example:type=hello2"));
objectName = objectInstance.getObjectName();
if(objectName==null)
print(objectName.getCanonicalName() + " registered");
...
Misc
Remarks and contributions are welcome !
Last modified: January 24, 2008, at 12:20 AM donsez







