Using Merlin

Casting Context to a Custom Interface

This tutorial describes how Merlin provides support for the safe casting of a supplied context instance to a domain specific context interface.

Resources supporting this tutorial are contained in the tutorials/casting package.

Requirements

While the context interface provides the mechanisms to access any object type, it is sometimes convenient to declare a domain specific interface and context implementation. This enables client code to take advantage of convenience accessors, resulting in code less cluttered with casting and context entry key references.

For example, the following code fragment demonstrates a type safe casting of a supplied context value by the component to domain specific context interface.

   /**
    * Contextualization of the component using a context
    * class that implements a domain specific context interface.
    */
    public void contextualize( Context context )
      throws ContextException
    {
        DemoContext c = (DemoContext) context;
        getLogger().info( "name: " + c.getName() );
        getLogger().info( "partition: " + c.getPartition() );
        getLogger().info( "home: " + c.getHomeDirectory() );
        getLogger().info( "temp: " + c.getWorkingDirectory() );
    }

Sample Code

The following code is an example of an extended context interface.

package tutorial;

import java.io.File;

import org.apache.avalon.framework.context.Context;

/**
 * An example of an convinience interface that extends the 
 * standard Avalon Context interface.
 */
public interface DemoContext extends Context
{

   /**
    * Return the component name.
    * @return the component name
    */
    String getName();

   /**
    * Return the name of the partition assigned to the component.
    * @return the partition name
    */
    String getPartition();

   /**
    * Return the home directory.
    * @return the directory
    */
    File getHomeDirectory();

   /**
    * Return the temporary working directory.
    * @return the directory
    */
    File getWorkingDirectory();
}

The following source is the implementation of the domain specific context interface. The implementation class must include a constructor that takes a base context as single argument. The supplied context context entries requested by the component type and populated in accordance with the associated context directives.

package tutorial;

import java.io.File;

import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.DefaultContext;
import org.apache.avalon.framework.context.ContextException;


/**
 * A demonstration class that that we will instantiate via 
 * context directives within the component declaration.
 */
public class DemoContextProvider extends DefaultContext implements DemoContext
{

   /**
    * A custom context type implementation must provide
    * the following constructor.
    * @param entries a map of context entries
    */
    public DemoContextProvider( Context context )
    {
        super( context );
    }
 
   /**
    * Return the component name.
    * @return the component name
    */
    public String getName()
    {
        try
        {
            return (String) super.get( "urn:avalon:name" );
        }
        catch( ContextException ce )
        {
            // should not happen 
            throw new RuntimeException( ce.toString() );
        }
    }

   /**
    * Return the name of the partition assigned to the component.
    * @return the partition name
    */
    public String getPartition()
    {
        try
        {
            return (String) super.get( "urn:avalon:partition" );
        }
        catch( ContextException ce )
        {
            // should not happen 
            throw new RuntimeException( ce.toString() );
        }
    }

   /**
    * Return the home directory.
    * @return the home directory
    */
    public File getHomeDirectory()
    {
        try
        {
            return (File) super.get( "urn:avalon:home" );
        }
        catch( ContextException ce )
        {
            // should not happen 
            throw new RuntimeException( ce.toString() );
        }
    }


   /**
    * Return the temporary working directory.
    * @return the temp directory
    */
    public File getWorkingDirectory()
    {
        try
        {
            return (File) super.get( "urn:avalon:temp" );
        }
        catch( ContextException ce )
        {
            // should not happen 
            throw new RuntimeException( ce.toString() );
        }
    }
}

Declaring the Context Interface

To be supplied with a domain specific context to which the component can safely cast, we need to declare this dependency within the component xinfo descriptor.

<type>
  <info>
    <name>demo</name>
    <version>1.0.0</version>
    <lifestyle>singleton</lifestyle>
    <collection>hard</collection>
  </info>
  <context type="tutorial.DemoContext">
    <entry key="urn:avalon:name" />
    <entry key="urn:avalon:partition" />
    <entry key="urn:avalon:home" type="java.io.File" />
    <entry key="urn:avalon:temp" type="java.io.File" />
  </context>
</type>

Secondly, we need to provide corresponding meta-data to Merlin describing the implementation class that it can use to construct the context instance. The following changes to the block.xml description include the class attribute on the context directive. The class attribute tells Merlin to use the named class as the context implementation.

<container name="tutorial">
   <component name="hello" class="tutorial.HelloComponent" activation="startup">
     <context class="tutorial.DemoContextProvider"/>
   </component>
</container>

Executing the Example

Build and run the tutorial.

$ maven
$ merlin build\classes

In the logging output we see the standard context values accessed via the domain specific context interface.

[INFO   ] (tutorial.hello): name: hello
[INFO   ] (tutorial.hello): partition: /tutorial/hello
[INFO   ] (tutorial.hello): home: F:\tutorial\005\working\home\tutorial\hello
[INFO   ] (tutorial.hello): temp: F:\tutorial\005\working\temp\tutorial\hello

Next Steps

The advanced tutorial provides information about the creation of a custom contextualization strategies . Alternatively, you can move onto the subject of service publication .