Skip to content

Plugin Descriptor Schema

opencode-agent[bot] edited this page May 10, 2026 · 1 revision

Plugin Descriptor Schema

XML schema for JNode plugin descriptors defining plugin metadata, extension points, and extensions.

Overview

JNode plugins are declared using XML descriptor files (.xml) located in */descriptors/ directories. Each descriptor follows a DTD (jnode.dtd) that defines the structure for plugin metadata, runtime libraries, extension points, and extensions. The descriptor is parsed at runtime by the plugin framework to instantiate and configure plugins.

Descriptor Structure

The <plugin> Tag

The root element declares a plugin's identity and metadata:

<plugin id="org.jnode.driver" 
        name="JNode Driver Framework"
        version="@VERSION@"
        provider-name="JNode.org"
        license-name="lgpl"
        class="org.jnode.driver.DriverPlugin">

Attributes:

Attribute Description
id Unique identifier (dot-separated, e.g., org.jnode.driver)
name Human-readable display name
version Plugin version ( @VERSION@ placeholder replaced at build time)
provider-name Author or organization name
license-name License identifier (e.g., lgpl, gpl)
class (Optional) Plugin entry point class implementing org.jnode.plugin.Plugin

Runtime Effect: The PluginManager loads the descriptor and creates a PluginDescriptor instance. If a class is specified, the plugin's start() method is called during system startup to initialize the plugin.

The <requires> Tag

Declares plugin dependencies:

<requires>
  <import plugin="org.jnode.work"/>
</requires>

Runtime Effect: The PluginManager resolves dependencies before starting the plugin. Plugins are started in dependency order. Circular dependencies cause startup failure.

The <runtime> Tag

Declares exported libraries and packages:

<runtime>
  <library name="jnode-core.jar">
    <export name="org.jnode.driver.*"/>
    <export name="org.jnode.driver.virtual.*"/>
  </library>
</runtime>

Runtime Effect: The PluginClassLoader uses these exports to resolve classes from other plugins. The library name maps to a JAR file in the plugin's classpath. The export patterns define which packages are visible to dependent plugins.

Extension Points

The <extension-point> Tag

Declares a well-known service interface that other plugins can extend:

<extension-point id="finders" name="System device finders"/>
<extension-point id="mappers" name="Device to Driver mappers"/>

Attributes:

Attribute Description
id Simple identifier (no periods) unique within the plugin
name Human-readable name

Unique Identifier: The full extension point ID is plugin-id.extension-point-id (e.g., org.jnode.driver.finders).

Runtime Effect: The declaring plugin's ExtensionPoint object is registered with the PluginRegistry. Other plugins can query PluginRegistry.getExtensionPoints() to discover available extension points. The declaring plugin typically listens for extensions via ExtensionPoint.addListener().

Extensions

The <extension> Tag

Implements or contributes to an extension point:

<extension point="org.jnode.driver.finders">
  <class name="org.jnode.driver.net.NetworkDeviceFinder"/>
</extension>

<extension point="org.jnode.shell.aliases">
  <alias name="console" class="org.jnode.shell.command.driver.console.ConsoleCommand"/>
  <alias name="clear" class="org.jnode.shell.command.driver.console.ClearConsoleCommand"/>
</extension>

Attributes:

Attribute Description
point The full extension point ID to contribute to

Child Elements: Custom child elements (e.g., <alias>, <class>, <syntax>, <permission>) are parsed into ConfigurationElement objects.

Runtime Effect:

  1. The PluginRegistry associates the extension with the target ExtensionPoint
  2. The declaring plugin retrieves extensions via ExtensionPoint.getExtensions()
  3. Each extension provides ConfigurationElement[] from Extension.getConfigurationElements()
  4. The host plugin instantiates the contributed classes using the configuration data

Security Permissions

Extensions to org.jnode.security.permissions declare runtime permissions:

<extension point="org.jnode.security.permissions">
  <permission class="java.io.FilePermission" name="<<ALL FILES>>" actions="read,write"/>
  <permission class="java.net.SocketPermission" name="*" actions="resolve,listen,connect"/>
</extension>

Runtime Effect: The PluginSecurityManager enforces these permissions when plugin code attempts privileged operations.

Key Classes

Class Purpose
PluginDescriptor Interface representing parsed plugin metadata
ExtensionPoint Interface for declaring plugin extension points
Extension Interface for contributed extensions
ConfigurationElement Accessor for extension sub-elements and attributes
PluginManager Manages plugin lifecycle and startup order
PluginRegistry Central registry of all plugins and extension points
PluginClassLoader ClassLoader enforcing export/import visibility

How Extensions Are Processed

// Host plugin retrieves extensions
ExtensionPoint ep = registry.getExtensionPoint("org.jnode.driver.finders");
for (Extension ext : ep.getExtensions()) {
    for (ConfigurationElement elem : ext.getConfigurationElements()) {
        String className = elem.getAttribute("class");
        Class<?> clazz = elem.loadClass(className);
        // Instantiate and register the contribution
    }
}

Example: Shell Aliases

<extension point="org.jnode.shell.aliases">
  <alias name="console" class="org.jnode.shell.command.driver.console.ConsoleCommand"/>
  <alias name="clear" class="org.jnode.shell.command.driver.console.ClearConsoleCommand"/>
</extension>

The shell plugin queries org.jnode.shell.aliases, reads the <alias> elements, and registers each command name in its command registry.

Gotchas

  • Version Placeholders: @VERSION@ is replaced during the build by build.xml using the Ant replace task.
  • Extension Point IDs: Must be unique within a plugin (no periods in the simple ID).
  • Lazy Loading: Plugins are only loaded when explicitly started; descriptors are parsed but classes are not loaded until needed.
  • DTD Location: The DTD is referenced as jnode.dtd but is embedded in the parser implementation, not a separate file.

Related Pages

Clone this wiki locally