The aim of this tutorial is to establish a good understanding of the term "part" and how part management can help you to build flexible and adaptive runtime system by leaveraging Transit's cassloader construction services.
A part
is an resource type that is used to describe
a classloader chain. The part resource is an XML file that
declares the contents of an PUBLIC classloader, PROTECTED classloader,
and an PRIVATE implementation classloader. Each classloader definition is
expressed as a series of jar artifact uris. Transit provides
support for the construction of classloader chains based on the
information contained within the part definition. A chain is
constructed by creating an PUBLIC classloader as child of a supplied
parent classloader, a PROTECTED classloader as a child of the PUBLIC classloader,
and a PRIVATE implementation classloader as a child of the PROTECTED classloader.
In additon to classloader chain information, a part resource can include the declaration of a deployment strategy. The Transit system provides support for 'plugin' strategies that enable declaration of a main class or resource. The combination of classloader chain with a deployment strategy combines to provide a framework for plugable sub-systems deployment.
In practice the creation and maintenance of plugin information is highly error prone due to overall complexity of dependency management. This was one of the driving factors in the development of the Depot build system. Depot was developed from the ground up to provided full transitive dependency management across build, runtime and test scopes. Using the Depot project model the job of creating a plugin definition is reduced down to type production declaration within a Depot project definition.
An example Depot project defintion ...
<?xml version="1.0" encoding="ISO-8859-1"?> <index xmlns="link:xsd:dpml/lang/dpml-module#1.0"> ... <project name="dpml-metro-runtime" basedir="runtime"> <info title="Metro Runtime"> <description> DPML Component management platform runtime container. </description> </info> <types> <type id="jar"/> <part:plugin alias="true" class="net.dpml.metro.runtime.CompositionController"/> </types> <dependencies> <include ref="dpml/util/dpml-logging-api" tag="public"/> <include key="dpml-metro-component" tag="protected"/> <include key="dpml-metro-model" tag="protected"/> </dependencies> <dependencies scope="test"> <include ref="ant/ant-junit"/> </dependencies> </project> ... </index>
The following part description is generated automatically by the Depot build system based on the above project definition based on the following rules:
- The info element is mapped directory to a part info declaration.
- The part:plugin element is mapped to a part deployment strategy definition.
- All runtime dependencies are fully expanded.
<?xml version="1.0"?> <part xmlns="link:xsd:dpml/lang/dpml-part#1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <info title="Metro Runtime"> <description>DPML Component management platform runtime container.</description> </info> <strategy xsi:type="plugin" class="net.dpml.metro.runtime.CompositionController"> <param class="net.dpml.component.InitialContext"/> </strategy> <classpath> <public> <uri>artifact:jar:dpml/util/dpml-logging-api#SNAPSHOT</uri> </public> <protected> <uri>artifact:jar:dpml/transit/dpml-transit-main#SNAPSHOT</uri> <uri>artifact:jar:dpml/metro/dpml-metro-state#SNAPSHOT</uri> <uri>artifact:jar:dpml/metro/dpml-metro-component#SNAPSHOT</uri> <uri>artifact:jar:dpml/metro/dpml-metro-model#SNAPSHOT</uri> </protected> <private> <uri>artifact:jar:dpml/metro/dpml-metro-runtime#SNAPSHOT</uri> </private> </classpath> </part>
Transit provides a number of plugin related services including loading of plugin descriptor, creation of a plugin classloader chain, plugin class establishment, plugin instance establishment, and generic object instantiation utility function. Collectively these methods make the process of sub-systems creation a painless development process.
The following example demonstrates the creation of a plugin sub-system using Transit to establish a client instance.
URI uri = new URI( "artifact:part:dpml/metro/dpml-metro-runtime#1.0.0" ); Part part = Part.load( uri ); Logger logger = getLogger(); Object instance = part.instantiate( new Object[]{ logger } );
The above code is typical in that it covers the following functions:
- Establish the classloader that will serve as the anchor for the classloader chain.
- Create an artifact URI referencing a "plugin" resource.
- Construct any objects that should be supplied as constructor arguments.
- Load the part definition.
- Request part instantiation using supplied constructor arguments.
Within production applications you would typically see a reasonable amount of error handling code wrapping the above code framgment. The error handling code would typically handle validation of the plugin either prior to instantiation or part of a try catch block, type checking, etc.
In the examples presented above we have demonstrated the usage of Depot's project definition as the source of information about project runtime dependencies and deployment information from which a part definition is created and used at runtime within an application. The next tutorial focussed on the underlying resource repositories from which artifact uris are resolved in terms of physical resources.