9/17/2010

Using AspectJ with RAD


Here I am going to explain how to use AspectJ with RAD 7.5 and Websphere Application Server 7.0.

Installing Aspect to RAD
The AspectJ Development Tools project provides support for AspectJ development on the Eclipse platform. To install Aspect here I am using Update Manager of Eclipse platform. The Update Manager can be accessed by clicking Help -> Software Updates -> Available Software -> Add Site.

Location for AspectJ update for RAD 7.5 is http://archive.eclipse.org/tools/ajdt/34/update/.

After install and RAD restart, you should be able to see Aspect Development Tools.

Here I am going to explain how to develop an aspect to process an annotation during a class constructor call. Using this aspect I can overcome the problem of calling injectMembers in my previous blog.

We will start by defining our Constructor Aspect.
package com.mine.myframework.aspects.ConstructorAspect;

import com.google.inject.Injector;

public aspect ConstructorAspect {
 
 before() : execution(new(..)) && !this(ConstructorAspect) { 
  Class clazz = thisJoinPoint.getThis().getClass();
  Injectable injectable = clazz.getAnnotation(Injectable.class);
  if(injectable != null) {
   String clazzName = thisJoinPoint.getThis().getClass().getName();
   StringBuilder builder = new StringBuilder(clazzName);
   builder.append(" constructor invoked ");
   Object[] params = thisJoinPoint.getArgs();
   if(params != null && params.length > 0) {
    builder.append("with arguments ")
        .append(Arrays.toString(params));
   }
   builder.append("............");

   Injector injector = Guice.createInjector(new MyModule());
   injector.injectMembers(this);
  }
 }
}

This aspect will get called before executing any code inside your constructor. But I don't want to call Ijector in every class. So what I am doing is I created an Annotation Injectable to annotate your class. If Injectable annotation is present in your class only Injection logic will execute.

Here is code for Injectable annotation.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Injectable {

}

If you want to read more about AspectJ refer to Programming Guide.

Since I am packaging this aspect inside a utility jar file and I am gonna use this aspect in classes inside other jar file. For that I need to use AspectJ Load Time Weaving feature to weave constructor aspect to classes outside of my utility jar. To do this I need to package AspectJ configuration file aop.xml with the my utility jar file.

<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
 <aspects>
      <aspect name="com.mine.myframework.aspects.ConstructorAspect"/>
      <include within="com.mine..*"/>
     </aspects>
    <weaver>
     <include within="com.mine..*"/>
    </weaver>
</aspectj>

We need to place aop.xml file inside the META-INF folder of the utility jar file.

As you know to enable load time weaving we need to configure aspectweaving jar file using -javaagent JVM argument.

Now I am going to explain how to configure our Websphere Application Server to use AspectJ Load Time Weaving.

Configure -javaagent JVM argument.
In Websphere Admin Console -> Servers -> Server Types -> Websphere Application Server -> <your server> -> Java and Process Management -> Process Definition -> Java Virtual Machine -> Add Generic JVM argument.

-javaagent:pathto/apectjweaving.jar


WAIT!!! Since Websphere security is enabled by default, and the aspectJ weaver is located outside the Websphere libraries - java security policy won't let it load - and you can't start your server!!! Copy the jars into the Websphere lib directory.


Now your Websphere Application Server is configured for ApectJ Load Time Weaving.

Any my problem with calling injectMembers is solved. Now if I want to inject an EJB to my POJO just annotate my POJO with Injectable annotation.


@Injectable
public class MyPOJO {

 // Injecting Remote EJB 3.0
 @EJB(name="ejb/MyRemoteBean")
 private MyRemote remote;
 
 // Injecting Local EJB 3.0
 @EJB(name="ejb/MyLocalBean", type="local")
 private MyLocal local;
 
 // Injecting Remote EJB 2.1
 @EJB(name="ejb/MyRemoteBean21", home=MyRemoteHome.class)
 private MyRemote21 remote1;
 
 // Injecting Local EJB 2.1
 @EJB(name="ejb/MyLocalBean21", type="local", home=MyLocalHome.class)
 private MyLocal21 local1;
  
 public void test() {
  remote.test();
  local.test();
  remote1.test();
  local1.test();
 }
}

Now we can hide all the injection logic from users. Enjoy!

No comments:

Post a Comment