JBoss.org Community Documentation

5.3. Aspects with APIs

The serialization and externalization examples show previously in this chapter are kinda lame. Sure, you can use introductions/mixins for multiple inheritance, or to do nice tricks like forcing an existing class to be serializable. A more compelling use case is needed to justify this particular feature. This is what this section is about.

The best use cases for introductions/mixins comes when you have an aspect that requires an API for the user to interact with. Many aspects have runtime APIs so that the application developer can interact with a particular aspect to set configuration or to gain added behavior. A good example of an aspect with an API is if we expand on the @Oneway example in the "Aspect-Oriented Annotations" section of this user guide. @Oneway allows you to tag a method as oneway and when you invoke that method it runs in the background. The problem with this example is that you can only run void methods in the background and cannot interact asynchronously with methods that return a value. You have no way of obtaining the return value of an asynchronous call. Let's walk through an example of taking the oneway aspect and adding a runtime API for that aspect so that application developers can obtain method return values 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.

         <aspect class="AsynchAspect" scope="PER_VM"/>
<bind pointcut="execution(!static * *->@Asynchronous(..))">
   <advice name="invokeAsynch" aspect="AsynchAspect"/>
</bind>

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.

<introduction expr="has(!static * *->@Asynchronous(..))">
   <mixin>
      <interfaces>AsynchronousFacade, FutureProvider</interfaces>
      <class>AsynchMixin</class>
      <construction>new AsynchMixin()</construction>
   </mixin>
</introduction>

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.