Cree e implemente MBeans para administrar servicios mediante la consola de JMX. Exponga los atributos y las operaciones del servicio para permitir que se realicen tareas de administración.
Para obtener información sobre el uso de la consola JMX, consulte Monitoreo de recursos del servidor con la consola JMX.
En la plataforma Apache Felix, se implementan MBeans como servicios OSGi. Cuando se registra un servicio MBean en el Registro de servicios OSGi, el módulo de pizarra JMX de Aries registra automáticamente el MBean con el servidor MBean. A continuación, el MBean está disponible para la consola JMX, que expone los atributos públicos y las operaciones.
Los MBeans que se crean para la administración de recursos CQ5 o CRX se basan en la interfaz javax.management.DynamicMBean. Para crearlos, siga los patrones de diseño habituales establecidos en la especificación JMX:
Además de definir la interfaz de administración, la interfaz también define la interfaz de servicio OSGi. La clase de implementación implementa el servicio OSGi.
El paquete com.adobe.granite.jmx.anottation proporciona varias anotaciones y clases para proporcionar fácilmente metadatos MBean a la consola JMX. Utilice estas anotaciones y clases en lugar de agregar información directamente al objeto MBeanInfo de MBean.
Anotaciones
Añada anotaciones en la interfaz de administración para especificar metadatos MBean. La información aparece en la consola JMX para cada clase de implementación implementada. Están disponibles las anotaciones siguientes (para obtener información completa, consulte com.adobe.granite.jmx.anottation JavaDocs):
Descripción: Proporciona una descripción de la clase o método MBean. Cuando se utiliza en la declaración de clase, la descripción aparece en la página de la consola JMX para MBean. Cuando se utiliza en un método, la descripción aparece como texto al pasar el ratón por encima para el atributo o la operación correspondiente.
Impacto: El impacto de un método. Los valores de parámetro válidos son los campos definidos por javax.management.MBeanOperationInfo.
Nombre: especifica el nombre que se mostrará para un parámetro de operación. Utilice esta anotación para anular el nombre real del parámetro de método que se utiliza en la interfaz.
OpenTypeInfo: especifica la clase que se utilizará para representar datos compuestos o datos tabulares en la consola JMX. Para usar con MBeans abiertos
TabularTypeInfo: se utiliza para anotar la clase que se utiliza para representar datos tabulares.
Clases
Se proporcionan clases para crear MBeans dinámicos que consumen las anotaciones que se agregan a sus interfaces:
Normalmente, el MBean es una reflexión sobre el servicio OSGi que desea administrar. En la plataforma Felix, se crea el MBean como se haría para la implementación en otras plataformas de servidor Java. Una diferencia principal es que puede utilizar anotaciones para especificar información de MBean:
El siguiente ejemplo de MBean proporciona información sobre el repositorio de CRX. La interfaz utiliza la anotación Descripción para proporcionar información a la consola JMX.
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();
}
La clase de implementación utiliza el servicio SlingRepository para recuperar información sobre el repositorio de CRX.
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");
}
}
El siguiente gráfico muestra la página de este MBean en la consola JMX.
Cuando se registran los MBeans como un servicio OSGi, se registran automáticamente en el servidor MBean. Para instalar un MBean en CQ5, inclúyalo en un paquete y exporte el servicio MBean como lo haría con cualquier otro servicio OSGi.
Además de los metadatos relacionados con OSGi, también debe proporcionar los metadatos que necesita el módulo de pizarra JMX de Aries para registrar el MBean con el servidor MBean:
Nombre de la interfaz DynamicMBean: Declare que el servicio MBean implementa la interfaz javax.management.DynamicMBea
n. Esta declaración notifica al módulo Pizarra JMX de Aries que el servicio es un servicio MBean.
El dominio MBean y las propiedades clave: En Felix, usted proporciona esta información como propiedad del servicio OSGi de MBean. Es la misma información que proporciona normalmente al servidor MBean en un objeto javax.management.ObjectName
.
Cuando su MBean es un reflejo de un servicio singular, sólo se requiere una instancia del servicio MBean. En este caso, si utiliza el complemento Felix SCR Maven, puede utilizar las anotaciones Apache Felix Service Component Runtime (SCR) en la clase de implementación MBean para especificar los metadatos relacionados con JMX. Para crear instancias de varias instancias de MBean, puede crear otra clase que realice el registro del servicio OSGi de MBean. En este caso, los metadatos relacionados con JMX se generan durante la ejecución.
MBean simple
Los MBeans para los que puede definir todos los atributos y las operaciones en tiempo de diseño se pueden implementar mediante anotaciones SCR en la clase de implementación MBean. En el siguiente ejemplo, el atributo value
de la anotación Service
declara que el servicio implementa la interfaz DynamicMBean
. El atributo name
de la anotación Property
especifica el dominio JMX y las propiedades clave.
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");
}
}
Varias instancias de servicio MBean
Para administrar varias instancias de un servicio administrado, cree varias instancias del servicio MBean correspondiente. Además, las instancias de servicio de MBean deben crearse o eliminarse cuando se inician o se detienen instancias administradas. Puede crear una clase de administrador MBean para crear instancias de servicios MBean en tiempo de ejecución y administrar el ciclo vital del servicio.
Utilice BundleContext para registrar el MBean como un servicio OSGi. Incluya la información relacionada con JMX en el objeto Dictionary que utilice como argumento del método BundleContext.registerService
.
En el siguiente ejemplo de código, el servicio ExampleMBean está registrado mediante programación. El objeto componentContext es ComponentContext, que proporciona acceso a BundleContext.
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);
El ejemplo de MBean en la siguiente sección proporciona más detalles.
Un administrador de servicios MBean resulta útil cuando las configuraciones de servicio se almacenan en el repositorio. El administrador puede recuperar la información del servicio y usarla para configurar y crear el MBean correspondiente. La clase manager también puede detectar eventos de cambio de repositorio y actualizar los servicios MBean en consecuencia.
El MBean de este ejemplo proporciona información sobre los modelos de flujo de trabajo de CQ5 almacenados en el repositorio. Una clase de administrador MBean crea MBeans basados en modelos de flujo de trabajo almacenados en el repositorio y registra su servicio OSGi durante la ejecución. Este ejemplo consta de un solo paquete que contiene los siguientes miembros:
Para simplificar, el código de este ejemplo no realiza el registro ni reacciona ante las excepciones generadas.
WorkflowMBeanManagerImpl incluye un método de activación de componentes. Cuando se activa el componente, el método realiza las siguientes tareas:
Los metadatos MBean aparecen en la consola de JMX con el dominio com.adobe.example, el tipo workflow_model y Properties es la ruta del nodo de configuración del modelo de workflow.
Este ejemplo requiere una interfaz y una implementación MBean que reflejen la interfaz com.day.cq.workflow.model.WorkflowModel
. El MBean es muy sencillo para que el ejemplo pueda centrarse en los aspectos de configuración e implementación del diseño. El MBean expone un solo atributo, el nombre del modelo.
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();
}
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();
}
}
El servicio WorkflowMBeanManager incluye el método de activación de componentes que crea servicios WorkflowMBean. La implementación del servicio incluye los siguientes métodos:
La implementación WorkflowMBeanManager solo crea servicios MBean para configuraciones de modelo que existen cuando se activa el componente. Una implementación más sólida escucha los eventos del repositorio en cuanto a las nuevas configuraciones de modelo y los cambios o eliminaciones de la configuración de modelo existente. Cuando se produce un cambio, el administrador puede crear, modificar o eliminar el servicio WorkflowMBean correspondiente.
package com.adobe.example.myapp.api;
public interface WorkflowMBeanManager {
}
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();
}
}
}
Para su comodidad, puede copiar y pegar el siguiente código XML en el archivo pom.xml del proyecto para crear el paquete de componentes. El POM hace referencia a varios complementos y dependencias requeridos.
Plugins:
Nota: En el momento de escribir este artículo, el complemento maven scr no es compatible con el complemento m2e para Eclipse. (Consulte Félix error 3170.) Para utilizar el IDE de Eclipse, instale Maven y utilice la interfaz de la línea de comandos para realizar compilaciones.
<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>
Añada el siguiente perfil al archivo de configuración principal para utilizar el repositorio público de Adobes.
<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://repo.adobe.com/nexus/content/groups/public</releaseRepository-URL>
</properties>
<repositories>
<repository>
<id>adobe-public-releases</id>
<name>Adobe Basel Public Repository</name>
<url>https://repo.adobe.com/nexus/content/groups/public</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 Basel Public Repository</name>
<url>https://repo.adobe.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>