RHQ, the common services project for infrastructure management

  Dashboard > RHQ-Project > ... > Writing Custom Plugins > AMPS-Plugin Extensions
  RHQ-Project Log In | Sign Up   View a printable version of the current page.  
  AMPS-Plugin Extensions
Added by John Mazzitelli , last edited by John Mazzitelli on Feb 14, 2008
Labels: 
(None)

Plugin Extensions

RHQ plugins have the ability for one plugin to extend or use another plugin. Examples to illustrate why you would need this type of functionality is: "Tomcat embedded in a JBossAS server" and "Hibernate running in some JMX-enabled container".

In this section, we'll be using the following terms:

  • a "parent plugin" is one that has another plugin depending on it.
  • a "child plugin" is a plugin that depends on one or more other plugins
  • a "dependent plugin" is another name for a "child plugin"
  • a "plugin root level resource type" is a resource type defined as a direct child element under the <plugin> element in a plugin descriptor.
  • a "parent resource type" is a resource type that has one or more child resource types associated with it
  • a "child resource type" is a resource type that has a parent resource type (plugin root level resource types normally do not have a parent, unless it is using the Injection extension model as described below)

There are two main extension models:

  1. Injection: A plugin root level resource type runs inside one or more resource types as defined in one or more parent plugins
    • Think of the dependent plugin being able to say "I run inside another plugin".
    • The dependent plugin defines a new child resource type under an existing parent resource type (which is defined in the parent plugin).
    • The dependent plugin defines a child resource type that is injected into another plugin's resource type hierarchy. It is injected as a child type to the parent plugin's resource type (called the "parent resource type").
    • The child resource type knows about its parent resource types, but the parents do not know about the child (this is because knowledge of plugins flow down, not up - that is to say, a parent plugin's type information is known to its child plugin, but a parent plugin does not know anything about the child plugins that depend on it).
    • An example that uses the Injection extension model is "Hibernate inside JBossAS and/or Tomcat"
    • This extension model allows a resource type to have multiple parent resource types - e.g. a Hibernate service type has JBossAS server and Tomcat server as a parent
  2. Embedded: A plugin embeds another plugin's resource type
    • Think of the dependent plugin being able to say "I know something else runs inside of me".
    • The dependent plugin defines a new parent resource type that will contain an existing child resource type (which is defined in the parent plugin)
    • Note the reversal of parent-child relationships - the child plugin defines a parent resource type - the parent plugin defines the existing child resource type.
    • The parent resource type knows about its child resource type, but the child does not know about the parent (again, this is because knowledge of plugins flow down, not up - that is to say, the child plugin will know about the parent plugins it depends on, but a parent plugin does not know anything about the child plugins that depend on it).
    • The dependent plugin pulls in a copy of the parent plugin's resource type
    • An example that uses the Embedded extension model is "Tomcat inside JBossAS"
    • The parent plugin's resource type embedded as a child by the child plugin will be a copied version of a parent plugin's resource type and thus is a completely separate type - for example, the "Embedded Tomcat Server" has JBossAS Server as its parent - "Embedded Tomcat Server" is a copy of the "Tomcat Server" type defined in the parent Tomcat plugin and is different than the "Tomcat Server" type (which has no parent type).

Both extension models are mutually exclusive - a plugin can be extended using one or the other, but not both. For example, a plugin A resource type cannot be a child to a plugin B resource type IF another plugin A resource type is a parent to a plugin B resource type. A more concrete example: Tomcat cannot be run inside of a JBossAS server while at the same time have a JBossAS server run inside of Tomcat. However, a plugin can be extended in different ways by different plugins. For example, if a plugin A resource type is a child to a plugin B resource type, it is OK if a plugin A resource type is a parent to a plugin C resource type. A more concrete example: Tomcat runs inside of a JBossAS server (child/parent) while at the same time Tomcat can run a Hibernate service inside of it (parent/child).

Notice that metadata and class definitions flow in only one direction - from a parent plugin to its dependent plugin. Information cannot flow in the other direction. The JBossAS plugin can access the Tomcat plugin metadata and classes (because the JBossAS extends the Tomcat plugin using the Embedded model), but the Tomcat plugin cannot access the JBossAS metadata or classes.

Classloader Issues / Class Sharing Between Plugins

GHINKLE
PLEASE REVIEW AND MODIFY AS APPROPRIATE
  • All plugins will have their own classloader while running in the plugin container.
  • All plugins are isolated from one another, unless extended using the <depends> useClasses attribute set to true.
  • If a plugin is a direct dependent on a plugin, and that dependency is defined with <depends useClasses="true">, then that parent plugin jar's classes (and all of its parent jars) will be available to the dependent plugin's classloader.
  • A dependency graph is built that determines the order in which plugins are deployed. Child plugins are deployed after their parent plugins are deployed. For example, if plugin A depends on plugin B, then plugin B needs to be loaded first, then plugin A. Circular dependencies are not allowed - exceptions will be raised and errors logged if a circular dependency among plugins are found (for example, if Plugin A depends on Plugin B, B depends on C and C depends on A).
  • A plugin can depend on more than one other plugin. All parent plugins will be deployed prior to the child plugin getting deployed.
  • However, you can only use classes from one dependency. That is to say, if you have multiple <depends> defined, only one of them can be defined with useClasses="true". Remember that using classes from one dependency means you also can use classes that that dependency pulls in.

Plugin Descriptor Content That Deals With Plugin Extensions

  • A plugin can depend on other plugins - either through the Injection or Embedded extension model.
  • There is a depends element directly under the <plugin> element that defines one or more parent plugins that the plugin depends on.
  • You can define if you want to pull in classes from one of the dependency jars by specifying the "useClasses" attribute of the <depends> tag. <depends useClasses="true" plugin="A" means the plugin wants to use classes from plugin A. You can only set useClasses to true for one and only one <depends> in a single plugin descriptor.
  • Embedded: A <server> or <service> can be a copy of a source resource type found in another plugin. <server>/<service> has "sourcePlugin" and "sourceType" attributes. The <server>/<service> will be a copy of the source resource type which means it will have the same metadata as the source with the exception that the <server>/<service> can override the discovery and resource classes and will have a potentially different name.
  • Injection: A plugin root level resource type (that is, a direct child of <plugin>) can define the parent resource types that this type can run inside of. In effect, this injects the root level resource type as a child type to another plugin's resource type.
  • You define this directly under the root level type via the <runs-inside> element:
    <runs-inside>
       <parent-resource-type name="Tomcat Server" plugin="Tomcat" />
       <parent-resource-type name="JBoss Server" plugin="JBossAS" />
       <parent-resource-type name="Embedded Tomcat Server" plugin="JBossAS" />
    </runs-inside>

Caveats

  • Embedded: A <server> or <service> with a sourcePlugin/sourceType will take that source definition and duplicate it. This includes all children resources as well. The <server>/<service> can override things like discovery and class but today cannot add/remove/change any other metadata - the source type is copied as-is.
    Do we want it also to add or remove things like configuration, operation and metric metadata? How do you denote that you want to remove one?
  • Injection: A root level <server> or <service> can have a <runs-inside> element.
    Do we also want to allow non-root-level types to accept <runs-inside>?

Discovery

  • The plugin container will invoke discovery components to discover resource types as appropriate.
  • For the Embedded model, the new child type that is copied from the source plugin can have its own discovery component defined by the child plugin - that new component's job is to discover the embedded resource using its own custom mechanism. The plugin container will call that discovery component and it is that component that will build the proper resource details for the discovered resources.
  • For the Injection model, the plugin container will take a parent component, look at all of its child resource types (which can be more than one type) and run a discovery for each child type, injecting that parent component into each child type's discovery method. This is why the Injection model does not give a child plugin its own copies of a parent plugin's classes. This parent component is a component that exists and was created by the parent plugin - the parent component instance is passed to the child plugin's discovery component and thus they must both share class definitions so they can call each other.

RHQ Server Plugin Deployer

  • The plugin deployer running in the RHQ Server is very simple - whatever plugin jar it gets, it reads its descriptor and inserts the metadata into the DB.
  • The plugin deployer never runs the plugins, or even instantiates classes within the plugin jars. It simply reads the plugin jar's XML descriptors, builds the metadata from those descriptors and inserts that metadata into the database.
  • The plugin deployer does, however, ensure that the plugins are deployed in the proper order - that is, parent plugin metadata is read in first, before child metadata. This is to ensure things like the "sourcePlugin" attribute can be validated and "sourceType" types can be found and copied.

Use Cases

GHINKLE
PLEASE LOOK AT THE <depends> TAGS AND MAKE SURE THEY ARE RIGHT AND USE useClasses PROPERLY

This section will illustrate some of the use-cases that drove the design of the Embedded and Injection extension models. Use these as examples for how you can build your own plugin extensions.

JBossAS extends the JMX plugin

The JMX plugin is a generic plugin and can be used by many other plugins. If you have a product that is manageable by JMX, you probably will want to add a dependency on the JMX plugin to pick up all its utilities.

In this example, consider that a JBossAS has a JMX server running inside of it that houses all the JBossAS 4.x services used for manageability.

JMX Plugin Descriptor:

<plugin name="JMX">
   <server="JmxServer" discovery="JmxDiscoveryComponent" class="JmxServerComponent">
   ...
   </server>
</plugin>

JBossAS Plugin Descriptor:

<plugin name="JBossAS">
   <depends plugin="JMX" useClasses="true"/>
   <!-- JBossXXXComponent classes extend the JmxXXXComponent classes -->
   <server name="JBossAS" discovery="JBossDiscoveryComponent" class="JBossServerComponent">
   ...
   </server>
</plugin>

Things to consider:

  • The JBoss plugin now needs the JMX plugin's classes in its classloader (this is the Embedded extension model).
  • The JMX plugin will also autodetect the JBossAS MBeanServer - it will look like a generic MBeanServer though; the JBoss discovery component will be able to take the MBeanServer it finds and build JBoss resources around them.
  • Note that the JBossAS plugin descriptor does not actually define any source types from the JMX plugin. The JBossAS plugin only needs the classes that are in the JMX plugin. However, there is nothing wrong with also having the JBossAS plugin define a child server that provide the raw JMX plugin access to the MBeanServer:
    <plugin name="JBossAS">
       <depends plugin="JMX" />
       <server name="JBossAS" discovery="JBossDiscoveryComponent" class="JBossServerComponent">
          <server name="Embedded MBeanServer" sourcePlugin="JMX" sourceType="JmxServer">
          ...
          </server>
       ...
       </server>
    </plugin>

Standalone Tomcat and Tomcat Embedded In JBossAS

Tomcat can be run either standalone (within its own JVM process) or it can be housed inside of a JBossAS server (that is, embedded inside the JBossAS VM process). We will use the Embedded extension model to define both of these situations:

JMX Plugin Descriptor:

<plugin name="JMX">
   <server="JmxServer" discovery="JmxDiscoveryComponent" class="JmxServerComponent">
   ...
   </server>
</plugin>

Tomcat Plugin Descriptor:

<plugin name="Tomcat">
   <depends plugin="JMX" useClasses="true" />
   <server name="TomcatServer" discovery="TomcatDiscoveryComponent" class="TomcatServerComponent">
   ...
   </server>
</plugin>

JBossAS Plugin Descriptor:

<plugin name="JBossAS">
   <depends plugin="JMX" />
   <depends plugin="Tomcat" useClasses="true" />
   <!-- JBossXXXComponent classes extend the JmxXXXComponent classes -->
   <server name="JBossServer" discovery="JBossDiscoveryComponent" class="JBossServerComponent">
   ...
   </server>

   <!-- effectively duplicates the tomcat plugin's resource type -->
   <!-- JBossTomcatXXXComponent classes extend the TomcatXXXComponent classes -->
   <server name="EmbeddedTomcat" sourcePlugin="Tomcat" sourceType="TomcatServer"
           discovery="JBossTomcatDiscoveryComponent" class="JBossTomcatServerComponent">
   ...
   </server>
</plugin>

Things to consider:

  • Plugins have "multiple dependency" support - a plugin can depend on more than one other plugin
  • <server> has sourcePlugin and sourceType - you must have a <depends> defined with the sourcePlugin and the source plugin must have a type with the same name as the sourceType.
  • We now have two Tomcat discoveries happening, one with TomcatDiscoveryComponent and one with JBossTomcatDiscoveryComponent.
  • The sourcePlugin/sourceType makes a duplicate copy of a resource type and gives it a unique name. During runtime, they are seen as two distinct and different resource types. This is why subCategory exists - to be able to link two or more similar resource types that are otherwise different.

Hibernate Able to Run in Either Tomcat or JBossAS

Hibernate can be deployed/run in either a Tomcat server or JBossAS server. It can also be deployed in a Tomcat server that is embedded in a JBossAS server. We will use the Injection extension model to define both of these situations:

JMX Plugin Descriptor:

<plugin name="JMX">
   <server="JmxServer" discovery="JmxDiscoveryComponent" class="JmxServerComponent">
   ...
   </server>
</plugin>

Tomcat Plugin Descriptor:

<plugin name="Tomcat">
   <depends plugin="JMX" useClasses="true" />
   <server name="TomcatServer" discovery="TomcatDiscoveryComponent" class="TomcatServerComponent">
   ...
   </server>
</plugin>

JBossAS Plugin Descriptor:

<plugin name="JBossAS">
   <depends plugin="JMX" />
   <depends plugin="Tomcat" useClasses="true" />
   <!-- JBossXXXComponent classes extend the JmxXXXComponent classes -->
   <server name="JBossServer" discovery="JBossDiscoveryComponent" class="JBossServerComponent">
   ...
   </server>

   <!-- effectively duplicates the tomcat plugin's resource type -->
   <!-- JBossTomcatXXXComponent classes extend the TomcatXXXComponent classes -->
   <server name="EmbeddedTomcat" sourcePlugin="Tomcat" sourceType="TomcatServer"
           discovery="JBossTomcatDiscoveryComponent" class="JBossTomcatServerComponent">
   ...
   </server>
</plugin>

Hibernate Plugin Descriptor:

<plugin name="Hibernate">
   <depends plugin="JMX" />
   <depends plugin="Tomcat" />
   <depends plugin="JBossAS" useClasses="true" />

   <server name="HibernateSession" discovery="HibernateDiscoverComponent" class="HibernateComponent">
      <runs-inside>
         <parent-resource-type name="TomcatServer" plugin="Tomcat"/>
         <parent-resource-type name="JBossServer" plugin="JBossAS"/>
         <parent-resource-type name="EmbeddedTomcat" plugin="JBossAS"/>
      </runs-inside>
   </server>
</plugin>

Things to consider:

  • Hibernate is injecting its resource type definition as a child to the parent types of TomcatServer, JBossServer and EmbeddedTomcat.
  • Hibernate explicitly depends on the Tomcat and JBossAS plugins. Because it directly depends on the JBossAS plugin, it also implicitly is a dependent of the JMX plugin.

TODO - things to clarify and implement

What happens if we want a resource type to be injected as a child but ALSO have it be a top-level root type? How do you indicate this? The list of parents is empty will mean it is a root type - but as soon as you inject it as a child, you take it out of the root-level space. We need some way of saying "runsInside" something but also "runs outside of everything" too.

The JBossAS has a dependency on the JMX plugin - it is using the Embedded model which means it will have its own copy of the JMX classes. However, the Hibernate plugin depends on the JBossAS plugin using the Injection model - which means it must share classes with the JBossAS plugin. What happens with this indirect relationship with the JMX plugin? How do we define the classloading rules when Plugin A depends on B depends on C when A->B uses Injection and B->C uses Embedded? The relationship between C classes in plugin A is what?

Powered by a free Atlassian Confluence Open Source Project License granted to Hyperic HQ. Evaluate Confluence today.
Powered by Atlassian Confluence 2.7.1, the Enterprise Wiki. Bug/feature request - Atlassian news - Contact administrators