JBoss Community Archive (Read Only)

RHQ 4.9

Plugin Dependencies and Class Loaders

This affects AMPS-Plugin Extensions. That page will need to be changed to reflect the new features that will be implemented based on the information you see on this page.

http://svn.rhq-project.org/repos/rhq/trunk/etc/classloaders-test/ has maven modules that builds plugins along with some dependency jars (dummy-1.0.jar, dummy-2.0.jar and dummy-3.0.jar) that you can use to test this stuff.

Classloading OpenOffice Document that shows some diagrams illustrating some use-cases and patterns that help me better visualize the classloaders.

Suppose I am writing plugin "Z" - there are plugins A, B, C and D that may or may not be deployed. Here's Z's descriptor:

<plugin name="Z">

   <depends plugin="A" />

   <server name="Z1.server" classLoader="shared|instance">
      <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="shared|instance">
   </server>
</plugin>

This means that if I deploy Z, then:

Resource classLoader

Parent classLoader

Classloader Description

shared

shared

Both resource and parent are willing to share their classloader. If we reached the top of the resource hierarchy (i.e. the parent is the platform resource), our resource's classloader needs only be its own plugin classloader. If we are not at the top, the resource is running inside its parent resource and thus needs to have that parent resource's classloader, but it also needs to have its own classes from its own plugin. Therefore, in both cases, the resource gets assigned its own plugin classloader. This means that its plugin classloader must also have the parent plugin classloader as its parent. (e.g. RHQ-Server plugin resource runs inside JBossAS server)

instance

shared

Resource wants its own classloader because it needs to provide additional jars in order to connect properly to the managed resource; this is so, even though the parent is willing to share its classloader. If we reached the top of the resource hierarchy, our resource's new classloader needs to follow up its plugin classloader hierachy. If we are not at the top, the resource is running inside its parent resource and thus needs to have that parent resource's classloader. (e.g. JBossAS 5 server)

shared

instance

Resource is willing to share its own classloader, but the parent has created its own instance. So, even though this resource says it can be shared, it really needs to have its own instance because the parent has its own instance. Therefore, the resource has its own instance of a classloader whose parent classloader is that of its parent resource (e.g. Hibernate running in JBossAS).

instance

instance

Same as (shared,instance), the resource has its own instance of a classloader whose parent CL is that of the classloader of its parent resource.

Note that if a child resource and its parent resource are both from the same plugin, the child will always use the parent's classloader no matter what.

Implementation Notes

  • Source is in SVN branches:

  • org.rhq.core.pc.plugin.ClassLoaderManager.obtainResourceClassLoader implements the shared,instance table above

  • Having a "depends" tag implicitly means the depending plugin requires that the dependant plugin exists. So if plugin A "depends" on plugin B, having plugin B is required (it is not optional). To deploy plugin A you must also deploy plugin B.

  • Using the Extension Model (sourcePlugin attribute on server/service tags) or the Injection Model (using runs-inside element) implicitly means the depending plugin optionally wants that dependent plugin to exist, but it doesn't have to. So if plugin A defines a type that has "sourcePlugin" attributes or has "runs-side" elements that reference plugin B, then plugin B may or may not be deployed with plugin A, it is optional.

  • Any types that rely on optional plugins via the Extension model (sourcePlugin attribute) where those optional plugins do not exist, then the types will be ignored and will not exist.

  • Any types that rely on optional plugins via the Injection model (runs-inside element) where those optional plugins do not exist, then the types will exist, but they will not have parent resource types for those parent resource types whose plugins are missing.

  • All plugin classloaders have a root plugin classloader as their parent. This root plugin classloader is a hiding classloader that prohibits the plugins from accessing many classes deployed in the agent's own core classloader. You can define what classes the agent hides from plugins by setting the agent preference "rhq.agent.plugins.root-plugin-classloader-regex". This is one big regular expression that, when it matches a classname, means that class name is to be hidden from plugins. You normally do not have to set this preference, its default is the most appropriate for all plugins.

  • All plugin classloaders are parent-first. Therefore, as soon as one plugin loads a class, all descendants of that classloader will get that version of the class. To be more specific, say there is a plugin "A" and plugin "B". Plugin "A" contains /lib/class1.jar and plugin "B" contains /lib/class2.jar (where class1.jar and class2.jar each have "MyClass.class", but are different versions). Plugin "B" depends on plugin "A". The "MyClass.class" in Plugin "A" will always "win" - the plugin "B" class will never be seen because parent-first semantics say that plugin "A"'s class will load first.

  • If a plugin A <depends> on another plugin B (that is, plugin classloader A has plugin classloader B as its parent classloader), then the plugin classloader B is used as resource A's classloader's parent (as opposed to resource B's classloader). (so far it looks like this is only true for those resource's whose parent resource is a platform - unsure if this is the right thing to do).

Use Cases

These use cases are why we need RHQ-2059:

  • the Agent has a different version of JBoss Remoting than the one that the AS5 plugin requires to connect to AS5 instances. With the current schema, the version from the agent "wins" and the plugin can not connect to the AS

    • SOLUTION: the plugin classloader's root classloader is a hiding classloader and it never sees the remoting library the agent has. The plugin needs to ship with or reference its classloader to its own remoting jar.

  • the JBossAS plugin could e.g. supply a version of commons-foobar-1.0 while another plugin that runs within it (e.g. Jboss cache) could need a non-interface-compatible version commons-foobar-2.0. Here the other plugin needs a child first CL to enable commons-foobar-2.0

    • SOLUTION: the jboss cache plugin needs to define the following in the <server> element for the cache resource: classLoaderScope="child-first".

    • WARNING: CURRENT DESIGN DOESN'T SOLVE THIS ONE

  • the JBossAS plugin connects to different versions of JBossAS for the different JBossAS resources it manages. This could mean different jars per resource are needed to connect to them. This requires each resource to have its own classloader so it can connect using the proper jars for the version of the resource.

    • SOLUTION: the <server> resource needs to specify classLoader="instance" and the server discovery component needs to implement ClassLoaderFacet that provides the plugin container with the URLs to the plugins that need to be added to the resource's classloader.

  • Some companies have "allowed" versions of libraries (commons-foobar-1.0-companyFix) that they are required to use when writing their own plugins, so a agent or as-plugin supplied version of commons-foobar-1.0 can not be used by their policy

    • WARNING: CURRENT DESIGN DOESN'T SOLVE THIS ONE

  • the hiding / child first behavior needs to be multi-level:

    • agent may need version 1.0 of a lib

    • as5 plugin may need version 2.0

    • fooBar plugin running within the as5 plugin needs version 3.0

    • WARNING: CURRENT DESIGN DOESN'T SOLVE THIS ONE

JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-13 08:01:15 UTC, last content change 2013-09-18 19:41:18 UTC.