DPML
Building on the Sholders of Giants
HomeUtilitiesStationMetro
Building on the Sholders of Giants
Tutorial Objective

This tutorial aims to demonstrate the reuse of existing component definitions. The demonstration uses three projects:

  • a component that defines a minamalistic clock
  • a component that extends the clock defintion with overriding context data declared in the component directive
  • a component that extends the clock both in terms of classpath and context arguments

In addition to the techniques uses to create a component defintion by extension, the tutorial also summarizes the impact of these changes on the overall classloader heirachy established by the Metro runtime.

Project 1: The SimpleClock

Our minamalistic clock is defined as a component with a context format argument K:mm a, z. The format argument simply determines the format that the clock will use when listing the current time.

<index .... >

  ...
  
  <project name="acme-simple-clock" basedir="customize/clock">
    <info title="Simple Clock"/>
    <types>
      <type id="jar"/>
      <component xmlns="dpml:metro" alias="true"
           type="org.acme.clock.SimpleClock" name="clock">
        <context>
          <entry key="format" value="K:mm a, z"/>
        </context>
      </component>
    </types>
    <dependencies>
      <test>
        <include ref="ant/ant-junit"/>
        <include ref="dpml/transit/dpml-transit-main"/>
      </test>
    </dependencies>
  </project>
  
  ...
  
</index>

Based on the above defintion Metro will construct a single classloader containing the dpmlx/tutorials/components/acme-simple-clock#SNAPSHOT jar file as a child of the Metro SPI.

Classloader chain for the clock component.

|-----------------------------|
| Classloader (PUBLIC)        |
| Metro Runtime               |
|-----------------------------|
              ^
              |
|-----------------------------|
| Classloader (PROTECTED)     |
| Metro Runtime               |
|-----------------------------|
              ^
              |
|-----------------------------|
| Classloader (PRIVATE)       |
| /clock                      |
|-----------------------------|
Project 2: Overriding the component ..

Our second project is an example of a component solution based on our first project - however, we change the data format context argument (but reference the original component defintion under the uri attribute). Secondly, we have overriden the context format argument with a new value. Any context argument not declared in our new defintion will be based on arguments declared in the super-component.

<index .... >

  ...
  
  <project name="acme-simple-clock" basedir="customize/extension">
    <info title="Cusomized Clock"/>
    <types>
      <component xmlns="dpml:metro" 
          uri="link:part:dpmlx/tutorials/components/acme-simple-clock" 
           name="clock">
        <context>
          <entry key="format" value="K:mm a, z"/>
        </context>
      </component>
    </types>
    <dependencies>
      <test>
        <include ref="ant/ant-junit"/>
        <include ref="dpml/transit/dpml-transit-main"/>
      </test>
    </dependencies>
  </project>
  
  ...
  
</index>

The classloader chain constructed in the second example is basically the same as before except that the final component classloader is established relative to the classloader definition declared in the super-component.

|-----------------------------|
| Classloader (PUBLIC)        |
| Metro Runtime               |
|-----------------------------|
              ^
              |
|-----------------------------|
| Classloader (PROTECTED)     |
| Metro Runtime               |
|-----------------------------|
              ^
              |
|-----------------------------|
| Classloader (PRIVATE)       |
| /clock (super)              |
|-----------------------------|
Project 3: Extending the component ..

Our third project is an example of a component solution where we customize the original component defintion with a new context value, but the context value is resolved from a class local to the customized component. In this case Metro has to handle the establishment of a classloader for the super-component and a subsidiary classloader for the cusomization content.

<index .... >

  ...
  
  <project name="acme-simple-clock" basedir="customize/custom">
    <info title="Simple Clock"/>
    <types>
      <type id="jar"/>
      <component xmlns="dpml:metro" 
           uri="resource:part:dpmlx/tutorials/components/acme-simple-clock"
           name="clock">
        <context>
          <entry key="format" class="org.acme.extra.Customizer" method="getCustomFormat"/>
        </context>
      </component>
    </types>
    <dependencies>
      <test>
        <include ref="ant/ant-junit"/>
        <include ref="dpml/transit/dpml-transit-main"/>
      </test>
    </dependencies>
  </project>
  
  ...
  
</index>

The following classloader chain is similar to the above (the super-component classloader hanging of the Metro SPI) together with an additional classloader created as a child of the super-component classloader holding the classes used in the new component definition.

|-----------------------------|
| Classloader (PUBLIC)        |
| Metro Runtime               |
|-----------------------------|
              ^
              |
|-----------------------------|
| Classloader (PROTECTED)     |
| Metro Runtime               |
|-----------------------------|
              ^
              |
|-----------------------------|
| Classloader (PRIVATE)       |
| /clock (super)              |
|-----------------------------|
              ^
              |
|-----------------------------|
| Classloader (PRIVATE)       |
| /clock                      |
|-----------------------------|
Summary

In this tutorial we have demonstrated the usage of the uri attribute in a component defintion as a means to declare a super-component. In each case we used a different date fomat value generating the following output values:

base[junit] 11:33 PM, CST
customizer[junit] 11:33 PM
extended[junit] 11:33

In real-world applications component context models can become rather complex and the ability to define a generic solution component fully populated with an appropriate deployment solution is attractive. Adding the ability to further customize default solutions further simplifies the overall development task and encorages reuse of existing component definitions.