Search

4. Writing Agent Plug-ins: Background

download PDF
Agent plug-ins extend the control capabilities that agents have as they interact with resources. This can include adding monitoring, operations, or configuration over resources.

4.1. About the Advanced Management Plug-in System (AMPS) for Agent Plug-ins

Agent resource plug-ins in JBoss ON have a certain pattern or system to how they are written. This is called the Advanced Management Plug-in System (AMPS). AMPS is defined in the core API for JBoss ON.
Basically, an agent plug-in is comprised of five parts (which, collectively, are the AMPS system):
  • The agent's plug-in container. The plug-in contain runs inside the JBoss ON agent and it provides a manager for all of the deployed resource plug-ins.
    The plug-in container is what actually manages the lifecycle of the resource plug-ins. The agent starts the plug-in container, and the plug-in container starts the resource plug-ins. The plug-in container also handles all the classloading, threading, and running for resource plug-ins.
    Plug-in developers never need to interact with the plug-in container. As long as a plug-in is written with the appropriate components and with a valid plug-in descriptor, the agent will be able to manage the resource.
  • Domain objects. This defines the individual objects for plug-ins, specifically resources, resource types, and configuration. All of the other elements in AMPS use the domain objects to define resource elements.
    One of the largest API sets within the domain object is configuration. The configuration API is used anywhere that a set of configuration properties is required, from plug-in configuration settings to connect to a resource to operation arguments.
  • The plug-in components. These components define the actual component interfaces that are used by agent plug-ins, well as the facets that plug-ins can support.
    The plug-in components are the public API.
    This element within AMPS is the part that plug-in writers use. This contains the interfaces that plug-in writers implement in the resource plug-in.
  • Native System. A lot of information require to monitor or manage a resource is available from the operating system information. The native system provides JNI or native access to that operating system information and can pull information from the process table, run external programs, or gather system metrics.
  • Resource plug-ins.. JBoss ON has a set of resource plug-ins already defined. Each individual resource plug-in manages a particular product (applications and servers, services, or platforms). These plug-ins are loaded into the agent's plug-in container and implement the plug-in components defined in the API.

Note

Agent plug-ins can leverage the JBoss ON domain and native system APIs to define objects and communication layers, respectively.

4.2. The Breakdown of Agent Plug-in Configuration

Agents do not have a fixed functionality; their functions, from monitoring to the resources they can inventory, are defined by their plug-ins.
At its core, an agent plug-in consists of a single JAR file and an XML plug-in descriptor file (rhq-plugin.xml inside the META-INF/ directory).
Along with the plug-in descriptor, an agent plug-in has up to three different types of Java files for each plug-in defined in the JAR file package:
  • A plug-in component file that contains all of the code for the plug-in functionality
  • A *Discovery.java file that configures the discovery process for the resources defined in the plug-in
  • A *EventPoller.java that defines the events that can be collected by the resource
The definitions in the Java files closely track the configuration for the plug-in in the rhq-plugin.xml plug-in descriptor.

Note

Generating an agent plug-in template with the plug-in generator creates files with TODO markers to help guide writing the plug-in.

4.2.1. Schema Files

The agent plug-in is defined through its metadata and configuration in its XML plug-in descriptor file. The configuration elements that are available to the descriptor are defined in the XML schema definition (XSD) files for agent plug-ins.
All JBoss ON plug-ins — both agent plug-ins and server-side plug-ins — uses the rhq-configuration.xsd file to define the basic configuration options available.
Agents also use the rhq-plugin.xsd file, which extends the rhq-configuration.xsd schema and adds additional elements specifically for resource-related plug-ins.

Note

More information about specific elements within both XSD files is available through the comments (in <xs:annotation> items) in the XSD files themselves.
The rhq-configuration.xsd file provides schema which is available for all JBoss ON plug-ins. The rhq-configuration.xsd file is in source/modules/core/client-api/src/main/resources.
The most commonly used elements defined in the rhq-configuration schema relate to setting configuration values for a plug-in, like <simple-property> and <map-property>.
Table 9. rhq-configuration.xsd Schema Elements
Element Description
configuration-property For adding a configuration attribute to a plug-in for user-defined settings.
simple-property For setting a default configuration value.
option For setting whether a property's values come from an enumerated list (false) or can be anything defined by the user (true).
The rhq-configuration.xsd file also defines the most common flags that can be used for the plug-in descriptor, including the required name and optional displayName attributes.
Table 10. rhq-configuration.xsd Schema Attributes
Attribute Description
name Required. Gives a unique name for the plug-in.
displayName Gives the name to use for the plug-in in the GUI. If this isn't given, then the name value is used.
description Gives a short description of the plug-in.
The rhq-plugin.xsd provides all of the schema elements specifically for agent plug-ins. The rhq-plugin.xsd file is in the source/modules/core/client-api/src/main/resources directory.
The most common elements in the rhq-plugin.xsd file are listed in Table 11, “rhq-plugin.xsd Schema Elements”.
Table 11. rhq-plugin.xsd Schema Elements
Element Description
plugin Contains the root element for the plug-in descriptor.
depends Identifies any other plug-ins which this plug-in requires or extends.
platforms, servers, services Identifies the type for a resource defined within the agent plug-in. <platforms> are top-level elements, but <servers> and <services> are added as children of platforms or other server and service resources.
metric An element within a platform, server, or service which defines metrics which can be collected for that resource type.
Child elements and attributes for this resource element are listed in the rhq-plugin.xsd file.
Values that form part of a larger data structure, such as an array of values, need to be deconstructed into individual values before they can be monitored.
event An element within a platform, server, or service which defines whether that resource supports events. There are no other configuration properties with events; the events themselves are culled from the resource's log files.
bundle-target Configures whether and how bundles can be deployed to a resource.
Child elements and attributes for this resource element are listed in the rhq-plugin.xsd file.
drift-definition Configures whether and how drift monitoring can be performed for a resource.
Child elements and attributes for this resource element are listed in the rhq-plugin.xsd file.
resource-configuration Defines a configuration property for a resource type.
Child elements and attributes for this resource element are listed in the rhq-plugin.xsd file.
operation Defines an operation that can be performed on that resource type.
Child elements and attributes for this resource element are listed in the rhq-plugin.xsd file.
content Configures what types of packages can be uploaded or deployed on a resource type.
Child elements and attributes for this resource element are listed in the rhq-plugin.xsd file.
Most of the attributes defined within the rhq-plugin.xsd contain flags that are used within the root element of the plug-in descriptor. These add additional management attributes for controlling the release and updates of agent plug-ins.
Table 12. rhq-plugin.xsd Schema Attributes
Attribute Description
package For setting the plug-in package name.
version For setting the version of the plug-in. This must be in an OSGi-compatible format.
ampsVersion For the agent plug-in system version that this plug-in requires. This must be in an OSGi-compatible format.
pluginLifecycleListener For the listener which initializes and shuts down the plug-in.
discovery Sets whether a resource type is detected by discovery scans. This flag may not be necessary for child resources that will be discovered by the parent resource.
There are many other elements and attributes set in the rhq-plugin.xsd file. Each one is described by the text in the <xs:annotation> tags for the item.

4.2.2. Descriptor and Configuration

A plug-in descriptor contains the metadata that described everything about the plug-in and the resource it configured. The descriptor describes the type and interactions of the resource type the agent plug-in defines.
The plug-in descriptor contains the information about name of the resource, the supported resource versions, the total resource hierarchy (meaning parents or children of the resource), configuration properties that the agent uses to connect to the resource, and all of the monitoring metrics, operations, and events related to the resource that can be managed by the agent.
The plug-in descriptor also contains information about the plug-in itself.
A resource definition in a plug-in descriptor can be a platform, server, or service. Multiple resources can be defined in a single plug-in descriptor; one resource is the root (parent) element, and the rest of the resources defines are its children.
Because the plug-in descriptor is an XML file, it follows a clear and structured schema definition. The schema definitions are what allow the plug-in descriptor to expose the resource's management interfaces to JBoss ON.
The plug-in descriptor, at a minimum, defines the resource type. Past that, it defines the different aspects of the resource that JBoss ON can manage:
  • The names of the resource types (servers and services) supported by the plug-in
  • Any configuration settings that the agent's plug-in components use to connect to the resource
  • Any metrics (measurement definitions) to use to monitor the resource; this depends on the type of data issued by the resource itself.
  • A set of operations that can be invoked on the resource. This is commonly start and stop operations, but it can include application-specific operations or other actions, like running a script.
  • Resource configuration values that can be edited in the actual configuration of the resource.
    The plug-in configuration tells the components how to connect to the resource. The resource configuration, on the other hand, are settings in the resource itself that can be edited externally.
  • Any child resources that are part of the resource hierarchy. For example, a JBoss server has data source services running within them, so the data source services are defined in the JBoss server resource plug-in, as a child resource of the JBoss server.
4.2.2.1. Resource Type, Metadata, and Plug-in Configuration
The top element in an agent plug-in is the <plugin> element.
<plugin name="JMX"
        displayName="Generic JMX"
        package="org.rhq.plugins.jmx"
        description="Supports management of JMX MBean Servers via various remoting systems."
        ampsVersion="2.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="urn:xmlns:rhq-plugin"
        xmlns:c="urn:xmlns:rhq-configuration">
Several attributes on this element are important:
  • name and displayName give the internal and GUI name of the plug-in.
  • ampsVersion gives the version number of the plug-in itself.
  • package gives the name of the classes used by the components in the plug-in.
The next element in the plug-in descriptor defines the root resource that is defined by the plug-in. This can be <platform>, <server>, or <service>.
One or multiple resources can be defined in a plug-in descriptor. The plug-in descriptor not only defines those resource types, but it organizes those types in a parent-child hierarchy. For example, a JBoss EJB service only runs inside of a JBoss server, so the EJB service resource type should logically be a child type of the JBoss server resource type.
The hierarchy is defined by nesting <service> resource definitions inside <server> (or other <service>) resource definitions.
   <server name="JMX Server" discovery="JMXDiscoveryComponent" class="JMXServerComponent"
           description="Generic JMX Server"
	   supportsManualAdd="true" createDeletePolicy="neither">

Important

Do not rename resource types when you edit the resource plug-in. This breaks backward compatibility with any resource that was inventoried using the older version of the plug-in.
Two of the attributes are related to the Java resource files associated with the plug-in:
  • discovery identifies the discovery component used to identify the resource type.
  • class identifies the plug-in component which contains the actual code of the plug-in.
Two of the attributes define how resources of that type are added to the inventory:
  • supportsManualAdd allows resources to be added to the inventory by administrators.
  • createDeletePolicy sets whether children can be added or removed manually from inventory.
The last part that relates to configuring the plug-in is setting (optional) plug-in configuration properties. These are flexible and can define anything related to the information required to identify or set up a resource which matches the resource type in the plug-in, even setting constraints on allowed values or templates to define default settings.
<plugin-configuration>
  <c:list-property name="Servers">
     <c:map-property name="OneServer">
        <c:simple-property name="host"/>
        <c:simple-property name="port">
           <c:integer-constraint 
              minimum="0"
              maximum="65535"/> 
        </c:simple-property>
        <c:simple-property name="protocol">
           <c:property-options>
              <c:option value="http" default="true"/>
              <c:option value="https"/>
           </c:property-options>
        </c:simple-property>
     </c:map-property>
  </c:list-property>
</plugin-configuration>
The port has a constraint so, the GUI can validate the input being between 0 and 65535. The protocol can be selected from a list of drop-down menu items, with a default value of HTTP.
There are three types of properties:
  • <simple-property>, which defines a one key-value pair
  • <map-property>, which defines multiple key-value pairs related to a single entity, following the java.util.Map concept
  • <list-property>, which contains a list of properties
Both <map-property> and <list-property> define groups of <simple-property> element. Additionally, these properties can be formally grouped together under <group> element. Using a <group> element creates a collapsible configuration ares in the UI.
Templates can preset some configuration properties.
         <c:template name="JDK 5" description="Connect to JDK 5">
            <c:simple-property name="type" default="org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor"/>
            <c:simple-property name="connectorAddress" default="service:jmx:rmi:///jndi/rmi://localhost:8999/jmxrmi"/>
         </c:template>
4.2.2.2. Discovery and Process Scans
The central functionality of JBoss ON is the inventory. Each resource must be present in that inventory, so the plug-in descriptor has to define how resources are detected and how they are added to inventory. This is done through the discovery component.
The <plugin> element has a discovery attribute which identifies the discovery Java file for the resource plug-in. (If there are multiple resources defined in the plug-in, then there will be multiple discovery components.)
When the agent plug-in is generated using the plug-in generator, it creates the appropriate template to add the discovery requirements. The discovery component has to have the information to find a resource instance and to assign a unique identifier to that resource.
/**
 * Discovery class
 */
public class testDiscovery implements ResourceDiscoveryComponent
,ManualAddFacet
{

    private final Log log = LogFactory.getLog(this.getClass());

      /**
       * Do the manual add of this one resource
       */
      public DiscoveredResourceDetails discoverResource(Configuration pluginConfiguration, ResourceDiscoveryContext context) throws InvalidPluginConfigurationException {

            // TODO implement this
            DiscoveredResourceDetails detail = null; // new DiscoveredResourceDetails(
//                context.getResourceType(), // ResourceType
//            );

            return detail;
      }
}
Identifying resource instances is a critical part of maintaining the inventory. Any resource must be unique and must be consistently identified between discovery scans . Agents identify resources by constructing a unique resource key. A resource key varies by resource type. Whatever the key is, it has to intrinsic to the resources and detectable for the agent. Keys do not have to be globally unique, but they must be unique beneath a parent resource. For a JMX server, the resource key is its connector address, which is unique to the instance.
    public DiscoveredResourceDetails discoverResource(Configuration pluginConfig,
                                                      ResourceDiscoveryContext discoveryContext)
            throws InvalidPluginConfigurationException {
        // TODO: Connect to the remote JVM to verify the user-specified conn props are valid, and if connecting
        // fails, throw an exception.
        String resourceKey = pluginConfig.getSimpleValue(CONNECTOR_ADDRESS_CONFIG_PROPERTY, null);
        String connectionType = pluginConfig.getSimpleValue(CONNECTION_TYPE, null);
                            
        // TODO (ips, 09/04/09): We should connect to the remote JVM in order to obtain its version.
        String version = null;
                    
        DiscoveredResourceDetails resourceDetails = new DiscoveredResourceDetails(discoveryContext.getResourceType(),
                resourceKey, "Java VM", version, connectionType + " [" + resourceKey + "]", pluginConfig, null);
        return resourceDetails;
    }  
Optional dependencies can affect discovery. Embedded plug-ins copy the child type from the source plug-in, and then use the embedded plug-in's discovery component to run the discovery. Injected plug-ins take a parent resource and cycle through all potential children resource types and run a discovery for each type, injecting the parent component into each child type's discovery method.
Often, resources are processes running on the local machine. The JBoss ON agent can query the process table to detect those local processes. This is first defined in the plug-in descriptor using a <process-scan> element and then implemented in the discovery component.
Each resource type defined in the plug-in descriptor can have a <process-scan> child element. The <process-scan> element itself is empty, but has two required attributes: name and query. name identifies the specific scan method. query is the attribute that does something. The query is a string written in Process Info Query Language (PIQL). This value is used to search for the process.
The sourceforge PIQL API docs provide much more information on the syntax of PIQL queries.
The basic format of a PIQL process scan query is a three-part term which looks for the process, some kind of identifying marker, and then the value to match.
process|attribute|match=value,arg|attribute|match=value
For a process scan for discovery, the scan will usually look for a process name or a PID file.
Looking for a process by name can require additional attributes to help narrow the search down to a specific type of resource or even a specific instance. For example, a JBoss AS instance has a process name that starts with java and an argument with the value org.jboss.Main. The ps information contains both of those attributes.
jsmith     2035   0.0 -1.5   724712  30616  p7  S+    9:49PM   0:01.61 java  
 -Dprogram.name=run.sh -Xms128m -Xmx512m -Dsun.rmi.dgc.client.gcInterval=3600000
 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.platform.mbeanserver
 -Djava.endorsed.dirs=/devel/jboss-4.0.5.GA/lib/endorsed
 -classpath /devel/jboss-4.0.5.GA/bin/run.jar:/lib/tools.jar
 org.jboss.Main -c minimal
The PIQL query, then attempts to match the process name, using the basename query attribute, with a matching argument, defined in the arg query attribute.
process|attribute|match=value,arg|attribute|match=value
   |       |       |____      |_    |____     |______
   |       |            |       |        |           |
   |       |            |       |        |           |
   |       |            |       |        |           |
   |       |            |       |        |           |
process|basename|match=^java.*,arg|org.jboss.Main|match=.*
Alternatively, the process scan query can match a pid file, which is a simple way to identify processes. A PID-based PIQL query has a slightly simpler format:
process|attribute|match=value
For example:
process|pidfile|match=/etc/product/lock.pid
After defining the scan query in the rhq-plugin.xml descriptor file, then the discovery component must be written to implement the scan and process results.

Example 9. Process Scan Method in the Discovery Component

   List<ProcessScanResult< autoDiscoveryResults = 
      context.getAutoDiscoveredProcesses();
   for (ProcessScanResult result : autoDiscoveryResults) {
       ProcessInfo procInfo = result.getProcessInfo();
       ....
       // as before
       DiscoveredResourceDetails detail = 
          new DiscoveredResourceDetails(
              resourceType, key, name, null,
              description, childConfig, procInfo
          );
       result.add(detail);
   }
The agent manages resources by gathering metrics (for monitoring) and by launching scheduled operations, or tasks, on the resource. These two areas are configured similarly in the plug-in.
Monitoring areas are configured through <metric> elements in the plug-in descriptor.
        <metric displayName="Bytes Sent"
                description="Shows the rate that data bytes are sent by the Web service."
                property="Bytes Sent/sec"
                defaultOn="true"
                displayType="summary"
                measurementType="trendsup"
                units="bytes"/>
The most relevant attributes on that attribute relate to the monitoring property (which is partially defined by the resource itself).
  • property identifies the resource monitoring property.
  • measurementType sets the data type being collected.
  • units sets the units of the thing being monitored.
In the plug-in Java component, the metric is first set up by pulling in the MeasurementFacet.
public class testComponent implements ResourceComponent
, MeasurementFacet
, OperationFacet
Then, there is an entry for monitoring in a MeasurementReport, with a MeasurementScheduleRequest entity for each type of monitoring data.
    public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception {

        String propertyBase = "\\Web Service(_Total)\\";
        Pdh pdh = new Pdh();

        for (MeasurementScheduleRequest request : metrics) {
            double value = pdh.getRawValue(propertyBase + request.getName());
            report.addData(new MeasurementDataNumeric(request, value));
        }
}

Important

When defining metrics, values that form part of a larger data structure, such as an array of values, need to be deconstructed into individual values before they can be monitored.
Similarly, operations are configured in the plug-in descriptor in an <operation> element, implemented in the plug-in Java component through an OperationFacet, and then invoked in a OperationResult method.
4.2.2.3. Events
Events for resources are essentially types of log messages that are recognized by the agent.
In the plug-in descriptor, an event is configured by a simple <event> element, no children, that identifies the logging area by name.
<event name="errorLogEntry" description="an entry in the error log file"/>
The event handling is handled through an EventPoller component. This can be in the larger plug-in Java component, but it is usually broken into a separate *EventPoller.java component. The way to implement event polling depends on the resource and the nature of its logging. One of the simplest ways is to call the EventPoller(), then define the event type and set how the event is polled.
    public PerfTestEventPoller(ResourceContext resourceContext) {
        this.resourceContext = resourceContext;
    }

    public String getEventType() {
        return PERFTEST_EVENT_TYPE;
    }

    public Set<Event> poll() {
        int count = Integer.parseInt(System.getProperty(SYSPROP_EVENTS_COUNT, "1"));
        String severityString = System.getProperty(SYSPROP_EVENTS_SEVERITY, EventSeverity.INFO.name());
        EventSeverity severity = EventSeverity.valueOf(severityString);
        Set<Event> events = new HashSet<Event>(count);
        for (int i = 0; i < count; i++) {
            Event event = new Event(PERFTEST_EVENT_TYPE, "source.loc", System.currentTimeMillis(), severity, "event #"
                + i);
            events.add(event);
        }
        return events;
    }
4.2.2.4. Resource Configuration
Resources can have parameters or settings changed through the JBoss ON GUI, managed by the agent. Those properties that can be edited are defined in the plug-in descriptor in <resource-configuration> elements. These configuration elements follow the same conventions as the <plugin-configuration> elements. The properties are defined as <simple-property> elements and can be listed (for options), mapped, or organized into groups that are collapsible sections in the UI.
         <resource-configuration>
            <c:group name="Attributes">
               <c:simple-property
                  name="appBase"
                  required="true"
                  readOnly="true"
                  description="The Application Base directory for this virtual host." />
               <c:simple-property
                  name="autoDeploy"
                  type="boolean"
                  description="Does this host deploy new applications dropped in appBase at runtime?" />
               <c:simple-property
                  name="deployOnStartup"
                  type="boolean"
                  description="Does this host deploy applications in appBase at startup?" />
               <c:simple-property
                  name="deployXML"
                  displayName="Deploy XML"
                  type="boolean"
                  description="deploy Context XML config files?" />
               <c:simple-property
                  name="unpackWARs"
                  displayName="Unpack WARs"
                  type="boolean"
                  description="Does this Host automatically unpack deployed WAR files?" />
               <c:simple-property
                  name="aliases"
                  required="false"
                  type="longString"
                  description="Aliases assigned to the Host. When editing, each alias must be on a new line. Aliases are automatically lowercased." />
            </c:group>
         </resource-configuration>
The first thing that is defined in the plug-in Java component is the ability to load the current configuration.
    public Configuration loadResourceConfiguration() {
        Configuration configuration = super.loadResourceConfiguration();
        try {
            resetConfig(CONFIG_ALIASES, configuration);
        } catch (Exception e) {
            log.error("Failed to reset role property value", e);
        }

        return configuration;
    }
The second part in the plug-in component allows the agent to change the configuration properties.
    public void updateResourceConfiguration(ConfigurationUpdateReport report) {
        Configuration reportConfiguration = report.getConfiguration();
        // reserve the new alias settings 
        PropertySimple newAliases = reportConfiguration.getSimple(CONFIG_ALIASES);
        // get the current alias settings
        resetConfig(CONFIG_ALIASES, reportConfiguration);
        PropertySimple currentAliases = reportConfiguration.getSimple(CONFIG_ALIASES);
        // remove the aliases config from the report so they are ignored by the mbean config processing
        reportConfiguration.remove(CONFIG_ALIASES);

        // perform standard processing on remaining config
        super.updateResourceConfiguration(report);

        // add back the aliases config so the report is complete
        reportConfiguration.put(newAliases);

        // if the mbean update failed, return now
        if (ConfigurationUpdateStatus.SUCCESS != report.getStatus()) {
            return;
        }

        // try updating the alias settings
        try {
            consolidateSettings(newAliases, currentAliases, "addAlias", "removeAlias", "alias");
        } catch (Exception e) {
            newAliases.setErrorMessage(ThrowableUtil.getStackAsString(e));
            report.setErrorMessage("Failed setting resource configuration - see property error messages for details");
            log.info("Failure setting Tomcat VHost aliases configuration value", e);
        }

        // If all went well, persist the changes to the Tomcat server.xml
        try {
            storeConfig();
        } catch (Exception e) {
            report
                .setErrorMessage("Failed to persist configuration change.  Changes will not survive Tomcat restart unless a successful Store Configuration operation is performed.");
        }
    }

4.2.3. Lifecycle Listeners

Some plug-ins need to perform some initialization immediately when they load and some cleanup when they unload. Global initialization and shutdown of a plug-in is performed by its lifecycle listener.
The org.rhq.core.pluginapi.plugin.PluginLifecycleListener class allocates global resources needed by plug-in components and cleans up those resources.
Each plug-in can optionally define one lifecycle listener by specifying a pluginLifecycleListener attribute in the top-level <plugin> element.
<plugin name="Apache"
		displayName="Apache HTTP Server"
		description="Management of Apache web servers"
		package="org.rhq.plugins.apache"
		pluginLifecycleListener="ApachePluginLifecycleListener"
		...

4.2.4. Plug-in Dependencies: Defining Relationships Between Plug-ins

Agent plug-ins can have relationships with other agent plug-ins. These relationships created dependencies between plug-ins, where plug-ins are only operable when other plug-ins are loaded, that allow plug-ins to share classes, or that extend the resource hierarchy by adding additional parent or child resources to an existing resource definition.
A parent plug-in is one that has another plug-in depending on it. A child plug-in is a plug-in that depends on another plug-in.
Agent plug-ins have three ways of defining dependencies:
  1. Required dependencies are set using the <depends> element. Just using <depends> means that the required plug-in must be loaded or the other plug-in will fail to load. Adding the useClasses attribute makes the classes and JAR files for the parent plug-in available to the child plug-in.
  2. An injection plug-in dependency means that a root-level resource runs inside another resource type, and that parent resource is defined as a parent plug-in. This essentially adds a new child to an existing resource type.
  3. An embedded plug-in dependency means that a new parent resource type is added for an existing child. This can allow the child to be extended to share the new parent's classloader (depending on both plug-ins' configuration) or simply expand discovery.

Important

Embedded and injection plug-in dependencies are mutually exclusive. They cannot be used in the same plug-in definition.
There is one interesting similarity in all of these plug-in dependency models: Metadata and class definitions flow in only one direction, from a parent plug-in to its dependent plug-in. Information cannot flow in the other direction.
4.2.4.1. Required Plug-in Dependencies
The <depends> element directly under the <plug-in> element defines a parent plug-in that the plug-in depends on and required to be loaded. The <depends> element is what specifies a required dependency. The plug-in will not deploy successfully, unless all <depends> plug-ins are also successfully deployed.
The <depends> element can pull in JARs from the parent plug-in by specifying the useClasses attribute. The useClasses option can be set for only one required dependency in a single plug-in descriptor. If no <depends> element has a useClasses attribute, the last <depends> element specified in the plug-in descriptor, by default, has its useClasses attribute to true.
The <depends> element is used if the plug-in needs access to another plug-in's classes or if the plug-in should only be deployed when another plug-in is also deployed.

Note

The embedded and injection plug-in dependencies are optional dependencies. If the specified plug-in isn't loaded, then the plug-in simply runs without loading those dependencies. To make an embedded or injection plug-in a required dependency, then set the embedded or injection plug-in as a required plug-in using the <depends> element, as well as the other configuration.
4.2.4.2. Embedded Plug-in Dependencies
An embedded plug-in dependency adds a new parent resource for an existing child resource. The dependent plug-in (for the new parent resource) depends on the child.
With an embedded plug-in dependency, the server or service definition can be a copy of a source resource type found in another plug-in. That copy is defined in the plug-in descriptor by setting the sourcePlugin and sourceType attributes on the resource elements. When a plug-in source is specified, the server or service is copied from the source resource type, which means it has the same metadata as the source, with the exception that the embedded server or service can override the discovery and resource classes and, potentially, have a different name.
An embedded plug-in is an optional dependency.
4.2.4.3. Injection Plug-in Dependencies
A root-level resource type in an agent plug-in can define parent resource types that it can run inside of. This essentially injects the resource type as a child type to another, existing resource. This is an injection plug-in dependency.
The injection plug-in dependency illustrates that a child resource type knows about its parent resource types, but the parents do not know about the child. Knowledge of plug-ins flow down, not up. A parent plug-in's type information is known to its child plug-in, but a parent plug-in does not know anything about the child plug-ins that depend on it.
An injection dependency is a list of allowed parents, within a <runs-inside> element. Each parent is an optional dependency.
<runs-inside>
   <parent-resource-type name="JMX Server" plugin="JMX" />
   <parent-resource-type name="JBoss Server" plugin="JBoss AS" />
</runs-inside>

4.2.5. Class Sharing Between Plug-ins

All agent plug-ins have their own classloader while running in the plug-in container. Each resource in inventory will be assigned a classloader, which can be the same as its plug-in classloader.
Agent Components, Together

Figure 5. Agent Components, Together

All plug-in classloaders are isolated from one another, unless the <depends useClasses=""> attribute is set to true. If a plug-in is a direct dependent of another plug-in, and that dependency is defined with <depends useClasses="true">, then that parent plug-in's JAR classes (and all of its parent JARs) are available to the dependent plug-in's classloader.
The most common reason to create that kind of dependency, and share JARs and classes between plug-ins, is because one resource defined in one plug-in is deployed and running in another resource defined in another plug-in. The child plug-in needs a way to connect to its parent resource to perform things like discovery and management of the child resource. By default, all managed resources are assigned a resource classloader that is shared. This classloader can belong to the plug-in or to the parent resource.
When a resource component needs to create a connection to its actual managed resource, that resource's classloader must be different than the normal, shared plug-in classloader. The resource usually needs to have the client JARs necessary to connect to the managed resource within its own classloader, and those client JARs are usually very specific to the version of the resource being managed. The connecting resource should be in charge of creating the connection, since it knows how to do it. When a resource requires its own connection classloader, specify the attribute classLoader="instance" on the resource type and make sure the resource type's discovery component implements the ClassLoaderFacet so it tells the plug-in container where any additional connection classes can be found for the specific version of the specific resource being managed.
In Example 10, “classLoader for Plug-in Z”, the Z1.server has a classLoader option set to shared. This means that Z1.server resources share their classloaders with their parent resources, and that classloader may be a resource classloader or a plug-in classloader. Every Z1.server resource uses the same classloader.

Example 10. classLoader for Plug-in Z

<plug-in name="Z">

<depends plugin="A" />

<server name="Z1.server" classLoader="shared">
   <runs-inside>
      <parent-resource-type name="B1.server" plugin="B"/>
      <parent-resource-type name="C1.server" plugin="C"/>
   </runs-inside>
</server>

<server name="Z2.server" sourcePlugin="D" sourceType="D1" classLoader="instance">
</server>

<server name="Z3.server" classLoader="instance">
</server>

</plugin>
Normally, setting a classLoader option to instance means that each resource uses its own resource plug-in. However, for Z2.server, the Z2.server plug-in is extended by embedding the values for Plug-in D, so Z2.server resources share their classloaders with their parent plug-in.
Z3.server simply uses its own resource classloader because its classLoader option is set to instance and it has no injected or embedded dependencies. When the classLoader option is set to instance, the ResourceDiscoveryComponent implementation can optionally define a ClassLoaderFacet with a method (getAdditionalClasspathUrls) that returns a List<URL> pointing to additional JARs that should be placed in the resource's classloader. When the plug-in container needs to create a classloader for a resource, it checks if the resource's discovery component implements this facet, and, if so, it gets the additional classpath URLs and adds them to the resource classloader when it creates it.
If a resource type is defined with either an injection or embedded dependency, then its classloader depends on both its classLoader attribute value and its parent's classLoader attribute value.
Resource ClassLoader Parent ClassLoader ClassLoader Description
shared shared The useClasses value must be set to true so that the resource can access both its classes and the parent classes.
instance shared The resource primarily needs its own classes, but it may be beneficial for useclasses to be set to true to so that the child can use parent classes.
shared instance The resource uses only its own classloader.
instance instance The resource uses only its own classloader.

4.3. Extended Example: Content Types for Resources

All of the behavior for how a resource is managed in JBoss ON depends on how it is described in its resource plug-in for the agent. This includes all of the monitoring metrics that can be collected, any configuration that can be set, and any operations that can be performed. This also includes any content that can be deployed for that resource and what kind of content is expected.
A package refers to any piece of content. A package is usually a file of some kind, like a JBoss AS JAR file. However, since the package type for a resource is defined in the resource plug-in, a package can be anything, so long as the resource plug-in is configured to use it.
As with other elements related to the resource, the package type is defined in the plug-in descriptor for the resource type. Each package type can define certain attributes (listed in Table 13, “Package Attributes”), but every package must define its name and its type (of four given categories).
In the plug-in descriptor, package types are identified by <content> elements. The required properties are set as flags on the main <content> element; any configurable properties, which are set by the user when new packages are uploaded to the resource, are given in <c:simple-property> child elements. For example, this content element in the Platform Resource Plug-in identifies deployable (category) package types for Windows platforms:
      <content name="InstalledSoftware" displayName="Installed Software" category="deployable" description="Installed Windows Software">
           <configuration>
               <c:simple-property name="Publisher"/>
               <c:simple-property name="Comments"/>
               <c:simple-property name="Contact"/>
               <c:simple-property name="HelpLink"/>
               <c:simple-property name="HelpTelephone"/>
               <c:simple-property name="InstallLocation"/>
               <c:simple-property name="InstallSource"/>
               <c:simple-property name="EstimatedSize" units="kilobytes"/>
          </configuration>
       </content>
While packages can be manually added to a resource, an agent can also actively check for new content and add any discovered content to its inventory. A package is inventoried in JBoss ON through a recurring package discovery scan. The interval at which this discovery occurs can be explicitly set in the package's definition in the plug-in's descriptor or it can use the default value given in the plug-in schema file.
Table 13. Package Attributes
Attribute Description Optional or Required
NameThe programmatic name of the package type. Required
Display NameA user interface friendly name of the package type. Optional
DescriptionDescribes the type of content found in packages of this type. Optional
CategoryOne of four enumerated options:
  • Executable Script (which is potentially editable)
  • Executable Binary
  • Configuration (a configuration file for the resource)
  • Deployable
Required
Discovery IntervalDefines the time between package discovery scans for this type; different package types can be configured with intervals to represent the likelihood of the package inventory changing. Optional
Creation Type FlagIf set to true, a package of this type is used when creating resources of the enclosing resource type. An example of this situation is a Java EAR file. There is an EAR resource type that represents the enterprise application in JBoss ON. Under that resource type, there is a package type defined to represent the EAR file itself. This package type is flagged as a creation type; when creating a new EAR resource, the EAR file must be created at the same time. The default for this attribute is false, as packages will typically not represent the creation of a new resource. Optional
ConfigurationThe configuration element allows the plug-in to define an open-ended set of attributes about the package type. These values will be populated during package discovery, and if not marked as read only, can be specified by the user at artifact creation time. An example of a property in this configuration element is a Boolean that describes if an EAR file is deployed as exploded or zipped. When EAR files are discovered, this flag will be populated and carry package type specified information. Additionally, when deploying a new EAR file through JBoss ON, this flag can be set to indicate how the package should be deployed on the AS instance. Optional

4.4. Extended Example: HTTP Metrics

This example plug-in is written for the agent to connect to an HTTP server to monitor the web server itself for performance or availability. This plug-in performs two tasks:
  • Issue a GET or HEAD request to the base URL for the given server.
  • Collect both the HTTP return code and the response time as a resource trait.
Basic Agent Plug-in Scenario

Figure 6. Basic Agent Plug-in Scenario

Note

For simplicity, this plug-in is written for an agent that is running on the same machine as a JBoss ON server.
The HTTP metrics plug-in is designed to run a server and a child service to collect two monitoring metrics. This requires two Java files which define the plug-in behavior and the behavior of a discovery component that the plug-in requires to locate URLs.
As with all agent plug-ins, this example also has a rhq-plugin.xml file as the plug-in descriptor, which is required for JBoss ON to recognize the plug-in configuration. The plug-in is built as a maven project, so it has a pom.xml file, although that is not a requirement, since any properly configured JAR file can be deployed as an agent plug-in.
Directory Layout of an Agent Plug-in Project

Figure 7. Directory Layout of an Agent Plug-in Project

4.4.1. Looking at the Plug-in Descriptor (rhq-plugin.xml)

The plug-in descriptor is where everything is glued together. The first part of the plug-in descriptor defines the basic information about the plug-in, like its name, version number, and schema.

Example 11. Basic Plug-in Information

<?xml version="1.0" encoding="UTF-8" ?>
<plugin name="HttpTest"
        displayName="HttpTest plugin"
        package="org.rhq.plugins.httptest"
        version="2.0"
        description="Monitoring of http servers"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="urn:xmlns:rhq-plugin"
        xmlns:c="urn:xmlns:rhq-configuration">
The package attribute identifies the Java package for Java class names that are referenced in the plug-in configuration in the descriptor.
The HTTP Metrics plug-in is defines as a server which runs a child resource. Services cannot run on their own, so defining the HTTP Metrics resource as a server first allows multiple services to be launched off of it.

Example 12. Server Definition

<server name="HttpCheck" 
   description="Httpserver pinging"
   discovery="HttpDiscoveryComponent"
   class="HttpComponent">
The next step is to add a service element as a child of the server. To differentiate between the server and the service operations, the service has its own discovery and plug-in components, meaning its own .java files and classes. The supportsManualAdd option sells JBoss ON that the HTTP services can be added manually through the UI, which is important for administration.

Example 13. Service Definition

<service name="HttpServiceCheck" 
         discovery="HttpServiceDiscoveryComponent"
         class="HttpServiceComponent" 
         description="One remote Http Server"
         supportsManualAdd="true"
The middle of the <service> element defines the plug-in properties that are configured through the UI. This can be simple (setting a simple string for the URL).

Example 14. Simple Configuration Properties

<plugin-configuration>
   <c:simple-property name="url" 
     type="string" 
     required="true" />
</plugin-configuration>
The properties can be more advanced and allow specific values for the protocol, port, and hostname or IP address, depending on how much information needs to be configured.

Example 15. Complex Configuration Properties

<plugin-configuration>
  <c:list-property name="Servers">
     <c:map-property name="OneServer">
        <c:simple-property name="host"/>
        <c:simple-property name="port">
           <c:integer-constraint 
              minimum="0"
              maximum="65535"/> 
        </c:simple-property>
        <c:simple-property name="protocol">
           <c:property-options>
              <c:option value="http" default="true"/>
              <c:option value="https"/>
           </c:property-options>
        </c:simple-property>
     </c:map-property>
  </c:list-property>
</plugin-configuration>
The last part of the <service> element contains the metrics that are configured for the HTTP Metrics plug-in. The first metric, for the response time, collects a numeric data type. The status metric collects a trait data type. (JBoss ON is intelligent enough to only store changed traits to conserve space.)

Example 16. Defined Metrics

     <metric property="responseTime"
             displayName="Response Time"
             measurementType="dynamic"
             units="milliseconds"
             displayType="summary"/>
            
     <metric property="status"
             displayName="Status Code"
             data type="trait"
             displayType="summary"/>
      </service>
   </server>
</plugin>
The attributes available to define the metric are defined in the agent plug-in XML schema. The attributes used in this example are listed in Table 14, “metric Attributes”.
When defining metrics, values that form part of a larger data structure, such as an array of values, need to be deconstructed into individual values before they can be monitored.
Table 14. metric Attributes
Attribute Description
property Gives the unique name of this metric. The name can also be obtained in the code using the getName() call.
description Gives a human readable description of the metric.
displayName Gives the name that gets displayed in the JBoss ON UI.
data type Sets the type of metric, such as numeric or trait.
units The measurement units to use for numerical data type.
displayType If the value is set to summary, the metric is displayed in the indicator charts and collected by default.
defaultOn Sets whether the metric collected by default.
measurementType Sets what characteristics the numerical values have. The options are trends up, trends down, or dynamic. For both trends metrics, the system automatically creates additional per minute metrics.
Values that form part of a larger data structure, such as an array of values, need to be deconstructed into individual values before they can be monitored.

4.4.2. Looking at the Discovery Components (HttpDiscoveryComponent.java and HttpServiceDiscoveryComponent.java)

Two Java files define how to discover the HTTP metrics server and any URL defined to be monitored.
The first Java file, HttpDiscoveryComponent.java, discovers the HTTP metrics server. The discovery component is called by the InventoryManager in the agent to discover resources. This can be done by a process table scan, querying the MBeanServer, or other means. Whatever the method, the most important thing is that the discovery component returns the same unique key each time for the same resource. The DiscoveryComponent needs to implement org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent and you need to implement discoverResources().
Basically, this retrieves a list of resources discovered by the process scan and creates the details about the discovered resource. Using ProcessInfo gets more information about the process and can be used to exclude certain types of discovered resources from the final list.

Example 17. HttpDiscoveryComponent.java

public class HttpDiscoveryComponent implements 
    ResourceDiscoveryComponent 
{
    public Set discoverResources(ResourceDiscoveryContext context)
        throws InvalidPluginConfigurationException, Exception 
    {
        Set<DiscoveredResourceDetails> result = 
            new HashSet<DiscoveredResourceDetails>();
 
        String key = "http://localhost:7080/"; // Jon server
        String name = key;
        String description = "Http server at " + key;
        Configuration configuration = null;
        ResourceType resourceType = context.getResourceType();
        DiscoveredResourceDetails detail = 
            new DiscoveredResourceDetails(resourceType, 
                key, name, null, description,
                configuration, null
            );
 
        result.add(detail);
 
        return result;
    }
The service discovery component (defined in HttpServiceDiscoveryComponent.java) relies on information passed through the GUI to configure its resources, rather than a discovery scan. The initial definition in the Java file is similar to the one for the server discovery, but this definition has an additional List<Configuration> childConfigs which processes the information that is passed through the UI. This pulls the information for the required url information supplied by the user.

Example 18. Service Discovery

public class HttpServiceDiscoveryComponent 
    implements ResourceDiscoveryComponent<HttpServiceComponent>;
{
    public Set<DiscoveredResourceDetails> discoverResources
        (ResourceDiscoveryContext<HttpServiceComponent> context)
        throws InvalidPluginConfigurationException, Exception
    {
        Set<DiscoveredResourceDetails> result = 
            new HashSet<DiscoveredResourceDetails>();
        ResourceType resourceType = context.getResourceType();

        List<Configuration> childConfigs = 
            context.getPluginConfigurations();
        for (Configuration childConfig : childConfigs) {
            String key = childConfig.getSimpleValue("url", null);
            if (key == null)
                throw new InvalidPluginConfigurationException(
                       "No URL provided");
The list of URLs that are configured are processed and added as a resource with the resource name, description, type, and (critically) the unique resource key that is used by the discovery process.

Example 19. Listing HTTP URL Resources

            String name = key;
            String description = "Http server at " + key;
            DiscoveredResourceDetails detail = 
                new DiscoveredResourceDetails(
                    resourceType, key, name, null,
                    description, childConfig, null
                );
            result.add(detail);
        }
        return result;
    }

4.4.3. Looking at the Plug-in Components (HttpComponent.java and HttpServiceComponent.java)

The plug-in component is the part of the plug-in that does the work after the discovery has finished.
For the server component (HttpComponent.java), the plug-in is pretty simple. The component only implements placeholder methods from the ResourceComponent interface to set the server availability. Setting the availability to UP automatically allows the resource component to start.

Example 20. Server Availability After Discovery

    public AvailabilityType getAvailability() {
        return AvailabilityType.UP;
    }
The service component (HttpServiceComponent.java) is more complex because it must carry out the operations defined in the plug-in descriptor.
Each of the basic functions in the plug-in descriptor is implemented through an appropriate agent facet. All of the gent facets are listed in Section 6.2, “Plug-in Facets”. The HTTP metrics component specifically maps the <metric> element in the descriptor to the MeasurementFacet.
Each facet has its own methods to implement. For monitoring and other operations that require processing metrics, the MeasurementFacet implements the following method:
getValues(MeasurementReport report, Set metrics)
The MeasurementReport passed in is where the monitoring results are added. The metrics value is a list of metrics for which data should be gathered. All of this information can be defined in the <metrics> element or in the UI configuration.
So the next part is the plug-in component to do the work.
public class HttpComponent implements ResourceComponent,
    MeasurementFacet 
{
    URL url;       // remote server url
    long time;     // response time from last collection
    String status; // Status code from last collection
To monitor things, the getValues() method from the MeasurementFacet must be implemented, but that's not the first step to take. A resource cannot be discovered if the resource is down, so the first step is to set a start value to start the service from ResourceContext and give it an availability of UP.

Example 21. Service Resource Availability

    public void start(ResourceContext context) 
        throws InvalidPluginConfigurationException, Exception 
    {
        url = new URL(context.getResourceKey());
        // Provide an initial status, so 
        // getAvailability() returns up
        status = "200"; 
    }
Once the service is started, then the getValues() can be implemented. This actually collects the monitoring data from the given URLs.

Example 22. Implementing getValues()

public void getValues(MeasurementReport report, 
          Set<MeasurementScheduleRequest> metrics) 
        throws Exception 
    {
        getData();
        // Loop over the incoming requests and 
        // fill in the requested data
        for (MeasurementScheduleRequest request : metrics) 
        {
            if (request.getName().equals("responseTime")) {
                report.addData(new MeasurementDataNumeric(
                    request, new Double(time)));
            } else if (request.getName().equals("status")) {
                report.addData(new MeasurementDataTrait
                    (request, status));
            }
        }
    }
The final step is to process the information. Implementing the getData() method in the MeasurementFacet loops the incoming request to see which metric is wanted and then to supply the collected value. Depending on the type of data, the data may be to be wrapped into the correct MeasurementData* class.

Example 23. Implementing getData()

private void getData() 
    {
        HttpURLConnection con = null;
        int code = 0;
        try {
            con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(1000);
            long now = System.currentTimeMillis();
            con.connect();
            code = con.getResponseCode();
            long t2 = System.currentTimeMillis();
            time = t2 - now;
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (con != null)
            con.disconnect();
 
        status = String.valueOf(code);
    }
This implementation for the HTTP Metrics plug-in is very simple. It opens a URL connection, takes the time it takes to connect, and gets the status code. That's all.

4.5. Examples: Embedded and Injected Plug-in Dependencies

JBoss ON agent plug-ins have several different ways of defining dependencies between plug-ins: simple depends, embedded, and injected. The way that a dependency is defined has some affect on how the plug-in behaves. This is all explored more in Section 4.2.4, “Plug-in Dependencies: Defining Relationships Between Plug-ins”.
These examples show how each of the dependency types are defined in the plug-in descriptors for agent plug-ins.

4.5.1. Simple Dependency: JBoss AS and JMX Plug-ins

A required dependency is defined using the <depends> tag. This means that the required plug-in has to be deployed successfully before the plug-in which requires it can be deployed. A simple example of this is JBoss AS, which has a JMX server running inside it. The JBoss AS plug-in for JBoss ON, then, sets a dependency on the JMX plug-in.
The JMX plug-in descriptor simply defines the configuration for the JMX server.

Example 24. JMX Plug-in Descriptor

<plugin name="JMX">
   <server name="JMX Server" discovery="JMXDiscoveryComponent" class="JMXServerComponent">
   ...
   </server>
</plugin>
The JBoss AS plug-in descriptor lists the JMX plug-in as a dependency. This makes all of the JMX plug-in classes available to the JBoss AS plug-in classloader (since the useClasses argument is set to true), but the JBoss AS plug-in descriptor does not actually define or use any source types related to or referencing the JMX plug-in.

Example 25. JBoss AS Plug-in Descriptor

<plugin name="JBossAS">
   <depends plugin="JMX" useClasses="true"/>
   <server name="JBossAS Server" discovery="JBossASDiscoveryComponent" class="JBossASServerComponent">
   ...
   </server>
</plugin>

Important

Plug-ins can require or depend on multiple plug-ins. However, only one of those dependencies can have the value of useClasses=true.

Note

The JMX plug-in is a generic plug-in and can be used by many other plug-ins. Any application that can be managed by JMX can use the JMX plug-in to pick up all of its dependencies, as well as EMS libraries which extend the JMX plug-in.

4.5.2. Embedded Dependency: JVM MBeanServer and JBoss AS

Java Virtual Machines have a built-in JMX MBeanServer called the platform MBeanServer. Any JVM with this platform MBeanServer can be monitored for memory, garbage collectors, threading, and other subsystems through MBeans in the MBeanServer.
The JMX plug-in in JBoss ON can define resource types for each platform MBean, allowing the JBoss ON agent to monitor those MBeans as JBoss ON service resources.
The platform MBeanServer can be found in a standalone JVM process or embedded inside a JBoss AS VM process. If the JVM being monitored is embedded in a JBoss server, then the JBoss ON plug-ins are configured with an embedded plug-in dependency. An embedded dependency means that one plug-in is aware that another plug-in is running inside it.
The JMX plug-in descriptor simply defines the JMX server.

Example 26. JMX Plug-in Descriptor

<plugin name="JMX">
   <server name="JMX Server" discovery="JMXDiscoveryComponent" class="JMXServerComponent">
      <service name="VM Memory System"
               discovery="MBeanResourceDiscoveryComponent"
               class="MBeanResourceComponent"
               description="The memory system of the Java virtual machine">
      ...
      </service>
   ...
   </server>
</plugin>
The embedding is done in the JBoss AS plug-in descriptor. Along with setting a required dependency for the JMX plug-in, the JBoss AS plug-in's <server> definition pulls in the sourcePlugin and sourceType attributes. The reason for this is to run a second JMX discovery scan, this one using the org.rhq.plugins.jmx.EmbeddedJMXServerDiscoveryComponent class to run a special discovery scan looking for a JVM embedded in a JBoss AS instance. The sourcePlugin and sourceType attributes, then, copy the resource type and give it a unique name so that any embedded JVMs are treated as different resource types than standalone JVMs.

Example 27. JBoss AS Plug-in Descriptor

<plugin name="JBossAS">
   <depends plugin="JMX" useClasses="true"/>
   <server name="JBossAS Server" discovery="JBossASDiscoveryComponent" class="JBossASServerComponent">
      <server name="JBoss AS JVM"
              description="JVM of the JBossAS"
              sourcePlugin="JMX"
              sourceType="JMX Server"
              discovery="org.rhq.plugins.jmx.EmbeddedJMXServerDiscoveryComponent"
              class="org.rhq.plugins.jmx.JMXServerComponent">
      ...
      </server>
   ...
   </server>
</plugin>
This type of embedded plug-in also illustrates that an embedded resource type can be discovered using a different discovery component from that of the source plug-in type.

4.5.3. Injected Dependency: Hibernate with JVM and JBoss AS

An injection dependency is the logical opposite of an embedded dependency; it is an awareness in the plug-in that the resource configured by the plug-in is running inside another resource. The parent resources are listed as dependencies.
One common example of this is Hibernate. Hibernate can run in either a standalone J2SE JVM instance or a JBoss AS server; for this example, it runs inside a JVM in a JBoss AS instance. The plug-ins have chained dependencies, where either the JMX and JBoss AS plug-ins can be parents to the Hibernate plug-in, and both the Hibernate and JBoss AS plug-ins list the JMX plug-in as a required dependency.
Hibernate, JMX, and JBoss AS Dependencies

Figure 8. Hibernate, JMX, and JBoss AS Dependencies

As before, the JMX plug-in descriptor only defines the JMX plug-in, without any dependencies.

Example 28. JMX Plug-in Descriptor

<plugin name="JMX">
   <server name="JMX Server" discovery="JMXDiscoveryComponent" class="JMXServerComponent">
   ...
   </server>
</plugin>
The JBoss AS plug-in sets a required dependency on the JMX plug-in, but no other dependencies are required to be defined (although they could be).

Example 29. JBoss AS Plug-in Descriptor

<plugin name="JBoss AS">
   <depends plugin="JMX" useClasses="true"/>
   <server name="JBossAS Server" discovery="JBossASDiscoveryComponent" class="JBossASServerComponent">
   ...
   </server>
</plugin>
The most complex definition is for the Hibernate plug-in. This sets an explicit dependency on the JMX plug-in using the <depends> element. The Hibernate plug-in then defines what resource types could operate as its parents by running a discovery scan (specifically for the Hibernate Statistics resource) against potential parent types. The list of parent resource types is contained in the <runs-inside> element, and each potential parent is identified by name and plug-in type in <parent-resource-type> elements.

Example 30. Hibernate Plug-in Descriptor

   <depends plugin="JMX" useClasses="true"/>
   <service name="Hibernate Statistics"
            discovery="org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent" class="StatisticsComponent">
     <runs-inside>
         <parent-resource-type name="JMX Server" plugin="JMX"/>
         <parent-resource-type name="JBossAS Server" plugin="JBossAS"/>
      </runs-inside>
   ...
   </service>
</plugin>
When a plug-in is dependent on another plug-in, it is implicitly dependent on whatever other plug-ins are required. For example, Hibernate depends on the JBoss AS plug-in. Even if the Hibernate plug-in didn't explicitly state a dependency on the JMX plug-in, it would still be dependent on the JMX Plug-in because the JBoss AS plug-in requires it.

4.6. Extended Example: Drift Monitoring

Drift monitoring is allowed for a resource by defining a default drift definition in the plug-in. In the plug-in configuration, the drift definition creates a default template that indicates that a resource supports drift monitoring. (Additional templates can be created by users or the default template can be revised when it is applied to a resource.)
At its most basic, the drift definition sets a target location for the drift system to monitor. This location can be identified from several different configuration areas for the resource:
  • fileSystem, which is any directory on the machine local to the resource
  • pluginConfiguration, which is defined property in the resource plug-in, like a home directory
  • resourceConfiguration, a resource configuration property
  • measurementTrait, a trait that is gathered about the resource
This target location is the base directory. The element which identifies where to find the value for the base directory the value name, while the actual value is the context. For example, for a base directory of /etc/, the elements in the drift definition are:
Value name: fileSystem
Value context: /etc
The most basic drift definition only needs to define the value name and context.

Example 31. Base Directory Only

     <drift-definition name="Template-File System"   
                       description="Monitor the file system for drift. Definitions should set a more specific base directory as the file system root is not recommended.">  
         <basedir>  
             <value-context>fileSystem</value-context>  
             <value-name>/</value-name>  
         </basedir>  
     </drift-definition>
It is possible to set more information, like subdirectories or file types which should be explicitly included or excluded. These are additional paths, beneath the base directory, and file types can be identified by patterns.
If a directory or file type is explicitly included, then all other files and directories are implicitly excluded (and vice versa, if something is explicitly excluded, everything else is implicitly included). There can be multiple paths and patterns defined.

Example 32. Included Paths and Patterns

<drift-definition name="Template-Base Files"
                  description="Monitor base application server files for drift. It defines monitoring for some standard sub-directories of the HOME directory.  Note, it is not recommeded to monitor all files for an application server. There are many files, and many temp files.">
    <basedir>
         <value-context>pluginConfiguration</value-context>
         <value-name>homeDir</value-name>
    </basedir>
    <includes>
	<include path="bin" pattern="*/*.sh" />
        <include path="lib" />
        <include path="client" />
    </includes>
</drift-definition>

Note

Multiple drift definitions can be defined for a resource type, but each drift definition defined only a single base directory to monitor for drift.

4.7. Extended Example: Provisioning and Content Deployments (Bundles)

Allowing content to be deployed to a resource using the bundle system is enabled by defining allowed target locations for content to be provisioned to.
As with drift configuration, bundle configuration identifies the target location based on information in one of four areas:
  • fileSystem, which is any directory on the machine local to the resource
  • pluginConfiguration, which is defined property in the resource plug-in, like a home directory
  • resourceConfiguration, a resource configuration property
  • measurementTrait, a trait that is gathered about the resource
That area is the value name in the bundle definition. The actual value is the value context.

Example 33. A Single Bundle Base Directory

     <bundle-target>  
         <destination-base-dir name="Root File System" description="The top root directory on the platform (/)" >  
           <value-context>fileSystem</value-context>  
           <value-name>/</value-name>  
        </destination-base-dir>  
     </bundle-target> 
The potential target locations, the <destination-base-dir>, are presented to users as options when they are provisioning a bundle. Users can deploy a bundle to any, user-defined directory beneath that base directory, but they cannot deploy to a location outside that directory. If users will reasonably want to provision content to multiple directories, then each directory needs to be added to the <bundle-target> definition.

Example 34. Multiple Bundle Base Directories

<bundle-target>
    <destination-base-dir name="Install Directory" description="The top directory where the JBossAS Server is installed. ">
      <value-context>pluginConfiguration</value-context>
      <value-name>homeDir</value-name>
   </destination-base-dir>
   <destination-base-dir name="Profile Directory" description="The profile configuration directory.">
      <value-context>pluginConfiguration</value-context>
      <value-name>serverHomeDir</value-name>
   </destination-base-dir>
</bundle-target>

Note

There can be only one bundle definition for a resource type, but it can define multiple locations where content is allowed to be deployed.

4.8. Extended Example: Asynchronous Availability Checks

Availability scans are performed by a resource plug-in itself, for its defined resource types, and then reported to the agent.

Note

Any async availability collector only applies to the resource types within the plug-in. This is much safer and more performant configuration than increasing the agent's availability availability scan time. The availability scan time applies to all plug-ins in the plug-in container, so a longer timeout interval could easily result in the agent delaying or missing sending availability updates to the JBoss ON server and spuriously skew the histories of all resources on the platform.
Resource availability is defined within a plug-in as part of starting a resource type, as described in Example 20, “Server Availability After Discovery” and Example 21, “Service Resource Availability”. The method for retrieving and setting an availability state for a resource is getAvailability().
When a resource is started, it is automatically set to an UP state. The plug-in container checks for that availability state as part of the agent's periodic availability and monitoring scans.
Availability checks are typically very fast, fractions of a second. The plug-in container limits how long an availability check can run to five seconds, to prevent a rogue plug-in from delaying availability reporting for all other resources managed by the agent. There can be instances where a certain plug-in or resource type consistently has scans longer than the five-second timeout period.
Custom plug-ins can use a special availability collector to perform asynchronous availability checking. Basically, with async availability checks, the resource component creates its own, independent thread to run availability checks. Within that thread, the availability checks can take as long as they need to complete. The availability checks can also be run fairly frequently, every minute by default, to make sure that the availability state is current, even if the full check takes longer to complete.
The component caches and then reports the most recent availability result to the plug-in container. That stored last availability can be delivered very quickly, in the fractions of a second that the plug-in container expects.
Async availability checks are implemented through the AvailabilityCollectorRunnable class.
The availability collector is defined in three parts of the plug-in.
First, the availability collector itself is added as a data member.

Example 35. Part 1: The Collector

public class YourResourceComponent implements ResourceComponent {
 
    // your component needs this data member - it is your availability collector
    private AvailabilityCollectorRunnable availCollector;
Then, the collector is added to the AvailabilityFacet within the resource's start method. The facet object starts the collector, returns an availability type, and sets a collection interval for the longer availability checks. The facet is what connects to the resource, periodically, to check its availability.
The collector is part of the resource context and is defined in both the start and stop methods.

Example 36. Part 2: Start the Availability Collector

    public void start(ResourceContext context) {
        availCollector = resourceContext.createAvailabilityCollectorRunnable(new AvailabilityFacet() {
            public AvailabilityType getAvailability() {
                // Perform the actual check to see if the managed resource is up or not
                // This method is not on a timer and can return the availability in any amount of time
                // that it needs to take.
                return ...AvailabilityType...;
            }
        }, 60000L); // 1 minute - the minimum interval allowed
 
        // Now that you've created your availability collector, start it to assign it a thread in the pool.
        availCollector.start();
 
        // ... and the rest of your component's start method goes here ...
	}


    public void stop() {
        // Stop your availability collector to cancel the collector and kill its thread.
        availCollector.stop();
 
        // ... and the rest of your component's stop method goes here ...
    }
Resource availability — with or without asynchronous availability checking — is collected with the getAvailability() method. When the async availability collector is created, then the getAvailability() method needs to return the last known results stored in the collector rather than attempting to run a new availability scan.
So the last configuration point for the async availability check is to configure the return value for the getAvailability() method.

Example 37. Part 2: Return the Last Known Availability

    public AvailabilityType getAvailability() {
	// This method quickly returns the last known availability that was recorded 
	// by the availability collector.
        return availCollector.getLastKnownAvailability();
    }
}
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat Documentation

We help Red Hat users innovate and achieve their goals with our products and services with content they can trust.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

© 2024 Red Hat, Inc.