views:

82

answers:

1

Hi,

I want to wrap a number of classes implementing the Job interface with a JobEnabledDecorator object that determines whether or not it executes.

I am having trouble figuring out how to configure this in PicoContainer, so that it knows to create the Job implementation objects with a JobEnabledDecorator wrapping them.

Is this possible in Dependency Injection frameworks?

Is it possible in PicoContainer?

If so, any help would be appreciated.

+3  A: 

You'll probably want to add a "behavior." The short story is, you need to register a behavior factory which creates behaviors that wrap your component adapters. It's easier to describe when walking through an example.

First, you want to create a container, something like so.

final MutablePicoContainer container = new PicoBuilder()
    .withBehaviors(new JobEnabledDecorating())
    .build();

This means that, once the basic object is created - in your case the Job - you want to add something extra to it. There are a number of built-in behaviors, but you want your own: JobEnabledDecorating.

public class JobEnabledDecorating extends AbstractBehaviorFactory {
    @Override
    public ComponentAdapter createComponentAdapter(
        final ComponentMonitor componentMonitor, final LifecycleStrategy lifecycleStrategy,
        final Properties componentProperties, final Object componentKey,
        final Class componentImplementation, final Parameter... parameters) throws PicoCompositionException 
    {
        return componentMonitor.newBehavior(
            new JobEnabledDecorated(
                super.createComponentAdapter(
                    componentMonitor, lifecycleStrategy, componentProperties, 
                    componentKey, componentImplementation, parameters
                )
            )
        );
    }
}

The factory creates JobEnabledDecorated behaviors by wrapping the component adapter, which in turn provide your instances. The real work is now done in this behavior.

public class JobEnabledDecorated extends AbstractBehavior<Job> {
    public JobEnabledDecorated(final ComponentAdapter<Job> delegate) {
        super(delegate);
    }

    @Override
    public Job getComponentInstance(final PicoContainer container, final Type into)
            throws PicoCompositionException {
        final Job instance = super.getComponentInstance(container, into);
        return new JobEnabledDecorator(instance);
    }

    @Override
    public String getDescriptor() {
        return "JobEnabledDecorator-";
    }
}

getComponentInstance asks for the job, adds the decorator and returns this wrapped object as the new instance. You'll have to add your own logic here.

public interface Job {
    void execute();
}

public class JobEnabledDecorator implements Job {
    private Job delegate;

    public JobEnabledDecorator(final Job delegate) {
        this.delegate = delegate;
    }

    @Override
    public void execute() {
        System.out.println("before");
        delegate.execute();
        System.out.println("after");
    }
}

public class MyJob implements Job {
    @Override
    public void execute() {
        System.out.println("execute");
    }
}

Back to our container usage, consider this example.

    final MutablePicoContainer container = new PicoBuilder()
        .withBehaviors(new JobEnabledDecorating())
        .build();

    container.addComponent(Job.class, MyJob.class);

    final Job job = container.getComponent(Job.class);
    job.execute();

Running this will print:

before
execute
after

This is, of course, because the container handed you a JobEnabledDecorator(MyJob) object.

Ronald Blaschke
Thanks for the great answer. Unfortunately I can only give you one upvote!
Alex Baranosky
It's helpful to you, that's what matters. :-)
Ronald Blaschke