Startup and transformation issues

AspectWerkz support three different ways of transforming your code. All of these are managed using the command line tool aspectwerkz which resides in the ASPECTWERKZ_HOME/bin directory.

The aspectwerkz command line tool

When you start up your application using the aspectwerkz command line tool instead of using the java command, AspectWerkz will intercept the normal class loading mechanism and be able to transform classes loaded by any class loader except the bootstrap class loader.

The command line tool is one of the several ways to enable on the fly weaving. For a complete description read the online architecture section.

The command line tool also allows for offline post-processing of classes.

The aspectwerkz program assumes that both the ASPECTWERKZ_HOME and JAVA_HOME enviromental variables are set.

The options are:

  • Starting up an application:

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


  • Starting up an application using an executable jar file:

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


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

    aspectwerkz -offline < definition file > [-verbose ] [-v erify ] [-haltOnError ] [-cp < classpath > ] * < target classes to transform > +

    The 'definition file' option is the path to the definition file.

    Turns on -verbose to follow each step of the processing.

    Turns on -verify to verify all weaved class according to the Java Class Format specification. Note that this can slow down the processing.

    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. 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 jar along with all the the dependency jars the ASPECTWERKZ_HOME/lib directory in your classpath.


Invoke the aspectwerkz command line tool without any arguments to get a more detailed usage description.

In all three cases you have to feed the system with your definition. See the Loading the definition section for a detailed description on how to do this.

Ant task for offline post-processing

For the -offline mode there is an Ant task that you can use for simplifying your build process. (It might be useful to run the ASPECTWERKZ_HOME/bin/setEnv.{bat|sh} script first.)

Please not that this Ant task uses exec and is using bin/aspectwerkz . It is provided in 0.8 for backward compatibility with 0.7.x and will be refactored in the next release. It is possible to use directly the main class org.codehaus.aspectwerkz.compiler.AspectWerkzC .

In order to use the Ant task you have to first define the task and then create a target that invokes the task.

Example:

<target name="offline" depends="init">
    <offlineTransformation
        aspectWerkzHome="${basedir}"
        definitionFile="${basedir}/src/samples/samples.xml"
        classesToTransform="${basedir}/target/samples-classes"
        classPath="${basedir}/lib"/>
</target>

<taskdef name="offlineTransformation"
    classname="org.codehaus.aspectwerkz.task.OfflineTransformationTask"
    classpath="${aspectwerkz.classpath}"/>

Loading the definition

The AspectWerkz system needs to know where it can find the aspect definition.

You have two options depending on your needs and settings:

  • Feed the system with the XML definition using the:

    -Daspectwerkz.definition.file= < path_to_definition_file > command line option.


  • Put the definition in a file called exactly aspectwerkz.xml and put it on the class path. Then the system will try to load the definition as a resource.


You can validate the definition at runtime by defining the:

-Daspectwerkz.definition.validate=true option.

See the Validate definition section for details.

Validate definition

AspectWerkz has a build in definition validator that can help you catch errors in the XML definition as well as in the attributes at compile time.

This feature is turned off by default and you can switch it on by defining the:

-Daspectwerkz.definition.validate=true option.

To be able to validate you have to have all the advices and introductions on the classpath. This is needed since the definition validator checks if the classes defined actually exists.

Even if you don't compile a weave model before starting up the system you can use the definition validator which will then validate the XML definition at runtime before proceeding (but it will not abort on errors).

Hot deployment and reconfiguration

AspectWerkz supports hot deployment and reconfiguration of both Advices and Introductions . It can actually create, add, remove and rearrange Advices as well as replace an introduced implementation at runtime. The target classes does not have to be reloaded or transformed again.

The AspectWerkz system is retrieved by invoking the AspectWerks.getSystem(uuid) . The uuid is the same UUID as specfied when compiling the weave model. If an auto-generated has been used the generated UUID can be read in the file name of the weave model (weaveModel_ < UUID > .ser). If no weave model has been compiled (only using the XML definition) then you can retrieve the system by invoking AspectWerkz.getDefaultSystem() .

Examples

  • For replacing an Introduction implementation use:
    AspectWerkz.getSystem(uuid).getIntroduction("mixins/Mixin").
            swapImplementation("mixins.NewMixinImpl");
    
    (the new implementation has to implement the same interface as the previous one)


  • For creating a new Advice use:
    // The parameters are:
    // 1. the name of advice
    // 2. the class name of advice
    // 3. the deployment model
    // 4. an optional user defined classloader (can be null)
    
    AspectWerkz.getSystem(uuid).createAdvice(
            "advices/NewAdvice", "advices.NewAdvice", "perInstance", myClassLoader);
    


  • For removing an Advice from a specific pointcut use:
    List methodPointcuts = AspectWerkz.getSystem(uuid).getAspect("MyAspect").
                    getMethodPointcuts(className, methodMetaData);
    for (Iterator it = methodPointcuts.iterator(); it.hasNext();) {
        MethodPointcut pointcut = (MethodPointcut)it.next();
        if (pointcut.hasAdvice("advices/NewAdvice")) {
            pointcut.removeAdvice("advices/NewAdvice");
        }
    }
    


  • For adding a new Advice to a specific pointcut use:
    List methodPointcuts = AspectWerkz.getSystem(uuid).getAspect("MyAspect").
                    getMethodPointcuts(className, methodMetaData);
    for (Iterator it = methodPointcuts.iterator(); it.hasNext();) {
        MethodPointcut pointcut = (MethodPointcut)it.next();
        if (pointcut.getExpression().equals(expression)) { // check that we are at the right pointcut
            pointcut.addAdvice("advices/NewAdvice");
        }
    }
    


  • For changing the order of the Advices at a specific pointcut use:
    List methodPointcuts = AspectWerkz.getSystem(uuid).getAspect("MyAspect").
            getMethodPointcuts(className, methodMetaData);
    for (Iterator it = methodPointcuts.iterator(); it.hasNext();) {
        MethodPointcut pointcut = (MethodPointcut)it.next();
        List advices = pointcut.getAdviceIndexTuples();
    
        ... // change the order of the advices
    
        pointcut.setAdviceIndexTuples(advices);
    }
    


All these operations are fully thread-safe.

Thread safety

AspectWerkz is generally thread-safe.

There is only one rare case where you have set it explicitly and that is when you are spawning a new thread inside an Advice . Then you have to call joinPoint.proceedInNewThread() instead of the normal call to joinPoint.proceed() .

Here is an example taken from the Asynchronous calls example in the Examples section .

public Object execute(final JoinPoint joinPoint) throws Throwable {
    m_threadPool.execute(
            new Runnable() {
                public void run() {
                    try {
                        // this call is made in a new thread
                        joinPoint.proceedInNewThread(); // using proceedInNewThread

                    } catch (Throwable e) {
                        throw new WrappedRuntimeException(e);
                    }
                }
            }
    );
    return null;
}

Pluggable container implementation

You have the possibility of providing your own advice or introduction container implementation. This can be useful if you for example would like to make the advices and/or introductions persistent.

To create a custom container you only need to implement the org.codehaus.aspectwerkz.advice.AdviceContainer or the org.codehaus.aspectwerkz.introduction.IntroductionContainer interface. The custom implementation then need to be fed to the system using the -Daspectwerkz.introduction.container.impl=... or the -Daspectwerkz.advice.container.impl=... option.

If you don't provide a custom implementation the default one will be used.

For an example on how to create a persistent container using Prevayler as the persistence engine see code in the ASPECTWERKZ_HOME/sandbox dir.