PicoContainer - Configuration

Authors: Paul Hammant

      WARNING! CODE IS OUT OF DATE. NEEDS WORK.      

Overview

Configuration for PicoContainer components requires some explanation. The basic idea is that a component should not be tied to a single configuration design.There are two ways a developer may declare configuration needs for a component. The first is as seperate parameters in the constructor, the second is as a bespoke configuration pseudo-component, also passed in through constructor.

Constructor parameters

Consider a component a that requires configuration :

class Foo {
      public Foo(DependantComp dComp, String fooName, Integer barNumber) {
      }
    }

Clearly the string and the integer are not components. What we need is a way of passing in those parameters at runtime. Possibily interleaved with real components.

MutablePicoContainer pico = new DefaultPicoContainer();
    pico.registerComponent(DefaultDependantComp.class);
    pico.registerComponent(Foo.class);
    pico.addParameterToComponent(Foo.class, String.class, "foo");
    pico.addParameterToComponent(Foo.class, Integer.class, new Integer(33);
    pico.start();

Obviously you'd have some soft coded implementation rather than that hard coded above. We're trying to illustrate the intermingling of components and configuration. Well perhaps we are if you consider the following component :

class Foo {
      public Foo(Wilma wilma, String fooName, FredImpl fred, Integer barNumber) {
      }
    }

    ....

    PicoContainer pico = new HierarchicalPicoContainer.Default();
    pico.registerComponent(Foo.class);
    pico.registerComponent(Wilma.class, WilmaImpl.class);

    pico.registerComponent(FredImpl.class);

    pico.addParameterToComponent(Foo.class, String.class, "foo");
    pico.addParameterToComponent(Foo.class, Integer.class, new Integer(33);
    pico.start();

Pseudo-component

class Foo {
      public Foo(DependantComp dComp, FooConfig fooConfig) {
      }
    }

    interface FooConfig {
      String getFooName();
      int getBarNumber(); // note this is int not Integer (restriction lifted).
    }

Without going into the how, many implementations of the FooConfig are possible.

MutablePicoContainer pico = new DefaultPicoContainer();
    pico.registerComponent(DefaultDependantComp.class);
    pico.registerComponent(Foo.class);
    pico.registerComponent( DefaultFooConfig.class );
    //pico.registerComponent( DefaultFooConfig.class );
    //pico.registerComponent( PropertiesFileFooConfig.class );
    //pico.registerComponent( XmlFileFooConfig.class );
    //pico.registerComponent( ParallelUniverseFooConfig.class );
    //pico.registerComponent( WebPageReadingFooConfig.class );
    //pico.registerComponent( FromTibcoFooConfig.class );
    //pico.registerComponentImplementation ( myAvalonConfigurableForLegacySupportFooConfig );    
    //pico.registerComponentImplementation ( someCarefullyDeserializedFooConfig );    
    pico.start();

Clearly a person needs to write an adaptor, but any adaptor can be written. The developer who uses the component can do anything - they are not forced to fit one configuration design.
Anti-patterns
In non IoC designs, a component may hard code its configuration in one of a number of ways....

True hard coding:

class MyWebServer {
      ServerSocket socket;
      public MyWebServer() {
      }
      public void start() {
        // listen on port 80
        socker = new ServerSocket(80); 
      }
    }

Bound to a specific properties file:

class MyWebServer {
      ServerSocket socket;
      public MyWebServer() {
      }
      public void start() {
        ResourceBundle rb = new ResourceBundle("MyWebServer.properties");
        socker = new ServerSocket(rb.getIntProperty("port.number"); 
      }
    }

There are IoC anti-patterns as the embedor can't choose their own configuration mechanism. An application comprising a number of components may have to include multiple xml and properties files to control the configuration.