Here I would like to share my experience playing with Aspect Oriented Programming and applying it to TANGO

AOP overview

Shortly speaking AOP helps to extract functionality from the code which otherwise is split all over the code base. Here is an example: logging, imaging we want to log every call to every method in a class. Conventional programming leaves us no choice expect this one:


public class Foo {
 
   public void bar1(){
        log.info(..)
        ..
   }


   public void bar2(){
        log.info(..)
        ..
   }

   //etc  
}

Now imaging we want to try/catch every method:


public class Foo {
 
   public void bar1(){
        log.info(..)
        try{
          ..
        } catch (..) {..}
   }


   public void bar2(){
        log.info(..)
        try{
          ..
        } catch (..) {..}
   }

   //etc  
}

Now hopefully you clearly realize where it goes…

AOP gives the solution: we can define aspects like Loggable, HandleError etc

so that our code will look like this:


@Loggable
@HandleError
public class Foo {
 
   public void bar1(){
      ..
        
   }


   public void bar2(){
      ..        
   }

   //etc  
}

But enough on theory…

AOP in TANGO

I have created a small project to implement some aspects useful for TANGO on GitHub

Namely this library now provides single Aspect called SelfRegisteringTangoService:


public @interface SelfRegisteringTangoService {
    String host() default "127.0.0.1";

    String port() default "10000";

    String db() default "sys/database/2";

    /**
     * @return domain for this service
     */
    String domain() default "development";

    /**
     * @return family for this service
     */
    String family() default "custom";

    /**
     * @return member for this service
     */
    String member() default "0";
}

This one can be used to automatically register TANGO server in the DB:


@SelfRegisteringTangoService(host = "hzgxenvtest")
@Device(transactionType = TransactionType.NONE)
public class DevEnumTestServer {
    public static void main(String[] args) {
        ServerManager.getInstance().start(args, DevEnumTestServer.class);
    }
..

Shortly speaking one has to use AspectJ compiler which will enhance Java byte code with additional methods call to perform the desired action:


//decompiled byte code
public static void main(String[] args) {
        JoinPoint var1 = Factory.makeJP(ajc$tjp_0, (Object)null, (Object)null, args);//this was added during compilation
        SelfRegisteringTangoServiceAspect.aspectOf().doRegister(var1);//this was added during compilation
        ServerManager.getInstance().start(args, DevEnumTestServer.class);
    }

Full project with the example above can be found here: DevEnumTestServer

If you investigate pom.xml you will find out that it requires at least these lines:



        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>de.hzg.wpi.tango</groupId>
            <artifactId>tango-aspects</artifactId>
            <version>1.0</version>
        </dependency>

<!– … –>

             <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.10</version>
                <executions>
                    <execution>
                        <id>aspectj</id>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                        <phase>process-sources</phase>
                    </execution>
                </executions>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <complianceLevel>${maven.compiler.target}</complianceLevel>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>de.hzg.wpi.tango</groupId>
                            <artifactId>tango-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                    <showWeaveInfo>true</showWeaveInfo>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>

Which is quite a lot to my opinion to just use a 3rd party library.

Anyway this approach may be very usefull inside JTango (logging, transactioning, retry-on-failure etc)

Conclusions

The approach of AOP itself seems very interesting and useful to reduce the code base of, for instance, Device class methods.

But honestly speaking AspectJ itself seems to be not very reliable, for instance, I had several problems with IntelliJ IDEA to resolve my custom aspects library (simply speaking I was not able to debug aspect code a few times after library update).

Plus for external usage significant configuration in pom.xml is required.

So my conclusion is that the approach can be used inside JTango, but we can use our own annotation processing i.e. extend existing one.

In C++ the same can be achieved using decorator pattern.

References

Here is a good article on the subject (aka short and clear): Java Method Logging with AOP and Annotations
Edited 6 years ago