DPML
Context Driven Development
HomeUtilitiesStationMetroDepotTransit
Working with Context
Tutorial Objective

The purpose of this tutorial is to introduce the Metro Context model and the contract this represents between a container and a component.

Supporting classes:

Demo.java A component implementation incorporating a Context inner interface.
Asserting Operational Requirements

Components are typically established and deployed dynamically by a controlling system. To do this the controlling system needs to know about the operational requirements of the component and delivery mechanism assumed by a component. Within the Metro component model both the declaration of requirement and the delivery mechanism are described using a Context inner interface within a component implementation class.

For example ...

package org.acme;

import java.util.logging.Logger;
import java.util.logging.Level;

public class Demo
{
    public interface Context
    {
        String getActivity();
        String getOwner();
        String getTarget();
        String getColor();
    }
    
    public Demo( final Logger logger, final Context context )
    {
        if( logger.isLoggable( Level.INFO ) )
        {
            final String owner = context.getOwner();
            final String activity = context.getActivity();
            final String target = context.getTarget();
            final String color = context.getColor();
            final String message = 
              activity + " " + owner + "'s " + target + " " + color + ".";
            logger.info( message );
        }
    }
}

The Context interface is a component driven contract. The information disclosed in the interface can be analysed by a container. The container is any system acting in the role of component manager (which could be a dedicated container solution or a simple testcase).

Context Interface Semantics

Looking closer at the Context interface declared by the Demo class we have an inner class declaration:

public interface Context
{
    String getActivity();
    String getOwner();
    String getTarget();
    String getColor();
}

This contract is stating that an implementation of the Context interface must supply values for the features activity, owner, and target, and color - each of which (in this example) are instances of java.lang.String.

Noteable points:

  1. no exceptions in method declaration
  2. dependency type is the method return type (and any return type including primitives, arrays, custom interfaces and classes are valid return type)
  3. the dependency key is based on the method name applying the bean pattern get[key]
  4. defalt values may be declared as a single method argument
  5. if a default value is declared it must be assignable to the method return type
Building the deployment solution

Tje context inner interface is declaring the operation requirements - however, we need to declare somewhere the solution strategy. We do this by updating our component definition to include a <context> block.

The following lines are example of the creation of a component deployment solution (taken from the components/002 project definition). Modifications markup shows changes from our initial component definition.

<index ..... >

  <project name="acme-demo-context" basedir="context">
    <types>
      <type id="jar"/>
      <component xmlns="link:xsd:dpml/lang/dpml-component#1.0" 
         type="org.acme.Demo" 
         name="demo">
        <context>
          <entry key="owner" value="${user.name}"/>
          <entry key="activity" value="Painting"/>
          <entry key="target" value="bike"/>
          <entry key="color" value="silver"/>
        </context>
      </component>
    </types>
    <dependencies>
      <test>
        <include ref="ant/ant-junit"/>
        <include ref="dpml/transit/dpml-transit-main"/>
      </test>
    </dependencies>
  </project>
  
  ...
  
</index>
Testing the component

During execution of the testcases we see the result of logging the a message reflecting configuration and runtime information. In the DemoTestCase the output is shows the result of concatination of values resolved fro the context implementation supplied by the container to the component instance.

test:
    [junit] Executing forked test.
    [junit] Running org.acme.test.DemoTestCase
    [junit] [16245] [INFO   ] (demo): Painting mcconnell's bike silver.
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.89 sec
Summary ...

The container will make best efforts to assemble a viable deployment scenario. If that scenario cannot be established then your component will not be deployed. During deployment the container will evaluate all runtime requirements declaring with a #Context innner interface, build an context implementation fullfilling the contract (and any other regognized contructor arguments) and deploy the component taking into account lifecyle and lifestyle (but more of these subject later in the tutorial).

The next tutorial provides a demonstration of the context contract within which we use primitive and complex types together with examples of optional context entries.