2. Writing Server-Side Plug-ins: Background
2.1. An Intro to Server-Side Plug-ins
- Alert sender plug-ins for methods to send alert notifications for resources
- Bundle plug-ins for deploying files and application
- Drift plug-ins for monitoring resource or filesystem configuration and files
- Content plug-ins for managing resource configurations
- Generic plug-ins for everything else
Important
- Once the server-side plug-in is built and deployed, the plug-in is a JAR file with a
META-INF/
directory which contains therhq-serverplugin.xml
plug-in descriptor. - Each plug-in is independent of every other plug-in. Unlike agent plug-ins, server-side plug-ins do not interact with each other. There are no plug-in dependencies for server-side plug-ins.
Figure 2. Server-Side Plug-in Containers
Note
Plug-in Type | Description | Container Name |
---|---|---|
Generic | Catch-all type for any custom plug-ins. This type of plug-in only interacts with the plug-in container for the container to start and stop the plug-in and to initialize and shutdown the plug-in libraries. | Generic Plugin |
Alert methods | Defines an alert notification method, or the way that an alert is sent. | AlertHandler |
Bundle | Defines and processes a type of bundle. This type of plug-in performs tasks that the core server needs to process and manage bundles of specific bundle types, such as Ant recipes or file-based bundles. Each bundle server plug-in knows about and can process a single bundle type. | Bundle Plugin |
Drift | Processes drift operations and configuration. This stores and retrieves content (files) being managed for drift detection and remediation. | Drift JPA Plugin |
Content | Contains metadata for a a repository or a group of repositories. | PackageSource |
Repository (also Package) | Defines a content repository. Plug-ins can define a single repository,which is then used for provisioning, entitlements, and updates for JBoss ON-managed resources. | ChannelSource |
Note
2.2. The Breakdown of Server-Side Plug-in Configuration
.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
org.rhq.enterprise.server.plugin.pc.ServerPluginComponent
class. This controls the lifecycle of the plug-in within the container.
- 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
Note
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.
MANIFEST.MF
file.
- 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
Example 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" >
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.
- 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)
Example 2. Plug-in Descriptor: Class Info
<serverplugin:plugin-component class="MyLifecycleListener" />
<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
<plugin-class>
element for any alert sender plug-in to hook into the alert mechanism in JBoss ON.
2.2.1.2. Control Operations
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>
element, which is a child to the <plugin-component>
element. Controls are optional, so you don't 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 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>
2.2.1.3. Scheduling Jobs
ScheduledJobInvocationContext
component.
- 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.
Example 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>
<scheduled-jobs>
container entry. Each individual job is within this container, in mapping (<map-property>
) entries.
2.2.1.3.1. States for Jobs
Example 5. Stateless Job Configuration
<c:map-property name="statelessJob1" description="invokes a stateless job class but given a job context"> <c:simple-propertyname="class"
type="string" required="true" readOnly="true" default="MyScheduledJob" summary="true" /> <c:simple-propertyname="methodName"
type="string" required="true" readOnly="true" default="executeWithContext" summary="true" /> </c:map-property>
- 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 typeScheduledJobInvocationContext
. - A setting showing whether the job is enabled.
<simple-property name="enabled" type="boolean" ... />
- 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>
- 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 * * * ?" ... />
(A full description of the cron schedule format is at http://quartz.sourceforge.net/javadoc/org/quartz/CronTrigger.html.) - 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" ... />
- 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" ... />
- 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. - 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 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
scheduleTrigger
setting). Where and how a job is run is determined by two settings: concurrent and clustered.
Note
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
2.2.1.4. Plug-in Configuration (Both Global and Local)
<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 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>
<alert-configuration>
and <simple-property>
item).
Example 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>
Example 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>
/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
git clone http://git.fedorahosted.org/git/rhq/rhq.git
/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
rhq-configuration.xsd
file. This file defines the basic configuration options available to any plug-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.
/modules/enterprise/server/xml-schemas/src/main/resources
directory.
<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
2.2.2.1. Parsing the Plug-in Container Schema Files
- Elements
- Attributes
Note
<xs:element name="alert-plugin">
<alert-plugin> Stuff </alert-plugin>
<xs:attribute name="name">
<alert-plugin name="myAlertPlugin"> Stuff </alert-plugin>
/modules/enterprise/server/xml-schemas/src/main/resources
directory and search for <xs:element name="">
and <xs:attribute name="">
entries.
Note
git clone http://git.fedorahosted.org/git/rhq/rhq.git
2.2.2.2. The rhq-configuration.xsd File
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.
rhq-configuration.xsd
file is in source/modules/core/client-api/src/main/resources
.
Note
git clone http://git.fedorahosted.org/git/rhq/rhq.git
/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
rhq-configuration
schema relate to setting configuration values for a plug-in, like <simple-property>
and <map-property>
.
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). |
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.
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. |
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
rhq-serverplugin.xsd
is the central server-side plug-in schema file.
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).
rhq-serverplugin.xsd
file is in source/modules/enterprise/server/xml-schemas/src/main/resources
.
rhq-serverplugin.xsd
file are listed in Table 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 |
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.
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. |
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
ServerPluginComponent
or ControlFacet
must be available in the JAR file for the plug-ins.
2.3. Anatomy of Alert Sender Server-Side Plug-ins
2.3.1. Default Alert Senders
Alert Method | Description | Plug-in Name |
---|---|---|
Sends emails with the alert information to a user or list of users. | alert-email | |
Roles | Sends an internal message to a JBoss ON user role. | alert-roles |
SNMP | Sends a notification to an SNMP trap. | alert-snmp |
Operations | Initiated a JBoss ON-supported task on a target resource. | alert-operations |
Subject | Sends a notification to a user in JBoss ON. | alert-subject |
2.3.2. Breakdown of a Real Alert Sender Plug-in
- An XML plug-in descriptor that conforms to a given XML schema file (XSD)
- Java files
2.3.2.1. Descriptor
rhq-serverplugin.xml
in the src/main/resources/META-INF/
file for that plug-in.
Note
displayName
flag contains the name to give for the plug-in in the list of installed server-side plug-ins.
<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" >
<serverplugin:help> Used to send notifications to direct email addresses. </serverplugin:help>
Figure 3. Alert Help Text
<!-- startup & tear down listener, + scheduled jobs <serverplugin:plugin-component /> -->
<scheduled-jobs>
element or implement a Java class in a <plugin-component>
element. There's no reason to schedule any jobs with an alert sender since the plug-ins don't perform tasks; they provide methods of sending message from the server when an event is detected.
<!-- Global preferences for all email alerts --> <serverplugin:plugin-configuration> <c:simple-property name="mailserver" displayName="Mail server address" type="longString" description="Address of the mail server to use (if not the default JBoss ON one )" required="false"/> <c:simple-property name="senderEmail" displayName="Email of sender" type="string" description="Email of the account from which alert emails should come from" required="false"/> <c:simple-property name="needsLogin" displayName="Needs credentials?" description="Mark this field if the server needs credentials to send email and give them below" type="boolean" default="false"/> <c:simple-property name="user" type="string" required="false"/> <c:simple-property name="password" type="password" required="false"/> </serverplugin:plugin-configuration>
<short-name>
element is required for every alert sender plug-in. This gives the name that is used for the alert sender type in the notification area of the alert definition.
<!-- How does this sender show up in drop downs etc --> <short-name>Email</short-name>
<short-name>
value is used in drop-down menus and other user-oriented areas, this value is much more human-friendly than the displayName value.
org.rhq.enterprise.server.plugins.
pluginName, taken from the package
element in the <plugin>
element of the descriptor. For the alert-email plug-in, the full package name is org.rhq.enterprise.server.plugins.alertEmail
, pointing to the EmailSender.java
class.
<!-- Class that does the actual sending --> <plugin-class>EmailSender</plugin-class>
<alert-configuration>
entry provides information that is configured individually, for every notification instance which uses that alert sender type. For alert-email
, this is a field which allows a list of email addresses that will receive the emailed notifications.
<!-- What can a user configure when defining an alert --> <alert-configuration> <c:simple-property name="emailAddress" displayName="Receiver Email Address(es)" type="longString" description="Email addresses (separated by comma) used for notifications."/> </alert-configuration>
2.3.2.2. Java Resource
package org.rhq.enterprise.server.plugins.alertEmail; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.rhq.core.domain.alert.Alert; import org.rhq.core.domain.alert.notification.SenderResult; import org.rhq.enterprise.server.plugin.pc.alert.AlertSender; import org.rhq.enterprise.server.util.LookupUtil;
public class EmailSender extends AlertSender { @Override public SenderResult send(Alert alert) { String emailAddressString = alertParameters.getSimpleValue("emailAddress", null); if (emailAddressString == null) { return SenderResult.getSimpleFailure("No email address given"); }
List<String> emails = AlertSender.unfence(emailAddressString, String.class, ","); try { Set<String> uniqueEmails = new HashSet<String>(emails); Collection<String> badEmails = LookupUtil.getAlertManager() .sendAlertNotificationEmails(alert, uniqueEmails); List<String> goodEmails = new ArrayList<String>(uniqueEmails); goodEmails.removeAll(badEmails); SenderResult result = new SenderResult(); result.setSummary("Target addresses were: " + uniqueEmails); if (goodEmails.size() > 0) { result.addSuccessMessage("Successfully sent to: " + goodEmails); } if (badEmails.size() > 0) { result.addFailureMessage("Failed to send to: " + badEmails); } return result; } catch (Throwable t) { return SenderResult.getSimpleFailure("Error sending email notifications to " + emails + ", cause: " + t.getMessage()); } } @Override public String previewConfiguration() { String emailAddressString = alertParameters.getSimpleValue("emailAddress", null); if (emailAddressString == null || emailAddressString.trim().length() == 0) { return "<empty>"; } return emailAddressString; } }
catch (Exception e) { log.warn("Sending of email failed: " + e); return SenderResult.getSimpleFailure("Sending failed :" + e.getMessage()); } return SenderResult.getSimpleSuccess("Send notification to " + txt + ", msg-id: " + status.getId()); } }
2.3.2.3. Schema Elements
rhq-configuration.xsd
, which is used by all JBoss ON plug-insrhq-serverplugin.xsd
, which is used by all server-side plug-insrhq-serverplugin-alert.xsd
, which is used by alert plug-ins
rhq-serverplugin-alert.xsd
file is required for any alert sender plug-in. While additional schema files can be added to contain other elements, the alert schema already contains several very useful schema elements for the alert sender plug-ins.
Schema Element | Description | Parent Tag |
---|---|---|
alert-plugin | The root element for a single alert plug-in definition. | None. |
short-name | The display name for the plug-in, which is used in the UI. | alert-plugin |
plugin-class | The class which implements the plug-in's functionality. | alert-plugin |
alert-configuration | A (default) configuration element to display in the UI when the alert instance is configured. This includes general data like a username, password, URL, server name, or port. | alert-plugin |