Integrating Services with the JMX Console integrating-services-with-the-jmx-console
Create and deploy MBeans to manage services using the JMX Console. Expose service attributes and operations to enable administration tasks to be performed.
For information about using the JMX Console, see Monitoring Server Resources Using the JMX Console.
The JMX Framework in Felix and CQ5 the-jmx-framework-in-felix-and-cq
On the Apache Felix platform, you deploy MBeans as OSGi services. When an MBean service is registered in the OSGi Service Registry, the Aries JMX Whiteboard module automatically registers the MBean with the MBean Server. The MBean is then available to the JMX Console which exposes the public attributes and operations.
Creating MBeans for CQ5 and CRX creating-mbeans-for-cq-and-crx
MBeans that you create for managing CQ5 or CRX resources are based on the javax.management.DynamicMBean interface. To create them you follow the usual design patterns as outlined in the JMX specification:
- Create the management interface, including get, set, and is methods to define attributes, and other methods to define operations.
- Create the implementation class. The class must implement DynamicMBean, or extend an implementation class of DynamicMBean.
- Follow the standard naming convention so that the name of the implementation class is the interface name with the MBean suffix.
In addition to defining the management interface, the interface also defines the OSGi service interface. The implementation class implements the OSGi service.
Using Annotations to Provide MBean Information using-annotations-to-provide-mbean-information
The com.adobe.granite.jmx.annotation package provides several annotations and classes for easily providing MBean metadata to the JMX console. Use these annotations and classes instead of adding information to the MBean’s MBeanInfo object directly.
Annotations
Add annotations to the management interface to specify MBean metadata. The information appears in the JMX console for each implementation class that is deployed. The following annotations are available (for complete information, see the com.adobe.granite.jmx.annotation JavaDocs):
-
Description: Provides a description of the MBean class or method. When used on the class declaration, the desctiption appears on the JMX Console page for the MBean. When used on a method, the desctiption appears as hover text for the corresponding attribute or operation.
-
Impact: The impact of a method. Valid parameter values are the fields defined by javax.management.MBeanOperationInfo.
-
Name: Specifies the name to display for an operation parameter. Use this annotation to override the actual name of the method parameter that is used in the interface.
-
OpenTypeInfo: Specifies the class to use for representing composite data or tabular data in the JMX Console. For use with Open MBeans
-
TabularTypeInfo: Used to annotate the class that is used to represent tabular data.
Classes
Classes are provided for creating Dynamic MBeans that consume the annotations that you add to their interfaces:
- AnnotatedStandardMBean: A subclass of the javax.management.StandardMBean class that automatically provides the JMX Console with the annotation metadata.
- OpenAnnotatedStandardMBean: A subclass of the AnnotatedStandardMBean class for creating Open Mbeans that consume the OpenTypeInfo annoatation…
Developing MBeans developing-mbeans
Typically, your MBean is a reflection on the OSGi service that you want to manage. On the Felix platform, you create the MBean as you would for deployment on other Java server platforms. A primary difference is that you can use annotations to specify MBean information:
- Management interface: Defines attributes using getter, setter, and is methods. Defines operations using any other public method. Uses annotations to provide metadata for the BeanInfo object.
- MBean class: Implements the management interface. Extends the AnnotatedStandardMBean class so that it processes the annotations on the interface.
The following example MBean provides information about the CRX repository. The interface uses the Description annotation to provide information to the JMX console.
Management Interface management-interface
package com.adobe.example.myapp;
import com.adobe.granite.jmx.annotation.Description;
@Description("Example MBean that exposes repository properties.")
public interface ExampleMBean {
@Description("The name of the repository.")
String getRepositoryName();
@Description("The vendor of the repository.")
String getRepositoryVendor();
@Description("The URL of repository vendor.")
String getVendorUrl();
}
The implementation class uses the SlingRepository service to retrieve information about the CRX repository.
MBean Implementation Class mbean-implementation-class
package com.adobe.example.myapp;
import org.apache.felix.scr.annotations.*;
import org.apache.sling.jcr.api.SlingRepository;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
import javax.management.*;
public class ExampleMBeanImpl extends AnnotatedStandardMBean implements ExampleMBean {
@Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
private SlingRepository repository;
public ExampleMBeanImpl() throws NotCompliantMBeanException {
super(ExampleMBean.class);
}
public String getRepositoryName() {
return repository.getDescriptor("jcr.repository.name");
}
public String getRepositoryVendor() {
return repository.getDescriptor("jcr.repository.vendor");
}
public String getVendorUrl() {
return repository.getDescriptor("jcr.repository.vendor.url");
}
}
The following graphic shows the page for this MBean in the JMX Console.
Registering MBeans registering-mbeans
When you register MBeans as an OSGi service, they are automatically registered with the MBean Server. To install an MBean on CQ5, include it in a bundle and export the MBean service as you would any other OSGi service.
In addition to the OSGi-related metadata, you must also provide metadata that the Aries JMX Whiteboard module requires for registering the MBean with the MBean Server:
-
The name of the DynamicMBean interface: Declare that the MBean service implements the
javax.management.DynamicMBea
n interface. This declaration notifies the Aries JMX Whiteboard module that the service is an MBean service. -
The MBean domain and key properties: On Felix, you provide this information as a property of the MBean’s OSGi service. This is the same information that you ordinarily provide to the MBean Server in a
javax.management.ObjectName
object.
When your MBean is a reflection of a singular service, only a single instance of the MBean service is required. In this case, if you use the Felix SCR Maven plugin, you can use the Apache Felix Service Component Runtime (SCR) annotations on the MBean implementation class to specify the JMX-related metatdata. To instantiate several MBean instances, you could create another class that performs that registration of the MBean’s OSGi service. In this case, the JMX-related metadata is generated at runtime.
Single MBean
MBeans for which you can define all the attributes and operations at design time can be deployed using SCR annotations in the MBean implementation class. In the following example, the value
attribute of the Service
annotation declares that the service implements the DynamicMBean
interface. The name
attribute of the Property
annotation specifies the JMX domain and key properties.
MBean Implementation Class with SCR Annotations mbean-implementation-class-with-scr-annotations
package com.adobe.example.myapp;
import org.apache.felix.scr.annotations.*;
import org.apache.sling.jcr.api.SlingRepository;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
import javax.management.*;
@Component(immediate = true)
@Property(name = "jmx.objectname", value="com.adobe.example:type=CRX")
@Service(value = DynamicMBean.class)
public class ExampleMBeanImpl extends AnnotatedStandardMBean implements ExampleMBean {
@Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
private SlingRepository repository;
public ExampleMBeanImpl() throws NotCompliantMBeanException {
super(ExampleMBean.class);
}
public String getRepositoryName() {
return repository.getDescriptor("jcr.repository.name");
}
public String getRepositoryVendor() {
return repository.getDescriptor("jcr.repository.vendor");
}
public String getVendorUrl() {
return repository.getDescriptor("jcr.repository.vendor.url");
}
}
Multiple MBean Service Instances
To manage multiple instances of a managed service, you create multiple instances of the corresponding MBean service. Furthermore, MBean service instances should be created or removed when managed instances are started or stopped. You can create an MBean manager class to instantiate MBean services at runtime, and manage the service lifecycle.
Use the BundleContext to register the MBean as an OSGi service. Include the JMX-related information in the Dictionary object that you use as an argument of the BundleContext.registerService method.
In the following code example, the ExampleMBean service is registered programmatically. The componentContext object is the ComponentContext, which provides access to BundleContext.
Code Snippet: Programmatic MBean Service Registration code-snippet-programmatic-mbean-service-registration
Dictionary mbeanProps = new Hashtable();
mbeanProps.put("jmx.objectname", "com.adobe.example:type=CRX");
ExampleMBeanImpl mbean = new ExampleMBeanImpl();
ServiceRegistration serviceregistration =
componentContext.getBundleContext().registerService(DynamicMBean.class.getName(), mbean, mbeanProps);
The example MBean in the next section provides more details.
An MBean service manager is useful when service configurations are stored in the repository. The manager can retrieve service information and use it to configure and create the corresponding MBean. The manager class can also listen for repository change events and update MBean services accordingly.
Example: Monitoring Workflow Models Using JMX example-monitoring-workflow-models-using-jmx
The MBean in this example provides information about the CQ5 Workflow models that are stored in the repository. An MBean manager class creates MBeans based on Workflow models that are stored in the repository and registers their OSGi service at runtime. This example consists of a single bundle containing the following members:
- WorkflowMBean: The management interface.
- WorkflowMBeanImpl: The MBean implementation class.
- WorkflowMBeanManager: The interface of the MBean manager class.
- WorkflowMBeanManagerImpl: The implementation class of the MBean manager.
Note: For simplicity, the code in this example does not perform logging or react to thrown exceptions.
WorkflowMBeanManagerImpl includes a component activation method. When the component is activated, the method performs the following tasks:
- Obtains a BundleContext for the bundle.
- Queries the repository to obtain the paths of the existing Workflow models.
- Creates MBeans for each Workflow model.
- Registers the MBeans with the OSGi service registry.
The MBean metadata appears in the JMX Console with the com.adobe.example domain, the workflow_model type, and Properties is the path of the workflow model condfiguration node.
The Example MBean the-example-mbean
This example requires an MBean interface and implementation that is a reflection on the com.day.cq.workflow.model.WorkflowModel
interface. The MBean is very simple so that the example can focus on the configuration and deployment aspects of the design. The MBean exposes a single attribute, the model name.
WorkflowMBean Interface workflowmbean-interface
package com.adobe.example.myapp.api;
import com.adobe.granite.jmx.annotation.Description;
@Description("Example MBean that exposes Workflow model properties.")
public interface WorkflowMBean {
@Description("The name of the Workflow model.")
String getModelName();
}
WorkflowMBeanImpl workflowmbeanimpl
package com.adobe.example.myapp.impl;
import javax.management.NotCompliantMBeanException;
import com.day.cq.workflow.model.WorkflowModel;
import com.adobe.example.myapp.api.WorkflowMBean;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
public class WorkflowMBeanImpl extends AnnotatedStandardMBean implements WorkflowMBean {
WorkflowModel model;
protected WorkflowMBeanImpl(WorkflowModel inmodel)
throws NotCompliantMBeanException {
super(WorkflowMBean.class);
model=inmodel;
}
public String getModelName() {
return model.getTitle();
}
}
The Example MBean Manager the-example-mbean-manager
The WorkflowMBeanManager service includes the component activation method that creates WorkflowMBean services. The service implmentation includes the following methods:
- activate: The componet activator. Creates the JCR session for reading WorkflowModel configuration nodes. The root node where model configurations are stored is defined in a static field. The name of the configuration node is also defined in a static field. This method calls other methods that obtain the node model paths and create the model WorkflowMBeans.
- getModelIds: Traverses the repository below the root node and retrieves the path of each model node.
- makeMBean: Uses the model path to create a WorkflowModel object, creates a WorkflowMBean for it, and registers its OSGi service.
WorkflowMBeanManager Interface workflowmbeanmanager-interface
package com.adobe.example.myapp.api;
public interface WorkflowMBeanManager {
}
WorkflowMBeanManagerImpl workflowmbeanmanagerimpl
package com.adobe.example.myapp.impl;
import java.util.*;
import org.apache.felix.scr.annotations.*;
import javax.jcr.Session;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.management.ObjectName;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.workflow.WorkflowService;
import com.day.cq.workflow.WorkflowSession;
import com.adobe.example.myapp.api.WorkflowMBean;
import com.adobe.example.myapp.api.WorkflowMBeanManager;
/**Instantiates and registers WorkflowMBean services */
@Component(immediate=true)
@Service(value=WorkflowMBeanManager.class)
public class WorkflowMBeanManagerImpl implements WorkflowMBeanManager {
//The ComponentContext provides access to the BundleContext
private ComponentContext componentContext;
//Use the SlingRepository service to read model nodes
@Reference
private SlingRepository repository = null;
//Use the WorkflowService service to create WorkflowModel objects
@Reference
private WorkflowService workflowservice = null;
private Session session;
//Details about model nodes
private static final String MODEL_ROOT ="/etc/workflow/models";
private static final String MODEL_NODE = "model";
private Set<String> modelIds = new HashSet<String>();
//Storage for ServiceRegistrations for MBean services
private Collection<ServiceRegistration> mbeanRegistrations= new Vector<ServiceRegistration>(0,1);
@Activate
protected void activate(ComponentContext ctx) {
//Traverse the repository and load the model nodes
try {
session = repository.loginAdministrative(null);
// load and store model node paths
if (session.nodeExists(MODEL_ROOT)) {
getModelIds(session.getNode(MODEL_ROOT));
}
//Create MBeans for each model
for(String modid: modelIds){
makeMBean(modid);
}
}catch(Exception e){ }
}
/**
* Add JMX domain and key properties to a collection
* Instantiate a WorkflowModel and its WorkflowMBeanImpl object
* Register the MBean OSGi service
*/
private void makeMBean(String modelId) {
// create MBean for the model
try {
Dictionary<String, String> mbeanProps = new Hashtable<String, String>();
//These properties appear on the JMX Console home page
mbeanProps.put("jmx.objectname", "com.adobe.example:type=workflow_model,id=" + ObjectName.quote(modelId));
WorkflowSession wfsession = workflowservice.getWorkflowSession(session);
WorkflowMBeanImpl mbean = new WorkflowMBeanImpl(wfsession.getModel(modelId));
ServiceRegistration serviceregistration = componentContext.getBundleContext().registerService(WorkflowMBean.class.getName(), mbean, mbeanProps);
//Store the ServiceRegistration objects for deactivation
mbeanRegistrations.add(serviceregistration);
} catch (Throwable t) {}
}
/**
* Traverses the repository branch below a given Node. Stores the path of each model node.
*/
private void getModelIds(Node node) throws RepositoryException {
try{
NodeIterator iter = node.getNodes();
while (iter.hasNext()) {
Node n = iter.nextNode();
//Look for "jcr:content" nodes
if (n.getName().equals("jcr:content")) {
//get the path of the model node and save it
if(n.hasNode(MODEL_NODE)){
modelIds.add(n.getNode(MODEL_NODE).getPath());
}
} else{
//Scan child nodes
getModelIds(n);
}
}
}catch(Exception e){ }
}
/**
* Log out of the JCR session and unregister WorkflowMBean services
*/
@Deactivate
protected void deactivate() {
session.logout();
session=null;
for(ServiceRegistration sr:mbeanRegistrations){
sr.unregister();
}
}
}
The POM file for the Example MBean the-pom-file-for-the-example-mbean
For your convenience, you can copy and paste the following XML code into your project pom.xml file for building the component bundle. The POM references several required plugins and dependencies.
Plugins:
- Apache Maven Compiler Plugin: Compiles Java classes from source code.
- Apache Felix Maven Bundle Plugin: Creates the bundle and the manifest
- Apache Felix Maven SCR Plugin: Creates the component descriptor file and configures the service-component manifest header.
Note: At the time of writing, the maven scr plugin is not compatible with the m2e plugin for Eclipse. (See Felix bug 3170.) To use the Eclipse IDE, install Maven and use the command line interface to perform builds.
Example POM file example-pom-file
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.adobe.example.myapp</groupId>
<artifactId>workflow-mbean</artifactId>
<version>0.0.2-SNAPSHOT</version>
<name>mbean-simple</name>
<url>www.adobe.com</url>
<description>A simple MBean</description>
<packaging>bundle</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.7.2</version>
<executions>
<execution>
<id>generate-scr-scrdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>1.4.3</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>com.adobe.example.myapp.*;version=${project.version}</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
<version>2.0.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr</artifactId>
<version>1.6.1-R1236132</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.jcr.api</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.adobe.granite</groupId>
<artifactId>com.adobe.granite.jmx</artifactId>
<version>0.1.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-wcm-mobile-api</artifactId>
<version>5.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.day.cq.workflow</groupId>
<artifactId>cq-workflow-api</artifactId>
<version>5.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Add the following profile to your maven settings file to use the public Adobe repository.
Maven Profile maven-profile
<profile>
<id>adobe-public</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<releaseRepository-Id>adobe-public-releases</releaseRepository-Id>
<releaseRepository-Name>Adobe Public Releases</releaseRepository-Name>
<releaseRepository-URL>https://repo1.maven.org/maven2/com/adobe/</releaseRepository-URL>
</properties>
<repositories>
<repository>
<id>adobe-public-releases</id>
<name>Adobe Public Repository</name>
<url>https://repo1.maven.org/maven2/com/adobe/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>adobe-public-releases</id>
<name>Adobe Public Repository</name>
<url>https://repo1.maven.org/maven2/com/adobe/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>