PicoContainer has a rudimentary Aspect Orientated Programing (AOP) capability with its 'Interception' behavior. With respect to the methods of a component, both before and after invocation, control can be handed to an interceptor. You can intercept a method call:
There are some limitations:
public static class BiteReporter implements Apple { private Intercepted.Controller controller; public BiteReporter(Intercepted.Controller controller) { this.controller = controller; } public boolean takeBite(int grams) { System.out.println("Bite of " + grams + " grams of apple '" + controller.instance().getName() + "'"); return false; // ignored, but necessary. } } ... pico = new DefaultPicoContainer(new Intercepting()); pico.addComponent(Apple.class, BraeburnApple.class); Intercpeted intercepted = pico.getComponentAdapter(Apple.class).findAdapterOfType(Intercpeted.class); intercepted.pre(Apple.class, new BiteReporter(intercepted.getController())); // see also Intercpeted.post(...) method. Apple a1 = pico.getComponent(Apple.class); a1.takeBite(100); // prints Bite of 100 grams of apple 'Braeburn' // ... irrespective of what else Braeburn.takeBite(int) does.
pico = new DefaultPicoContainer(); pico.as(INTERCEPT).addComponent(Apple.class, BraeburnApple.class); // etc
pico = new PicoBuilder.withInterception().build(); pico.addComponent(Apple.class, BraeburnApple.class); // etc
pico = new PicoBuilder.withBehaviors(interception()).build(); pico.addComponent(Apple.class, BraeburnApple.class); // etc
Fine grained participation in interception
Assuming you're passing in the Interceptor to the classes you're using for interception of a component, you can
participate in the fate of the method call. For a 'pre' invocation, you can veto the calling of the 'real'
method.
public boolean takeBite(int grams) { if (grams > 50) { controller.veto(); } return false; // will be passed back to the caller. }
For a 'post' invocation, you can override the return value of the 'real' method.
public boolean takeBite(int grams) { if (grams > 50) { controller.override(); (Apple) realApple = (Apple) controller.instance(); realApple.takeBite(-1 * grams); // undo ! } return false; // will be passed back to the caller. }
Also for a 'post' invocation, you can access the return value of the 'real' method.
public boolean takeBite(int grams) { boolean rv = (boolean) controller.getOriginalRetVal(); if (rv == false) { // do something ! } return true; // ignored as no 'override' }