Create an API to Obtain the Value of Method Returns Asynchronously
The end goal of this example is to allow an application developer to tag a method as @Asynchronous have the method run in the background, but to provide an API so that the developer can obtain the value of a method return asynchronously. What we'll use here is an introduction and mixin to provide an API to obtain a java.util.concurrent.Future instance (from JDK 5.0 concurrent package) that will allow us to get access to the asynchronous method's return value. Using the @Asynchronous annotation public class POJO { @Asynchronous int someMethod() { ... } } This is the interface we want to introduce to any class that has a method tagged as @Asynchronous public interface AsynchronousFacade { java.util.concurrent.Future getLastFuture(); } So, the user would interact with this asynchronous aspect in the following way. { POJO pojo = new POJO(); AsynchronousFacade facade = (AsynchronousFacade)pojo; ... pojo.someMethod(); // invokes in background Future future = facade.getLastFuture(); ... do other work... // go back and get result. block until it returns. int result = (Integer)future.get(); } The first thing we need to do is define the mixin that will provide Futures. This mixin should also have a private interface so that the asynchronous aspect has a way to set the current invocation's future after it spawns the method invocation to the background. The mixin will be very very simple. It will basically expose a java.lang.ThreadLocal so that the Future can be set and acquired. public class AsynchMixin implements AsynchronousFacade, FutureProvider { private ThreadLocal currentFuture = new ThreadLocal(); public Future getLastFuture() { return (Future)currentFuture.get(); } public void setFuture(Future future) { currentFuture.set(future); } } The FutureProvider is an additional interface introduction that the aspect will use to set the future when after it spawns the task in the background. public interface FutureProvider { public void setFuture(Future future); } Next, let's look at the aspect that will implement the asynchronous behavior. The aspect is made up of an advice that will create a java.util.concurrent.Callable instance so that the current method invocation will run in the background. public class AsynchAspect { ExecutorService executor = Executors.newCachedThreadPool(); public Object invokeAsynch(MethodInvocation invocation) throws Throwable { final Invocation copy = invocation.copy(); Future future = executor.submit( new Callable() { public Object call() { try { return copy.invokeNext(); } catch (Throwable throwable) { return throwable; } } }); FutureProvider provider = (FutureProvider)invocation.getTargetObject(); provider.setFuture(future); return nullOrZero(invocation.getMethod().getReturnType()); } private Object nullOrZero(Class type) { if (type.equals(long.class)) return 0; //... other types ... return null; } } The invokeAsynch advice first copies the invocation. A copy copies the entire state of the invocation objec and remembers exactly in the interceptor/advice chain to continue on when the method is spawned off into a separate thread. The copy allows the current Java call stack to return while allowing the copy to live in a separate thread and continue down the interceptor stack towards the actual method call. After creating a callable and running the method in a separate thread, the advice gets the target object from the invocation, and typecasts it to FutureProvider so that it can make the future available to the app developer. So the mixin and aspect are written. The next thing to do is to define an advice binding so that when a method is tagged as asynchronous, the asynch advice will be triggered, and the method will run in the background. After defining the aspect binding, we then come to the introduction definition itself. We want the introduction to be added to any class that has any method tagged as @Asynchronous. The JBoss AOP pointcut expression language has a keyword has to allow for this type of matching. Let's look at the introduction binding. AsynchronousFacade, FutureProvider AsynchMixin new AsynchMixin() The example is now complete. Introductions/mixins aren't solely limited to pseudo-multiple inheritance and the asynch aspect is a great example of an aspect with a runtime API.