Register MBeans in Apache Karaf

Just a quick note about how your OSGi application can register MBeans in Karaf’s platform.
Apache Karaf comes with its own JMX server and a global configuration you can find under its etc directory. Configuration goes from the server’s URL and remote access security, to a fine-grained permission system (e.g. who can access this or that MBean). For more details about what this, you can refer to the official documentation of Karaf.

Now, let’s assume you want to expose custom MBeans in Karaf’s platform.
How to proceed? Well, Karaf’s management feature comes with Apache Aries. The JMX component of this project is the Reference Implementation of the OSGi JMX Management Model Specification. This specification indicates how one can easily register MBeans within OSGi thanks to the white board pattern.

The only thing you have to do is to register a service that respects JMX naming conventions and that has the jmx.objectname property. Every time such a service is registered, Aries is notified and registers a MBean from it. If you remove the service, the MBean will be unregistered too. So, you only have to register a service! And that’s great. Then, you are plugged with Karaf’s JMX configuration, meaning you can easily integrate with other tools like Apache Decanter and its JMX collector.

How to register such a service?
You can do this programmatically…

BundleContext bundleCtx = osgiHelper.findBundleContext();
if( bundleCtx != null ) {

	this.logger.fine( "Running in an OSGi environment. Trying to register a MBean for the messaging." );
	Dictionary<String,String> properties = new Hashtable<> ();
	properties.put( "jmx.objectname", "net.roboconf:type=messaging" );
	try {
		this.serviceReg = bundleCtx.registerService( MessagingApiMBean.class, this, properties );
		this.logger.fine( "A MBean was successfully registered for the messaging." );

	} catch( Exception e ) {
		this.logger.severe( "A MBean could not be registered for the messaging." );
		Utils.logException( this.logger, e );
	}
}

… or with a framework, like iPojo (here with a metadata.xml file).

<ipojo 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd"
		xmlns="org.apache.felix.ipojo">

	<!-- Servlets registration -->
	<component classname="net.roboconf.dm.rest.services.internal.ServletRegistrationComponent" name="roboconf-dm-rest-component" immediate="true" public="false">

		<!-- Mandatory -->
		<requires field="manager" optional="false" />
		<requires field="httpService" optional="false" />

		<!-- Optional: Maven resolver -->
		<requires field="mavenResolver" optional="true">
			<callback type="bind" method="mavenResolverAppears" />
			<callback type="unbind" method="mavenResolverDisappears" />
		</requires>

		<!-- Optional: scheduler -->
		<requires field="scheduler" optional="true">
			<callback type="bind" method="schedulerAppears" />
			<callback type="unbind" method="schedulerDisappears" />
		</requires>

		<callback transition="validate" method="starting" />
		<callback transition="invalidate" method="stopping" />

		<properties pid="net.roboconf.dm.rest.services.configuration">
			<property name="enable-cors" method="setEnableCors" value="false" />
			<property name="enable-authentication" method="setEnableAuthentication" value="false" />
			<property name="authentication-realm" method="setAuthenticationRealm" value="karaf" />
			<property name="session-period" method="setSessionPeriod" value="-1" />
		</properties>

		<!-- Register OSGi services -->
		<!-- The implementation class also registers additional services... -->
		<provides specifications="net.roboconf.dm.rest.services.jmx.RestServicesMBean">
			<property name="jmx.objectname" value="net.roboconf:type=web" type="java.lang.String" />
		</provides>
	</component>

	<instance component="roboconf-dm-rest-component" name="Roboconf - DM REST services" />
</ipojo>

My example may look a little bit complex.
The interesting part is the provides section, which declares the service to register. Notice the service property. You can obviously use any framework (Blueprint, Declarative Services), no matter how you register your service, provided you actually do register it.

Here are some pointers to real implementations.
The code approach is used here to create MBeans on the fly for objects that are not managed as OSGi services. The framework approach is perfect when you want to associate MBeans with predefined OSGi services.

As usual, the interface of your service must be exported outside your bundle. This is fundamental! You must also respect JMX conventions. All my service interfaces for JMX have their name that end with MBean (and it is case sensitive). My implentation classes can use whatever names they want. You will find additional information on Apache Aries’s web site.


About this entry