Introduction

Weaving Schemes

AspectWerkz supports several integration schemes. Each schemes depends on your requirements and provides different advantages and drawbacks. It is possible to use :

  • post compilation of the application (like AspectJ does): offline weaving at application build time
  • class load time weaving: online weaving at application deployment time
  • runtime weaving: online weaving in a running application (experimental)
AspectWerkz distribution contains a command line tool that helps to be up and running quickly, although it is a good thing to really understand the different schemes for a production environment.

Just In Time join point optimization

By default, joinpoint execution logic blocks are compiled on the fly as standalone classes. This behavior is the default one since it provides the best performance, avoiding the use of reflection whe it comes to executes advices and target advised method/constructor.

If you encounter troubles with this mode, it can be for now deactivated thru the option -Daspectwerkz.jit.off=true when you start your application (this can be used with an offline weaved application as well).

This option might be deprecated with the 1.1 version.

Aspects deployment descriptors

Since release 1.0 AspectWerkz support to configure several AspectSystem alongside the deployed applications and the container (application server) in which those are deployed. As described here, you need to write an AOP XML deployement descriptor for your aspects, that declares the Aspects to use, and defines or refines the pointcuts (where to do) and advices (what to do), no matter your Aspects are using an annotations based definition or a full XML defintions, or both.

When thinking about this aop.xml file, you need to remember that the declared Aspects will affects the classes visible from the ClassLoader that can access this file. For example if you package this file in application.war/WEB-INF/aop.xml, it will affects all web-application classes, third parties libraries from application.war/WEB-INF/lib/ and all JSPs.

If you want to affect all JVM classes, you can use the JVM option -Daspectwerkz.definition.file=path/aop.xml, or better have one or more META-INF/aop.xml file(s) accessible from the JVM regular classpath.

It is thus possible to organise your aspects alongside all your deployed applications, while allowing some interesting schemes: a tracing Aspect deployed at the JVM level will affect all deployed applications, while Aspects deployed within the application itself will only affects this application.

If you plan to use offline mode, you need to post process your application as many time as you have aop.xml files, and still packaged the aop.xml file(s) alongside the application and/or at a JVM wide level, depending on what you want to achieve.

To summarize, you have to remember that an META-INF/aop.xml or WEB-INF/aop.xml file will affect the classes loaded by the classloader(s) that have this aop.xml file in their path. The JVM wide aop.xml file will affect the system classloader and all child classloaders.

Handling several Aspects across several deployed applications

Understanding class loading in Java

You should be familiar with the way Java handles ClassLoader isolation to fully understand how to deploy your own Aspects.

When you are invoking a main method of a Class, this class is loaded (and lives) in the System ClassLoader. All classes belonging to a path specified with a -cp or -classpath JVM option will live in this ClassLoader.

If this class is using java.lang.Object and other java.* classes, those have been loaded (and live) in Extension ClassLoader or Bootstrap ClassLoader.

The java.lang.Object can be seen and used by your main Class since the System ClassLoader is by convention a child of the Extension ClassLoader which is himself a child of the Boot ClassLoader. This relation looks like this:
                        Boot ClassLoader (JRE / JDK classes)
                           |
                        Extension ClassLoader (JRE extension, like SSL security etc, in jre/ext directory)
                           |
                        System ClassLoader (your main Class, and all the -cp / -classpath jars and classes)
                        

When you are using an application server, there are usually many other classloaders. A simple view is to say that there is one classloader per deployed application (that's why you don't need to add your war file in the JVM classpath right ?). In fact the picture is a bit more complex to allow JSPs changes while the application is running etc. Those application ClassLoaders are child of upper ClassLoaders like the System ClassLoader, but if you deploy two war files, they cannot share classes unless thoses classes are in an upper ClassLoader.

If we deploy to war file in a Tomcat we will end-up in the following (simplified) organization:
                        Boot ClassLoader (JRE / JDK classes)
                           |
                        Extension ClassLoader (JRE extension, like SSL security etc, in jre/ext directory)
                           |
                        System ClassLoader (the Tomcat main Class, and all the -cp / -classpath jars and classes)
                           |
                        Some Tomcat specific ClassLoader (does not really matters)
                                 |                                   |
                             First.war ClassLoader               Second.war ClassLoader
                                 |                                    |
                             WEB-INF/lib                            WEB-INF/lib
                            and WEB-INF/classes                    and WEB-INF/classes
                            ClassLoader                            ClassLoader for Second.war
                                 |   |                                 |   |   |
                            JSP ClassLoader(s)                     JSP ClassLoader(s)
                        

For J2EE / EJB based application, the schemes is a bit more complex but follows the same model.

Although this kind of organization is mainly J2EE oriented, some Swing based application are using ClassLoader parent-child relation to allow for example plugin life cycles etc.

Weaving scope of META-INF/aop.xml and WEB-INF/aop.xml files

The single idea you need to remember is that AspectWerkz deployed Aspects thru aop.xml files have the scope of the ClassLoader that has this file in its path and all its child ClassLoader(s).

Three specific paths are used:

  • JVM wide: defined with -Daspectwerkz.definition.file=path/aop.xml, it impacts all JVM classes (except boot classloader for convenience). Note that it is not mandatory to name the file aop.xml
  • defined with WEB-INF/aop.xml, it will impact the classes of the web application including JSPs. It is mandatory to name the file aop.xml
  • defined with META-INF/aop.xml, it will impact the classes that can see this file. It is mandatory to name the file aop.xml
It is thus possible to place a path/META-INF/aop.xml in the JVM classpath ( -cp path/;...) to have the same scope as the JVM wide defined one.

If a jar file of the JVM classpath contains a META-INF/aop.xml file, it will aslo have the same scope.

The precedence between the aspects is then the one of the classpath, and then the one of the order in the aop.xml file.

With this model, it is thus possible to package a tracing aspect in a jar file, with a META-INF/aop.xml file (with a pointcut for all public method execution f.e.) and just add it to your classpath to allow a very simple generic tracing !

Aspect System

A single aop.xml file can declare several Aspect Systems for convenience. All will have the same weaving scope. The goal is mainly to have a well organized namespace for organizing your aspects. The precedence will follow the order of the <system> elements in the XML file. Each system must have a unique id within a ClassLoader hierarchy, as defined with <system id="some/system">

In the following two systems are defined, and the system id is using the application name and a path as a mnemonic, allthough it could be any string.
        <aspectwerkz>
            <system id="First.war/WEB-INF/FirstSystem">
                <package name="examples">
                    <aspect class="caching.CachingAspect" deployment-model="perInstance"/>
                </package>
            </system>
            <system id="First.war/WEB-INF/SecondSystem">
                <aspect class="examples.trace.TracingAspect" deployment-model="perJVM"/>
            </system>
        </aspectwerkz>
                    

Offline weaving

Introduction

AspectWerkz provides several way to weave the aspects in the application classes at build time. This is called offline weaving, offline mode, or even class post-processing.

With this mode you have to be sure to post-process the application classes as many times as required if you plan to use multiple Aspect Systems as described here.

There is mainly two ways to achieve this, allthough some variants can be built on top of them:
  • Use the AspectWerkz command line tool with the -offline option on a specific .class file, directory or jar file.
  • Use the org.codehaus.aspectwerkz.compiler.AspectWerkzC utility in an Ant or Maven script.
As you might have understood, the command line tool is delegating to the AspectWerkzC class after all required jars have been added to the classpath.

Command line tool usage

The command line tool is described in a next part.

AspectWerkzC and Ant / Maven integration

You can find several samples of Ant and Maven integration in the AspectWerkz distribution.

The following are the options supported by the AspectWerkzC tool. Most of them can be used as well in the AspectWerkz command line tool.

# set the classpath correctly
# see bin/setEnv in the AspectWerkz distribution

# Add Ant-1.5 in the classpath

java -cp ... org.codehaus.aspectwerkz.compiler.AspectWerkzC [-verbose] [-haltOnError] [-verify] [-cp {additional cp i}]*  {target 1} [{target i}]*

# Use -Daspectwerkz.definition.file=... option to specify the XML definition file to use
# Or rely on the META-INF/aop.xml and WEB-INF/aop.xml path lookup
                    
  • -verbose: turns on verbose mode (optional)
  • -haltOnError: stops the compilation at the first error (target2 will not be post-processed if it fails on target1) (optional)
  • -verify: do some bytecode verification (mainly usefull for AspectWerkz development team) (optional)
  • -cp path1;path2/some.jar: additional classpath needed for the compilation. Put your aspect classes in this path, and your application third parties jar if any. This is mainly needed to match on subtype patterns (java.lang.String +), where the complete classes dependancies is needed. For convenience you can use several -cp ... option. Be sure to use ";" or ":" as a path separator as for the regular JVM classpath option.
  • target path/classes path/application.jar: defines the classes, classes directories and jar files to post-process. It is possible to pass as many target as needed.

A sample for Ant using the command line tool looks like the following. You will notice that the aspect classes must be in the classpath (to retrieve their annotations that defines the pointcut f.e.).

In this sample, since the command line tool is used, it is mandatory to pass the XML definition file as the second argument.
<!-- =================================================== -->
<!--  offline transformation of the samples -->
<!-- =================================================== -->
<target name="aspectwerkz:transform"
    depends="clean, aspectwerkz:init, aspectwerkz:compile, aspectwerkz:samples:aspectc">
    <exec executable="${bin.dir}/aspectwerkz.bat">
        <arg line="-offline ${basedir}/src/application/aop.xml -verbose -verify -cp ${aspect.classes} ${application.classes}"/>
    </exec>
</target>
                    

A sample for Ant using the AspectWerkzC class looks like the following:
<target name="aspectwerkz:war:transform"
    depends="aspectwerkz:compile, aspectwerkz:war:aspectc">
    <java classname="org.codehaus.aspectwerkz.compiler.AspectWerkzC" fork="true">
        <classpath refid="project.class.path"/>
        <classpath>
            <pathelement path="${build.main.dir}"/><!-- needed for abstract Aspect activation -->
            <pathelement path="${build.web.dir}"/><!-- needed for Aspect activation -->
        </classpath>
        <jvmarg value="-Daspectwerkz.definition.file=${src.web.dir}/WEB-INF/aspectwerkz.xml"/>
        <jvmarg value="-Daspectwerkz.transform.verbose=true"/><!-- an AspectWerkz weaver option -->
        <arg value="-verify"/><!-- an AspectWerkzC tool option -->
        <arg value="-verbose"/><!-- an AspectWerkzC tool option -->
        <!-- below is the classes dir to post-process. It could be some jar files as well. -->
        <arg value="${build.web.dir}"/>
        <arg value="${build.main.dir}"/>
    </java>
</target>
                    

There is also a native Maven plugin for this - you can read more about it here.

Packaging the post-compiled classes

Once the application classes (or dir / jars) have been post-compiled, those have dependancies on

  • AspectWerkz jars and third parties jars.
  • Your own aspects classes and all aspects that might be triggered according to the Aspect System organization
It is then a good practice to package the aspects alongside your application just as regular classes, and then decide if AspectWerkz jars and third parties jars should be packaged within the application (f.e. in First.war/WEB-INF/lib/) or added to the application regular classpath. You can use the bin/setEnv script of the distribution for that, or change your application startup script to add those jars in the -cp or -classpath JVM classpath settings.

Ant task for Offline weaving

An Ant task is provided for offline weaving

Usage

First you need to activate the custom task in your Ant build.xml file with the following: (refer to Ant documentation on "taskdef" for more details)

<!-- we assume we defined a classpath with the id="aw.class.path" for AspectWerkz jars -->
<path id="aw.class.path">
    ...
    <pathelement path="pathToAspectWerkz.jar"/>
    ...
</path>

<!-- define the custom task (annotationc can be changed to what you prefer)
<taskdef name="awc" classname="org.codehaus.aspectwerkz.compiler.AspectWerkzCTask" classpathref="aw.class.path"/>
<!-- Note: the <daskdef> element can be nested within a <target> element at your convenience -->

<!-- invoke the awc defined task -->
<target name="samples:task:awc" depends="init, compile:all, samples:task:annoationc">
    <awc
        verbose="true"
        definition="${basedir}/src/samples/samples-attribdef.xml"
        classpathref="project.class.path">

        <target path="${basedir}/target/samples-classes"/>
    </awc>
</target>
                 

Reference

The AspectWerkzCTask task accepts the following:

  • verbose: [optional] flag marking the weaver verbosity [true / false]
  • taskverbose: [optional] flag marking the task verbose [true / false]
  • definition: [optional] path to aspect definition xml file (optional, can be found on the path as META-INF/aop.xml - even several)

Use the following parameters to configure the classpath and to point to the classes to be weaved. Those can be specified with nested elements as well / instead:
  • classpath: classpath to use
  • classpathref: classpath reference to use
  • targetdir: directory where to find classes to weave
  • targetpath: classpath where to find classes to weave
  • targetpathref: classpath reference where to find classes to weave

Nested elements are similar to the "java" task when you configure a classpath:
  • classpath: Path-like structure for the classpath to be used by the weaver. Similar to "java" task classpath
  • targetpath: Path-like structure for the class to be weaved

Some rarely used options are also available:
  • backupdir: directory where to backup original classes during compilation, defautls to ./_aspectwerkzc
  • preprocessor: fully qualified name of the preprocessor. If not set the default is used.

Class load time weaving

Class load time weaving allows to integrate AspectWerkz seamlessly in your applications, or in your whole application server. Several schemes are supported, for Java 1.3, Java 1.4, Java 1.5, BEA JRockit JVM etc.

Allthough in some circumstances it is just a matter of adding a single JVM option and AspectWerkz jars to your classpath, a whole documentation is available here.

AspectWerkz command line tool

Environment setting

The command line tool is the easiest way to start using AspectWerkz since it provides all classpath settings for both class load time weaving and offline post-processing.

To use it, you first need to set the ASPECTWERKZ_HOME environment variable to the directory containing the AspectWerkz installation.
set ASPECTWERKZ_HOME=C:\aop\aspectwerkz\

# export might be needed on Linux / Unix OS.

# The tool assumes JAVA_HOME environment variable is correctly set.
                    
The command line tool is then in ASPECTWERKZ_HOME/bin directory. You can add this directory to your PATH environment variable if you want.

Type aspectwerkz without any arguments to print the usage message.

Offline compilation

To post-process all class files in a specific directory (recursively), jar or zip file:

aspectwerkz -offline <definition file> [-verbose] [-verify] [-haltOnError] [-cp <classpath>]* <target classes to transform>+
  • The 'definition file' option is the path to the XML definition file (mandatory).
  • Turns on -verbose to follow each step of the processing (optional).
  • Turns on -verify to verify all weaved class according to the Java Class Format specification (optional, mainly usefull for AspectWerkz development team).
  • When an error occurs, all classes of the current target are restored to their initilal state and the processing goes on with the next target unless -haltOnError was set (optional). In this case the processing stops. Else a complete status about successfull and failed targets is printed at the end of all target processing.
  • The 'classpath' option is the classpath needed for compilation but not to be transformed (eg -cp myAspects.jar;servletAPI.jar). It is possible to use several -cp <classpath> option instead of doing concatenation.
  • The 'target classes to transform' option specifies the classes to transform. It must the path to the root directory of the classes you want to transform, or a jar file or a zip file. Several targets can be passed in one call (eg toTransform.jar /classes otherToTransform.jar).

Note: when you then are running the application (without using the aspectwerkz command) you have to (apart from feeding it with the definition) put the aspectwerkz jars along with all the the dependency jars the ASPECTWERKZ_HOME/lib directory in your classpath. Read more about it here.

Class load time weaving

It is possible to use the command line tool as a replacement of the JAVA_HOME/bin/java command. In such a case, the command line tool will detect a suitable option for you and will enable class load time weaving.

This is the easiest way to give a try to class load time weaving although you should read and choose the best option by yourself by reading more on this topic here.

Starting up an application (use -Daspectwerkz.definition.file=.. or have META-INF/aop.xml and WEB-INF/aop.xml files in the classpath and applications packaging as explained in this section):

aspectwerkz [-options] <main class> [args...]

Starting up an application using an executable jar file:

aspectwerkz [-options] -jar <jar file> [args...]

Remote Proxy Server - RPC mechanism

AspectWerkz provides an RPC mechanism that allows you to use the instrumented objects (advices and mixins) seamlessly on a remote client site.

Client side

You can use the remote proxy on the client side in two ways:

  • create a client proxy that creates a matching instance on the server. The client now has seamless access this new specific instance on the server.

    Example:

    ...
    // creates a new remote proxy for the MixinImpl class which
    // maps to an instance of this class on the server
    RemoteProxy remoteProxy = RemoteProxy.createClientProxy(
            new String[]{"examples.connectivity.Mixin"},
            "examples.connectivity.MixinImpl",
            "localhost",
            7777
    );
    
    // retrieves the proxy to the MixinImpl instance
    Mixin mixin = (Mixin)remoteProxy.getInstance();
    
    // invoke methods on the proxy (executed on the server)
    System.out.println("Mixin says: " + mixin.test1());
    
    // close the proxy (close() must always be called)
    remoteProxy.close();
    ...
                                    



  • create an instance of some class on the server-side, wrap it with a RemoteProxy and send to the client over the wire. The client then have access to this specific instance on the server.

    Server side:

        ...
        // wrap an instance in a remote proxy on the server-side and send it to the client
        RemoteProxy remoteProxy = RemoteProxy.createServerProxy(anotherMixinInstance, "localhost", 7777);
        return remoteProxy;
    }
                                    

    Client side:

    ...
    // retrieve the proxy to the specific instance created on the server
    RemoteProxy remoteProxy = mixin.getMixin();
    
    // retrieves the proxy to the instance on the server
    AnotherMixin anotherMixin = (AnotherMixin)remoteProxy.getInstance();
    ...
                                    

A sample have been provided and can be found in the src/samples/examples/connectiviy directory. Start by taking a look at the Client.java class. You can run the sample by executing ant samples:remote:server to start up the server and then in another console execute ant samples:remote:client to start the client. (When you close down the server using ^C then the server listener threads are still hanging so you need to close down them manually.)

Server side

The remote proxy server is a multi-threaded production-ready implementation that is ready to serve any number of incoming requests. To configure the server settings (number of listener threads, max/min/init size of the thread pool, backlog etc.) you have to change the settings in the in the aspectwerkz.properties resource bundle and put it on the classpath. If no bundle is found default values are used.

The server resource bundle has the following format/options:

remote.server.hostname=localhost
remote.server.port=7777
remote.server.client.threads.timeout=60000
remote.server.listener.threads.nr=10
remote.server.listener.threads.backlog=200
remote.server.listener.threads.run.as.daemon=false
remote.server.thread.pool.type=bounded # possible types are bounded or dynamic
remote.server.thread.pool.max.size=100
remote.server.thread.pool.init.size=10
remote.server.thread.pool.min.size=10
remote.server.thread.pool.keep.alive.time=300000
remote.server.thread.pool.wait.when.blocked=true
remote.server.invoker.classname=
                    

To enable support for RPC in the AspectWerkz system you have to feed the JVM with the -Daspectwerkz.remote.server.run=true option.

If you have specific requirements. For example if you want to handle the user context that you (optionally) can set on the client RemoteProxy and have sent over or have other requirements on how you want to invoke you objects then you can create your own implementation of the org.codehaus.aspectwerkz.connectivity.Invoker interface and specify the implementation in the aspectwerkz.properties resource bundle using the remote.server.invoker.classname=.. option. For an example implementation see the org.codehaus.aspectwerkz.System.getDefaultInvoker() method.