PicoContainer Bsh Configuration

Java Development News:

PicoContainer Bsh Configuration

By Alex Winston

23 Apr 2004 | TheServerSide.com

I have spent quite a bit of time lately exploring various aop, ioc, and mvc frameworks and the one thing that seems to plague them all is the insidious desire to wire everything together with xml. I will not make an argument against xml for configuration, because it is a trite endeavour, and instead attempt to outline the benefits of using a scripting language such as bsh.

fortunately dynaop and picocontainer both provide bsh integration so i will attempt to outline my findings, which will be the foundation for my next article addressing mvc frameworks.

I have found dependency injection and picocontainer in particular quite ingenious, but found hardcoding the wiring of pico components rather undesirable. nanocontainer to the rescue. nanocontainer provides a thin wrapper around bsh which provides the ability to wire components through a bsh script.

before i delve into the specifics of bsh configuration i will outline the obligatory Foo and Bar components that will be used to test the bsh configuration.

public interface Foo {
    public Bar foo();
}

public class FooImpl implements Foo {
    private String foo;
    private Bar bar;

    public FooImpl(Bar bar, String foo) {
        this.foo = foo;
        this.bar = bar;
    }

    public Bar foo() {
        System.out.println(this.foo);
        return this.bar;
    }
}

public interface Bar {
    public void bar();
}

public class BarImpl implements Bar {
    private Foo foo;

    public BarImpl(Foo foo) {
        this.foo = foo;
    }

    public void bar() {
        foo.foo();
        System.out.println("bar");
    }
}

as you will notice i have created a circular dependency between the two components, this is simply to test some of the more advanced features of picocontainer. you will also notice that both Foo, and Bar require components as parameters for each corresponding constructor. the goal is to have picocontainer wire Foo and Bar with components dynamically through the bsh script.

in order to accomplish this some minor setup of picocontainer is involved and i will outline that next.

import java.io.InputStreamReader;
import java.io.Reader;

import org.nanocontainer.script.bsh.BeanShellContainerBuilder;

import org.picocontainer.PicoContainer;
import org.picocontainer.defaults.DefaultPicoContainer;
import org.picocontainer.defaults.ObjectReference;
import org.picocontainer.defaults.SimpleReference;

public class BshNanocontainerTest {
    public static void main(String[] args) throws Exception {
        new BshNanocontainerTest().testBsh();
    }

    void testBsh() throws Exception {
        Reader reader = new InputStreamReader(
            Thread.currentThread().getContextClassLoader().getResource(
                "nanocontainer.bsh").openStream());

        BeanShellContainerBuilder builder = new BeanShellContainerBuilder(
            reader, Thread.currentThread().getContextClassLoader());

        ObjectReference container = new SimpleReference();
        container.set(new DefaultPicoContainer());

        builder.buildContainer(container, new SimpleReference(),
            this.toString());

        PicoContainer pico = (PicoContainer) container.get();
        //System.out.println(pico.getComponentInstance("bar"));

        //System.out.println(pico.getComponentInstance("foo"));
        Foo foo = (Foo) pico.getComponentInstance("foo");
        foo.foo().bar();

        foo = (Foo) pico.getComponentInstance(Foo.class);
        foo.foo().bar();
        //System.out.println(foo.foo().bar());
    }
}

as you can see i am creating an instance of BeanShellContainerBuilder with the file nanocontainer.bsh. the PicoContainer is then created from the container which in turns allows the lookup of wired components. if my bsh configuration file is setup correctly i will be able to

  • get an instance of Bar named "bar" from pico.
  • get an instance of Foo named "foo" from pico.
  • get an instance of Foo named Foo.class from pico.

all three of the instances will have been instantiated appropriately.

obviously i have left out the most critical portion of this example and that is the bsh configuration. the configuration merely instructs pico to register component implementations that will be used to wire instances that are obtained from pico.


import org.picocontainer.*;
import org.picocontainer.defaults.*;
import org.nanocontainer.script.bsh.BeanShellComponentAdapterFactory;

pico = new DefaultPicoContainer(
    new ImplementationHidingComponentAdapterFactory(), parent);

//pico.registerComponentInstance("bar", new BarImpl());
pico.registerComponentImplementation("bar", BarImpl.class);
//pico.registerComponentImplementation(BarImpl.class);

pico.registerComponentImplementation(
    Foo.class, FooImpl.class, new Parameter[] {
        new ComponentParameter("bar"), new ConstantParameter("testing") });

pico.registerComponent(
    new BeanShellComponentAdapterFactory().createComponentAdapter(
        "foo", FooImpl.class, null));

there are three very important points of interest related to the bsh configuration. "pico", the bsh container, is to be assigned a DefaultPicoContainer with an ImplementationHidingComponentAdapterFactory which resolves circular dependencies such as those found in Foo and Bar. additionally i have listed three ways in which BarImpl can be registered but commented out all except the middle in order to allow pico to create an instance of BarImpl and wire FooImpl through the constructor. lastly i am registering a ComponentAdapter created by BeanShellComponentAdapterFactory. in my opinion this is the most exciting portion of this example. this allows a component to be singly defined in an external bsh configuration file. i can define an implmentation of FooImpl that will be wired by pico in a configuration file all by itself. this provides the ability to configure pico components in one large configuration file or break out any that may be more complex.

the BeanShellComponentAdapterFactory is a bit limited at the moment, but it is my hope that i or someone else can build it out. currently the call to createComponentAdapter registers the component returned from the configuration file named FooImpl.bsh. Currently FooImpl.class determines the name of the file, however i believe this is inappropriate and have suggested an alternative. nontheless the FooImpl.bsh is as follows.

import dynaop.*;

instance = ProxyFactory.getInstance().wrap(
    picoContainer.getComponentInstance(Foo.class));
    //new FooImpl(picoContainer.getComponentInstance("bar"), "test"));

first i have aspectified the component for good measure. secondly i assign an instance of FooImpl to "instance". instance and picoContainer are variables that are available to all bsh configurations. "instance" is the instance to be registered with pico. picoContainer is the container that was created in the parent bsh configuration file and is accessible as such.

next i hope to combine picocontainer and dynaop in a way such that it is possible to wire dynaop Interceptors. if anyone has any thoughts on how best to approach this please comment.

as you are probably no doubt aware docs for picocontainer are rather thin so it is my hope that this will be a useful guide to configuring picocontainer with bsh.