Provides the framework/template for definining factories to be used when classes are presented as the context in which the factory is to be used.

This family of classes exemplifies the Design Patterns concept of the Factory Method, "provide an interface for creating an object, but let subclasses decide which class to instantiate." The important difference between this definition and the factory context package is that a class context dictates the factory to instantiate.

Definitions/Concepts

To exploit this package one should define a contract (interface)/implementation, factory interface/implementation, and factory manager:

Please note: org.jplate.factory.FactoryIfc and org.jplate.factory.FactoryMgrIfc are simply marker interfaces. Although they contain no methods, it provides a trivial contract ensuring factories are used.

In summary: to retrieve a factory, one should use a factory manager and present the factory manager with a class when requesting a factory interface.

Please note: FactoryContext uses an XML file containing class names that map to factory class names. Also definable is a default factory - which is shorthand for "if the class provided is not defined, return the default factory." Please scroll to the end to see the XML file structure.

All of this is extremely powerful. By utilizing this functionality as a template for factories, one can dictate at runtime, what implementation of a factory should be returned to any class. If one utilizes the factory paradigm then it is possible to do things like enable tracing for a given type based upon the class requesting a factory.

It is encouraged that all factory manager/factory interface/factory implementations use the factory context package to simplify the aforementioned fucntionality.

Examples

The following is a simplified example of how to retrieve a factory based upon a some object's getClass()
//
// Assume factoryMgr has been assigned some FactoryMgrIfc...
//
FactoryContextIfc factoryContext = FactoryContext.getSingleton ();

FactoryIfc factory = 
  factoryContext.getFactoryContext ( factoryMgr, getClass () );

//
// Use factory to create objects...
//
Ideally, the above functionality will be wrapped in actual implementations. For instance, assume one works with Foo's and wants to support factory contexts to gain robust functionality:

//
// The foo interface...albeit trivial...
//
public interface FooIfc
{
    public void setX ( int x );
    public int getX ();
}

//
// The foo implementation.  Notice it is package protected and should be created
// using a factory.
//
final class Foo implements FooIfc
{
    private int _x;

    Foo ()
    {
    }

    public void setX ( final int x )
    {
        _x = x;
    }
    
    public int getX ()
    {
        return _x;
    }
}

//
// This is the factory definition to create Foo's...
//
public interface FooFactoryIfc extends org.jplate.factory.FactoryIfc
{
    public FooIfc createFoo ();
}

//
// The foo factory implementation.
//
public final class FooFactory implements FooFactoryIfc
{
    public FooFactory ()
    {
    }

    public FooIfc createFoo ()
    {
        return new Foo ();
    }
}

//
// This is the foo factory manager who manages an implementation of the foo
// factory interface.
//
public class FooFactoryMgr implements org.jplate.factory.FactoryMgrIfc
{
    private final FooFactoryIfc _defaultFactory;

    public FooFactoryMgr ()
    {
        final org.jplate.util.factorycontext.FactoryContext factoryContext =
            org.jplate.util.factorycontext.FactoryContext.getSingleton ();

        _defaultFactory =
            ( FooFactoryIfc ) factoryContext.getDefaultFactory ( this );
    }

    public FooFactoryIfc getDefaultFactory ()
    {
        return _defaultFactory;
    }

    public FooFactoryIfc getFactory ( final Class classContext )
    {
        final org.jplate.util.factorycontext.FactoryContext factoryContext =
            org.jplate.util.factorycontext.FactoryContext.getSingleton ();

        FooFactoryIfc factory =
            ( FooFactoryIfc )
                factoryContext.getFactoryForContext ( this, classContext );

        return factory != null ? factory : _defaultFactory;
    }
}
Consider the above a template to structuring code using the factory context family of classes. This may not appear overly powerful, but consider the situation where it is now desirable to add tracing capabilities to foo's. Of course it is possible to add checks to Foo.java to see if tracing is enabled and if so trace, but that detracts from Foo's initial requirements.

The following illustrates how tracing can be added for Foo.java without changing the code. Please note that this is an example of the Decorator Pattern.

//
// This class acts as a Decorator for a FooIfc adding System.out functionality
//
final class TraceableFoo implements FooIfc
{
    final FooIfc _foo;

    private TraceableFoo ()
    {
    }

    TraceableFoo ( final FooIfc foo )
    {
        _foo = foo;
    }

    public void setX ( final int x )
    {
        System.out.println ( "Setting x = <" + x + ">" );
        _foo.setX ( x );
    }

    public int getX ()
    {
        final int x = _foo.getX ();

        System.out.println ( "Returning x = <" + x + ">" );

        return retVal;
    }
}

//
// The traceable foo factory implementation.
//
public final class TraceableFooFactory implements FooFactoryIfc
{
    //
    // We need to create some kind of Foo.  Since any class can have
    // a foo factory defined for it, it is reasonable that one was set
    // for self.
    //
    private final FooFactoryIfc _myFooFactory;

    public TraceableFooFactory ()
    {
        final FooFactoryMgr fooFactoryMgr = new FooFactoryMgr ();

        _myFooFactory = fooFactoryMgr.getFactory ( getClass () );
    }

    public FooIfc createFoo ()
    {
        return new TraceableFoo ( _myFooFactory.createFoo () );
    }
}
As can be seen above, it is now a simple matter to enable tracing for any foo. The above could also have been written as:
//
// This class acts as a Decorator for a FooIfc adding System.out functionality
//
final class TraceableFoo implements FooIfc
{
    final FooIfc _foo;

    private TraceableFoo ()
    {
        //
        // We need to create some kind of Foo.  Since any class can have
        // a foo factory defined for it, it is reasonable that one was set
        // for self.
        //
        final FooFactoryMgr fooFactoryMgr = new FooFactoryMgr ();

        final FooFactoryIfc myFooFactory =
            fooFactoryMgr.getFactory ( getClass () );

        _foo = myFooFactory.createFoo ();
    }

    public void setX ( final int x )
    {
        System.out.println ( "Setting x = <" + x + ">" );
        _foo.setX ( x );
    }

    public int getX ()
    {
        final int x = _foo.getX ();

        System.out.println ( "Returning x = <" + x + ">" );

        return retVal;
    }
}

//
// The traceable foo factory implementation.
//
public final class TraceableFooFactory implements FooFactoryIfc
{
    public TraceableFooFactory ()
    {
    }

    public FooIfc createFoo ()
    {
        return new TraceableFoo ();
    }
}
Since the factory context family of classes is used above, it is now trivial to decide which foo factory should be returned from the foo factory manager based upon a class. For instance, one can enable foo tracing if a Bar class is using foo's. Or, one could enable tracing by default and enable standard foo functionality only for Bar classes.

The XML File

FactoryContext defines classes using the org.jplate.util.propertymgr family of classes. As such, the XML file structure is the same, but its content is pertenant to org.jplate.factory.FactoryMgr's and org.jplate.factory.FactoryIfc's. The following uses some pseudonames to illustrate:

<?xml version="1.0"?>
<!DOCTYPE factory-context SYSTEM "org.jplate.util.factorycontext.FactoryContext.dtd">

<factory-context>
    <factory-mgr class="factory-mgr-class-name">
        <context class="class-context">factory-class-name>/context>
        
        ...

        <default>default-factory-class-name>/default>
    <factory-mgr>

    ...

</factory-context>
Using the above example code, the following illustrates how to define foo factories in terms of a Bar:
<?xml version="1.0"?>
<!DOCTYPE factory-context SYSTEM "org.jplate.util.factorycontext.FactoryContext.dtd">

<factory-context>
    <factory-mgr class="FooFactoryMgr">
        <context class="Bar">TraceableFooFactory>/context>

        <default>FooFactory>/default>
    <factory-mgr>
</factory-context>
Please note: The above examples do not use packages. However, in order to work properly one must use fully qualified class names if the classes used belong to packages! This is no different than attempting to perform a Class.forName ( ... ).newInstance ()

You may define as many classes/factories as needed in the XML file...

@see org.jplate.factory @see org.jplate.util.propertymgr