Red Hat Training

A Red Hat training course is available for Red Hat JBoss Operations Network

2.2. The Breakdown of Server-Side Plug-in Configuration

JBoss ON plug-ins are packaged .jar files.The directory structure, libraries, and classes used by those .jar files is completely up to the discretion and requirements of the plug-in writer, with only one requirement: All plug-in .jar files must have a plug-in descriptor file, META-INF/rhq-serverplugin.xml.
NOTE
The one major guideline when writing plugins is that it should implement the org.rhq.enterprise.server.plugin.pc.ServerPluginComponent class. This controls the lifecycle of the plug-in within the container.
The server-side plug-in is defined within the JBoss ON server through three types of files:
  • An XML file which functions as the plug-in's descriptor
  • Java files which pull in the descriptor information and implement the classes for the plug-in.
  • Optional library dependencies. Any third-party libraries must be stored in the plug-in JAR file's lib/ directory.

2.2.1. Descriptor and Configuration

The plug-in descriptor is the mechanism that tells the plug-in container how the plug-in should be deployed, along with any additional information about the plug-in configuration and behavior. The plug-in descriptor is contained in an XML file which can use any default or user-defined tags and attributes to define that configuration.
NOTE
The XML file for the server-side plug-in is defined in the rhq-serverplugin.xml file in the META-INF/ directory in the plug-in's JAR file. (Default server-side plug-ins follow this same configuration.) This file is required.
The most important configuration in the plug-in descriptor is the basic definition for the plug-in which includes the type of plug-in, its name, and its version. Every plug-in has this basic definition. If the version number is not passed manually in the plug-in descriptor, then it is picked up automatically from the MANIFEST.MF file.
The key to server-side plug-ins is their flexibility. They have near absolute access to server functionality and can extend any of the existing functions of the server — monitoring, alerting, remote actions, provisioning, resource configuration, whatever. Maintaining this flexibility demands that server-side plug-ins at least have the option of advanced configuration in three general areas:
  • Scheduling actions periodically or using cron schedules
  • Setting global parameters for all instances of a specific plug-in type
  • Allowing local or instance-specific configuration for a plug-in type

2.2.1.1. Definitions and Classes

Each server-side plug-in has a root element that contains attributes for the name, display name, package, version, and other plug-in information. This also imports and defines the XML schema definitions used for the plug-in configuration (which is described in more detail in Section 2.2.2, “Schema Files”).

Example 2.1. Plug-in Descriptor: Definition

<alert-plugin
         name="alert-email"
         displayName="Alert:Email"
         xmlns="urn:xmlns:rhq-serverplugin.alert"
         xmlns:c="urn:xmlns:rhq-configuration"
         xmlns:serverplugin="urn:xmlns:rhq-serverplugin"
         package="org.rhq.enterprise.server.plugins.alertEmail"
         description="Alert sender plugin that sends alert notifications via email"
         version="1.0"
         >
The second part of the plug-in configuration sets the components or classes to use with the plug-in. Every server-side plug-in will implement the org.rhq.enterprise.server.plugin.pc.ServerPluginComponent class, which provides simple lifecycle management for the plug-in. This component provides the hook for the container to initialize, start, stop, and shut down the plug-in. When a plug-in is initialized, it is given a server plug-in context that provides information about the runtime environment of the plug-in.
This component is a stateful object, remaining alive for as long as the plug-in is initialized. While this object is alive, the plug-in can perform any tasks or call any methods to do the work they need to do.
Developers have the option of invoking a component for the plug-in in one of two ways:
  • Using the <plugin-component> tag to specify the class (this is available to every type of plug-in)
  • Using a user-defined tag to identify the class (this is available to some types of server-side plug-ins, depending on the available schema for the plug-in container)
It's not required to use any given invocation method for a plug-in, so using something like <plugin-component> is optional. Whatever the method of invoking the component, only one plug-in component can be specified in the descriptor.

Example 2.2. Plug-in Descriptor: Class Info

<serverplugin:plugin-component class="MyLifecycleListener" />
Alternatively, a container-defined tag (like <plugin-class> for the email alert server-side plug-in) can be created for the plug-in. Creating a class introduces the option to provide configuration options or other information with the component.
<plugin-class>RolesSender</plugin-class>
NOTE
The example in Example 2.2, “Plug-in Descriptor: Class Info” is specific to certain type of server-side plug-in. Not all server-side plug-ins support that structure.
Some descriptor tags are made available through the schema defined for that plug-in type. That is the schema that is defined in the plug-in container schema files. In this example, the alert sender plug-in container supplies the <plugin-class> element for any alert sender plug-in to hook into the alert mechanism in JBoss ON.
Container-defined schema isn't ad hoc. It can't be dropped into just any plug-in file, and developers cannot define their own schema elements.

2.2.1.2. Control Operations

Sometimes a user need to interact directly with a server plug-in's stateful component. This interaction can take any number of forms, such retrieving a list of agents or resources in contact with the plug-in to testing the plug-in itself.
To allow user-defined controls, the ServerPluginComponent class can optionally implement the ControlFacet interface. These control operations can then be invoked directly in the JBoss ON web interface, in the plug-in configuration area.
Control operations are configured in the plug-in descriptor using the <control> element, which is a child to the <plugin-component> element. Controls are optional, so you do not have to specify any, or you can specify multiple controls. Each control can also have optional parameters for the user to pass to the control operation, as well as (optional) result properties.

Example 2.3. Control Operation Configuration

<serverplugin:plugin-component class="MyLifecycleListener">
   <serverplugin:control name="testControl" description="A test control operation">
      <serverplugin:parameters>
         <c:simple-property name="paramProp" required="true" description="Set to 'fail' to simulate an error"/>
      </serverplugin:parameters>
      <serverplugin:results>
         <c:simple-property name="resultProp" required="false"/>
      </serverplugin:results>
   </serverplugin:control>
</serverplugin:plugin-component>
Control operations can be used with any server-side plug-in type.

2.2.1.3. Scheduling Jobs

One of the main advantages of the server-side plug-in framework is the capability to define scheduled jobs for the plug-in. The plug-in container handles actually scheduling and invoking those jobs. The plug-in descriptor has the scheduling information which simply tells the plug-in container what classes and methods should be invoked when the job is triggered, how often those jobs should be triggered, and what configuration settings to pass to the job method when it is invoked.
The job can perform any work it needs to get done when it is invoked, including accessing the plug-in's stateful component, as well as any information about the job itself through the ScheduledJobInvocationContext component.
Job configuration is entirely flexible:
  • A job class can be stateless (meaning each job class is instantiated for each job invocation) or it can be stateful by invoking the plug-in component instance.
    NOTE
    Any server-side plug-in can define a plug-in component to act as the lifecycle listener for the plug-in. Using a plug-in component is extremely useful; in fact, it is the only mechanism for a Generic server-side plug-in to connect with the core server.
  • A job can be concurrent, meaning more than one invocation can be performed at any one time on any number of servers (including on the same server). If a job is not concurrent, that means one and only one job invocation can be performed at any time. (If a job is not concurrent and is not clustered, then only one job invocation can be performed anywhere in the JBoss ON server cloud).
  • A job can be clustered, meaning the job can be run from any server in the JBoss ON server cloud. If a job is not clustered,  the job always runs on the machine where the job was scheduled. This works in conjunction with the concurrent setting.
  • The schedule can be either periodic (such as running every hour) or recurring on a pattern (such as every Monday at 5pm).
  • There can be multiple jobs scheduled for the same plug-in, each in its own <map-property> under the plug-in's <scheduled-jobs> entry.
Each scheduled job is a mapping entry that sets the name, schedule, frequency, methods, or classes invoked by the job, and any callback data.

Example 2.4. Plug-in Descriptor: Scheduled Jobs

<serverplugin:scheduled-jobs>
         <!-- notice that we use the map name as the methodName -->
         <c:map-property name="myScheduledJobMethod1">
             <c:simple-property name="enabled" type="boolean" required="true" default="true" summary="true" description="Whether or not the job should be scheduled"/>
             <c:simple-property name="scheduleType" type="string" required="true" default="cron" summary="true" description="Indicates when the schedule triggers">
                 <c:property-options>
                     <c:option value="periodic"/>
                     <c:option value="cron" default="true"/>
                 </c:property-options>
             </c:simple-property>
             <c:simple-property name="scheduleTrigger" type="string" required="true" default="0 0/5 * * * ?" summary="true" description="Based on the schedule type, this is either the period, in milliseconds, or the cron expression"/>
             <c:simple-property name="concurrent" type="boolean" required="false" default="false" summary="true" description="Whether or not the job can be run multiple times concurrently"/>
             <c:simple-property name="clustered" type="boolean" required="false" default="true" summary="true" description="Whether or not the job can be run anywhere in the JBoss ON server cluster, or if it must be run on the server where the job was schedule."/>
         </c:map-property>
</serverplugin:scheduled-jobs>
There is only one <scheduled-jobs> container entry. Each individual job is within this container, in mapping (<map-property>) entries.
2.2.1.3.1. States for Jobs
Server-side plug-ins can run one of two jobs: stateless or stateful. The only difference between a stateful job and a stateless job is whether the job specifies a class. If a plug-in does not specify a class, the plug-in job is stateful because it uses the plug-in component. If the job specifies a class, then the class is instantiated every time a new job starts, so the job is stateless.
At its simplest, a stateless job requires only a class and a method to call when the plug-in is started. For example:

Example 2.5. Stateless Job Configuration

<c:map-property name="statelessJob1" description="invokes a stateless job class but given a job context">
      <c:simple-property name="class" type="string" required="true" readOnly="true" default="MyScheduledJob" summary="true" />
      <c:simple-property name="methodName" type="string" required="true" readOnly="true" default="executeWithContext" summary="true" />
</c:map-property>
Aside from the class specified for stateless jobs, stateless and stateful jobs have similar configuration options. Both stateful and stateless jobs can take other optional parameters that help schedule the job. Scheduled jobs use the same configuration properties as other components in the plug-in, but scheduled jobs have a specialized semantics that require special properties to be defined to set create the job. Essentially, this is a property map for each job. These properties include:
  1. A method name for the job to invoke. For stateful jobs, the target method is in the plug-in component; for stateless jobs, it is in the class specified with the class property. Either way, the method name tells the server what to call. A default method is already defined in the plug-in component, and stateful jobs can call on that without having a specific method name property.
    <c:simple-property name="methodName" type="string" required="true" readOnly="true" default="executeWithContext" summary="true" />
    
    Any method must either have no arguments or have a single argument of the type ScheduledJobInvocationContext.
  2. A setting showing whether the job is enabled.
    <simple-property name="enabled" type="boolean" ... />
    
  3. A schedule type showing whether it's a periodic or cron job. The type of job is identified in the option which is set to true. For example:
    <simple-property name="scheduleType" ... default="periodic" ... >
          <c:property-options>
                <c:option value="periodic" default="true"/>
                <c:option value="cron" />
          </c:property-options>
    </c:simple-property>
    
  4. The actual schedule for when to run the job (the "trigger"), which can be a time period or a cron schedule. For a periodic job, this gives a time interval, in milliseconds:
    <simple-property name="scheduleTrigger" type="string" required="true" default="60000" ... />
    
    For a cron job, the default argument contains the full cron expression:
    <simple-property name="scheduleTrigger" type="string" required="true" default="0 0/5 * * * ?" ... />
    
  5. A setting on whether the job is concurrent (meaning, whether this job can be running multiple times on more than one server or at the same time). If this is false, so that only one instance of the job can be running at a time, then even if multiple servers are scheduled to run the job, it will only run on one of them.
    <simple-property name="concurrent" type="boolean" ... />
    
  6. A job can allow a setting on whether it runs anywhere in the JBoss ON server cloud or if it must be run on the same machine where the job was scheduled. Setting the cluster value to true allows the job to be called from any server in the JBoss ON cloud, so the job is clustered. This value should be false if the job must be run on all machines on schedule. Since all plug-ins are registered on all servers automatically, a non-clustered job will run on each server, independently.
    <simple-property name="clustered" type="boolean" default="true" ... />
    
  7. A job can optionally contain custom strings which accept callback data.
    <simple-property name="custom1" type="boolean" required="true" default="true" summary="true" description="A custom boolean for callback data"/>
    
    Callback data can be of any type — boolean, string, long, or whatever else is appropriate for the job being performed.
  8. Stateless jobs have a property that passes the method name of the class. The method name can identify the class that is called in the plug-in component or, alternatively, it can call a class to instantiate when the job is invoked. Both the method and the class keys are shown in Example 2.5, “Stateless Job Configuration”. Whatever class is used as the target, it must have the method defined in the method name simple property.
    Typically, the class isn't specified because the job will target the stateful plug-in component. The class property allows the option of writing a stateless job, however.
2.2.1.3.2. Concurrent and Clustered Jobs
When a scheduled job is run is determined by its schedule (scheduleTrigger setting). Where and how a job is run is determined by two settings: concurrent and clustered.
Just because the scheduled time for a job arrives doesn't necessarily mean that a specific JBoss ON server should run it. The server has to determine which server should run the task, and this is given in the clustered setting. If the clustered setting is set to true, then any server in the JBoss ON server cloud can invoke the task; if it is set to false, then the task can only run on the server where it is scheduled.
Note
One thing about clustering is that while the job can run on any server in the JBoss ON server cloud, there is no way to predict or require which servers will run the job. Some machines might never run the job.
On the other hand, the JBoss ON server-side plug-ins are automatically propagated to all servers in the cloud when they are deployed. If clustering is turned off (meaning each job only runs from the local server), all JBoss ON servers will eventually run this job independent of when the other servers run the job. The end result is that you are guaranteed that all JBoss ON servers will run this job on a consistent schedule and may even run more than one of the jobs at the same time.
Once the JBoss ON server identifies where to run the task, then it must find out if the task is already running. If the concurrent setting is true, then the job is invoked every the schedule is triggered, even if the task is already running on another server (or even the same server). If concurrent is set to false and the job is already running somewhere in the JBoss ON server cloud, then the server must wait until that job invocation is complete before it can run the job.
The clustered and concurrent settings can play off each other in several ways.
If a job is clustered but not concurrent, then before the JBoss ON server can invoke a job, it has to check whether it is running anywhere else in the JBoss ON server cloud. If it is, then the server has to wait until that job completes before invoking the new job.
If the job is not clustered and not concurrent, then the JBoss ON server only checks the local machine to see if the job is running. If the job is not running locally, then the JBoss ON server can invoke the job, even if it is running on another server in the cloud because the job is not clustered.
Essentially, the clustered setting determines how strict the concurrency check should be. If clustered is false, the concurrency check is performed only on the machine where the job was scheduled; if clustered is true, the concurrency check is performed on all machines in the cluster.

Table 2.2. Comparison of Concurrent and Clustered Behavior

Concurrent Clustered When the schedule is triggered...
true true ... the job will always be invoked. It may be invoked on any server in the JBoss ON server cloud.
true false ... the job will always be invoked and will run on the server where the job is scheduled.
false true ... the JBoss ON server checks to see if this job is running anywhere else in the JBoss ON server cloud. If it is, the new job must wait until that old job has finished before being invoked. Only one instance of this job can ever be running anywhere in the JBoss ON server cloud.
false false ... the scheduler checks to see if the job is already running locally before invoking the job. Only one job invocation may be running on the server at any time, but multiple servers in the cloud may be running the job at the same time.
Note
To guarantee that a job will run on all servers on a consistent schedule, set clustered to false. concurrent will determine if you are allowed to start a new job on a machine while an old job is still running on that machine.
To run a job somewhere, but not on any one specified JBoss ON server, set clustered to true. concurrent will determine if you are allowed to have more than one job running anywhere at any one time.

2.2.1.4. Plug-in Configuration (Both Global and Local)

Global configuration settings can be set for default values or global settings for every instance of that server-side plug-in. All of the global configuration parameters are contained within a <plugin-configuration> entry (defined in the standard JBoss ON schema) and then each parameter is identified with a <simple-property> item. Global settings are useful for any plug-in which accesses a single identity, such as alerts which use the same email or SNMP account.

Example 2.6. Plug-in Descriptor: Global Configuration

<serverplugin:plugin-configuration>
         <c:simple-property name="user" type="string" required="false"/>
         <c:simple-property name="password" type="password" required="false"/>
</serverplugin:plugin-configuration>
The same server-side plug-in can be created with multiple instances. These different instances are obviously going to require slightly different settings in order to fulfill different functions. For example, different instances of email alert senders should send notifications to different groups of sys admins.
These instance-specific configuration settings are identified in the plug-in descriptor through a configuration entry using schema specific to the server-side plug-in (such as <alert-configuration> and <simple-property> item).

Example 2.7. Plug-in Descriptor: Instance-Specific Configuration (Alerts)

<alert-configuration>
         <c:simple-property name="emailAddress" displayName="Receiver Email Address(es)" type="longString"
                 description="Email addresses (separated by comma) used for notifications."/>

h5. </alert-configuration>
Each plug-in container type defines its own set of schema, relevant to that type of plug-in. For example, GUI or perspectives have separate explicit schema elements for different types of UI elements.

Example 2.8. Plug-in Descriptor: Instance-Specific Configuration (Perspectives)

<perspectivePlugin
   description="The Core Perspective defining Core UI Elements"
   displayName="Core Perspective"
   name="CorePerspective"
   package="org.rhq.perspective.core"
   xmlns="urn:xmlns:rhq-serverplugin.perspective"
   xmlns:serverplugin="urn:xmlns:rhq-serverplugin"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">


<!-- Menu -->
<menuItem name="logo" displayName="" url="/" iconUrl="/images/JBossLogo_small.png">
   <position placement="firstChild" />
</menuItem>
Check the plug-in container schema in the sourceRoot/modules/enterprise/server/xml-schemas/src/main/resources directory to see what elements are available for the specific type of plug-in. Not all plug-in types accept local configuration settings; generic plug-ins, for example, only accept global plug-in configuration.
NOTE
The container schema is included with the RHQ source code, not the JBoss ON packages. To check out the code:
git clone http://git.fedorahosted.org/git/rhq/rhq.git
The example plug-ins are the sourceRoot/etc/samples/custom-serverplugin/ directory which can be used as a template for writing new plug-ins. Rather than checking out the entire source code, you can manually download the custom-serverplugin files at this URL:
http://git.fedorahosted.org/git/?p=rhq/rhq.git;a=tree;f=etc/samples/custom-serverplugin;hb=master

2.2.2. Schema Files

The server-side 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 the plug-in container type.
The descriptor file must conform to the elements within the plug-in types scheme. If the descriptor is improperly configured — such as missing required elements or attempting to use elements not defined in the plug-in container's schema — then the plug-in will fail to load.
Every plug-in — both agent plug-ins and server-side plug-ins — uses the rhq-configuration.xsd file. This file defines the basic configuration options available to any plug-in.
The schema in rhq-configuration.xsd file is extended by rhq-serverplugin.xsd. This file provides additional XML elements that are specific to the functions of server-side plug-ins. This file is referenced by every server-side plug-in.
The last XSD file used by a server-side plug-in is one that is specific to its plug-in container. The plug-in container schema files may define required elements for plug-ins of that type (as with alert sender plug-ins) or may not have any specific schema elements (as with generic plug-ins).
Specific server-side plug-in schema files are located in the sourceRoot/modules/enterprise/server/xml-schemas/src/main/resources directory.
This section takes a high-level look at the configuration elements and attributes that are associated with each XSD to give you enough familiarity with XSD in general and specifically the files with JBoss ON in order to help write server-side plug-ins and extend the schema as necessary.
More information about each XSD file is available through the comments (in <xs:annotation> items) in the XSD files themselves. For more information on XSD files and XML schema, check out a reference guide for XML and XSD, like http://www.w3.org/TR/xmlschema-0/.
Note
The JBoss ON XSD files are annotated with descriptions of each configuration area within the file.

2.2.2.1. Parsing the Plug-in Container Schema Files

All of the schema elements available and required for a specific type of server-side plug-in are defined in the schema for that type of plug-in container. There are two relevant elements configured in the XSD files:
  • Elements
  • Attributes
NOTE
For more detailed information on XML schema, review a reference guide for XML and XSD. For example http://www.w3.org/TR/xmlschema-0/.
Elements translate into available tags for the plug-ins XML file. For example:
<xs:element name="alert-plugin">
In the plug-in's XML file, that element defines the tag:
<alert-plugin>
Stuff
</alert-plugin>
Attributes are flags that available to the tags in the XML file. For example:
<xs:attribute name="name">
The attribute looks like this in the XML file:
<alert-plugin name="myAlertPlugin">
Stuff
</alert-plugin>
Elements and attributes are arranged hierarchically in the XSD file. The container element for the plug-in file is defined at the top of the XSD. Child elements reference the parent element's type and are included as sub-elements within the parent's definition. Likewise, any attributes that are available to an element are included within the element's definition.
One of the easiest ways to find the tags and attributes defined for a type of server-side plug-in is to check the plug-in container schema in the sourceRoot/modules/enterprise/server/xml-schemas/src/main/resources directory and search for <xs:element name=""> and <xs:attribute name=""> entries.
Note
The container schema is included with the RHQ source code, not the JBoss ON packages. To check out the code:
git clone http://git.fedorahosted.org/git/rhq/rhq.git

2.2.2.2. The rhq-configuration.xsd File

The rhq-configuration.xsd file provides schema which is available for all JBoss ON plug-ins. This is used by both agent and server-side plug-ins.
The rhq-configuration.xsd file is in source/modules/core/client-api/src/main/resources.
NOTE
The container schema is included with the RHQ source code, not the JBoss ON packages. To check out the code:
git clone http://git.fedorahosted.org/git/rhq/rhq.git
The example plug-ins are the sourceRoot/etc/samples/custom-serverplugin/ directory which can be used as a template for writing new plug-ins. Rather than checking out the entire source code, you can manually download the custom-serverplugin files at this URL:
http://git.fedorahosted.org/git/?p=rhq/rhq.git;a=tree;f=etc/samples/custom-serverplugin;hb=master
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 2.3. 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 2.4. rhq-configuration.xsd Schema Element 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.
There are many other elements and attributes set in the rhq-configuration.xsd file. Each one is described by the text in the <xs:annotation> tags for the item.

2.2.2.3. The rhq-serverplugin.xsd File

The rhq-serverplugin.xsd is the central server-side plug-in schema file.
The rhq-serverplugin.xsd file provides schema elements that are important for every server-side plug-in. Possibly the two most important elements are <server-plugin> (for the plug-in's root element) and <scheduled-jobs> (for running jobs on a resource or server).
The rhq-serverplugin.xsd file is in source/modules/enterprise/server/xml-schemas/src/main/resources.
The most common elements in the rhq-serverplugin.xsd file are listed in Table 2.5, “rhq-serverplugin.xsd Schema Elements”.

Table 2.5. rhq-serverplugin.xsd Schema Elements

Element Description
server-plugin Contains the root element for the plug-in descriptor.
help Contains additional usage information or other tips that can help users integrate the plug-in with other applications.
plugin-component Identifies a class that will be notified when the plug-in stops or starts. This is a stateful object and is the target of any scheduled stateful jobs.
scheduled-jobs Defines a schedule for the plug-in to execute any specified task
Most of the attributes defined within the rhq-serverplugin.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 server-side plug-ins.

Table 2.6. rhq-serverplugin.xsd Schema Element Attributes

Attribute Description
package For setting the plug-in package name.
version For setting the version of the plug-in. If the version isn't set in the descriptor, the plug-ins JAR file, META-INF/MANIFEST.MF, must define the version number in the Implementation-Version setting.
apiVersion For setting the version of the API used to write the plug-in.
There are many other elements and attributes set in the rhq-serverplugin.xsd file. Each one is described by the text in the <xs:annotation> tags for the item.

2.2.3. Java Class Files

Any Java class files used by the plug-in to implement elements like ServerPluginComponent or ControlFacet must be available in the JAR file for the plug-ins.