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.
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.
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}"/>
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.
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).
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()
.
-
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.
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;
}
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.