Chapter 10. Running Aspectized Applications

This section will show you how to run JBoss AOP with standalone applications and how to run it integrated with the JBoss application server.

10.1. Loadtime vs. Compiletime

There are 2 different modes to run your aspectized applications. Loadtime or precompiled. JBoss AOP needs to weave your aspects into the classes which they aspectize. You can choose to use JBoss AOP's precompiler to accomplish this(Compiletime) or have this weavining happen at runtime when the class is loaded(Loadtime).

Compiletime happens before you run your application. Compiletime weaving is done by using the JBoss AOP precompiler to weave in your aspects to existing .class files. The way it works is that you run the JBoss AOP precompiler on a set of .class files and those files will be modified based on what aspects you have defined. Compiletime weaving isn't always the best choice though. JSPs are a good instance where compiletime weaving may not be feasible.

Loadtime weaving offers the ultimate flexibility, but it requires some tweaking of classloaders that may or may not be standard depending on which JDK version you use. It is also slower to boot up your aspectized application with loadtime weavining as the class transformations happen at runtime. Once a class is loaded though, it runs just as fast as precompiled applications. The way it works is that when a class needs to be loaded, the AOP runtime library transforms the bytecode being loaded before the class is loaded by its class loader. To make this work with JDK 1.4 requires a little bit of hacking of java.lang.ClassLoader. JDK 5.0 though has a standard way of plugging in a class transformer via the java.lang.instrument package.

10.2. Regular Java Applications

JBoss AOP does not require an application server to be used. Applications running JBoss AOP can be run standalone outside of an application server in any standard Java application. This section focuses on how to run JBoss AOP applications that don't run in the JBoss application server.

10.2.1. Precompiled instrumentation

Running a precompiled aop application is quite similar to running a normal java application. In addition to the classpath required for your application you need to specify the files required for aop:

  • javassist.jar
  • trove.jar
  • concurrent.jar
  • jboss-common.jar
  • jboss-aop.jar
  • or jboss-aop-jdk50.jar

- depending on if you are using JDK 1.4 (jboss-aop.jar) or JDK 5.0 (jboss-aop-jdk50.jar)

JBoss AOP finds XML configuration files in these two ways:

  • You tell JBoss AOP where the XML files are. Set the jboss.aop.path system property. (You can specify multiple files or directories separated by ':' (*nix) or ';' (Windows), i.e. -Djboss.aop.path=jboss-aop.xml;metadata-aop.xml) If you specify a directory, all aop.xml files will be loaded from there as well.
  • Let JBoss AOP figure out where XML files are. JBoss AOP will look for all XML files that match this pattern /META-INF/jboss-aop.xml. So, if you package your jars and put your JBoss AOP XML files within /META-INF/jboss-aop.xml, JBoss AOP will find these files.

If you are using annotated bindings (See Chapter "Annotated Bindings"), you must tell JBoss AOP which JARS or directories that may have annotated @Aspects. To do this you must set the jboss.aop.class.path system property. (You can specify multiple jars or directories separated by ':' (*nix) or ';' (Windows), i.e. -Djboss.aop.class.path=aspects.jar;classes)

So to run a precompiled AOP application, where your jboss-aop.xml file is not part of a jar, you enter this at a command prompt:

$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \
         -Djboss.aop.class.path=aspects.jar
         com.blah.MyMainClass
            

To run a precompiled AOP application, where your application contains a jar with a META-INF/jboss-aop.xml file, you would need to do this from the command-line:

$ java -cp=<classpath as described above> com.blah.MyMainClass
            

In the /bin folder of the distribution we have provided batch/script files to make this easier. It includes all the aop libs for you, so you just have to worry about your files. The usage for JDK 1.4 is:

$ run-precompiled classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \
      com.blah.MyMainClass [args...]
            

For JDK 1.5:

$ run-precompiled15 classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \
      com.blah.MyMainClass [args...]
            

If your application is not in a jar with a META-INF/jboss-aop.xml file, you must specify the path to your *-aop.xml files in the -aoppath parameter, and if your class comtains aspects configured via annotations ( @Aspect etc.) you must pass in this classpath via the -aopclasspath parameter. (For JDK 1.4, you must have compiled the annotations first).

10.2.2. Loadtime

This section describes how to use loadtime instrumentation of classes with aop. The classes themselves are just compiled using Java, but are not precompiled with the aop precompiler. (If you want to use annotations with JDK 1.4, you will still need to use the JDK 1.4 Annotation Compiler). In the examples given if your classes are contained in a jar with a META-INF/jboss-aop.xml file, you would omit the -Djboss.aop.path system property.

10.2.2.1. Loadtime JDK 1.4

In order to do loadtime weaving of aspects with JDK 1.4, we had to massage java.lang.ClassLoader. java.lang.ClassLoader is modified to add hooks for class transformation before class loading. It is very similar to JDK 5's built in ability to define class transformers. What you have to do is generate a modification of java.lang.ClassLoader and add this class to the default bootstrap class path (bootclasspath) for your classes to get instrumented at loadtime. The classes used are dependent upon the VM. At present this custom classloader has only been tested with Sun's J2SE 1.4.x Due to licensing issues we believe we are not allowed to ship the precompiled version of the custom classloader. The steps to compile and use the custom classloader are shown below.

USE THIS ONLY WITH JDK 1.4. See below for how to do loadtime transformations with JDK 5.

$ java -cp=<classpath as described above>  \
       org.jboss.aop.hook.GenerateInstrumentedClassLoader <output dir>
               

For the following example, the aop boot classpath should be the output dir specified above, followed by the jars needed for AOP, i.e. javassist.jar, trove.jar, concurrent.jar, jboss-common.jar and jboss-aop.jar. You separate the classpath elements as normal, with ';' (Windows) or ':' (Unix). The path to your classes should NOT be included here! You then use this aop boot classpath as the argument for -Xbootclasspath option as shown here:

$ java -Xbootclasspath/p:<aop boot classpath as described> \
      -Djboss.aop.path=<path to jboss-aop.xml> \
      -classpath <path to your classes> com.blah.MyMainClass
               

In the /bin folder of the distribution we have provided batch/script files to make this easier. It includes all the aop libs for you, so you just have to worry about your files:

$ run-load-boot classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \
      com.blah.MyMainClass [args...]
               

The parameters have the same meaning as for the run-precompiled scripts. (Since this is for JDK 1.4, you must have compiled the annotations first). This script both creates the instrumented class loader and makes sure that that the JAVA_HOME environment variable has been set (Your job is to make sure it points to a 1.4 distribution!).

10.2.2.2. Loadtime with JDK 5

JDK 5.0 has a pluggable way of defining a class transformer via the java.lang.instrument package. JBoss AOP uses this mechanism to weave aspects at class load time with JDK 5. Using loadtime with JDK 5 is really easy. All you have to do is define an additional standard switch on the Java command line. -javaagent:jboss-aop-jdk50.jar. For these examples make sure that you use jboss-aop-jdk50.jar and not jboss-aop.jar in your classpath. Here's how run an AOP application in JDK 5.0 with loadtime instrumentation, where your jboss-aop.xml file is not part of a jar:

$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \
      -javaagent:jboss-aop-jdk50.jar com.blah.MyMainClass
               

And to run an AOP application in JDK 5.0 with loadtime instrumentation, where your application contains a jar with a META-INF/jboss-aop.xml file:

$ java -cp=<classpath as described above> -javaagent:jboss-aop-jdk50.jar \
      com.blah.MyMainClass
               

In the /bin folder of the distribution we have provided batch/script files to make this easier. It includes all the aop libs for you, so you just have to worry about your files. The usage for JDK 1.5 is:

$ run-load15 classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \
      com.blah.MyMainClass [args...]
               

The parameters have the same meaning as for the run-precompiled scripts.

If you invoke the previous java examples with ant, by using the ant java task, make sure that you set fork="true" in the ant java task. Failure to do so, causes the java task to execute in the same VM as ant which is already running. This means that the special classloader used to do the loadtime transformations does not replace the standard one, so no instrumentation takes place.

10.3. JBoss Application Server

JBoss AOP is integrated with JBoss 4.0 and JBoss 3.2.6RC1+ application server. The integration steps are different depending on what version of JBoss AS you are using and what JDK version you are using. It is also dependent on whether you want to use loadtime or compiletime instrumentation.

The JDK 5.0 integration to do loadtime transformations is much more stable and reliable than the 4.0 version and it is highly suggested that you consider moving to both JDK 5 and JBoss AOP's integration with JDK 5 if you want to do loadtime transformations. JDK 1.4 loadtime works, but it requires custom classloaders and not all libraries will use the JBoss class loader (i.e. JSPs).

10.3.1. Packaging AOP Applications

To deploy an AOP application in JBoss you need to package it. AOP is packaged similarly to SARs(MBeans). You can either deploy an XML file directly in the deploy/ directory with the signature *-aop.xml along with your package (this is how the base-aop.xml, included in the jboss-aop.deployer file works) or you can include it in the jar file containing your classes. If you include your xml file in your jar, it must have the file extension .aop and a jboss-aop.xml file must be contained in a META-INF directory, i.e. META-INF/jboss-aop.xml.

If you want to create anything more than a non-trivial example, using the .aop jar files, you can make any top-level deployment contain a .aop file containing the xml binding configuration. That is you can have a .aop file in an .ear file, or a .aop file in a war file etc. The bindings specified in the META-INF/jboss-aop.xml file contained in the .aop file will affect all the classes in the whole war!

10.3.2. JBoss 4.x and JDK 1.4

JBoss AOP comes distributed with the JBoss 4.x Application Server. It is best to download the latest version and update your JBoss Application Server installation as described in the "Installing" chapter of this guide. Also, the version distributed with JBoss 4.x Application Server may not be up to date. Check http://www.jboss.org/products/aop to see if a new version of JBoss AOP is available. To install a new version remove the jboss-aop.deployer file from the JBoss AS deploy/ directory and copy the jboss-aop.deployer directory from the JBoss AOP distribution to the JBoss AS deploy/ directory. This jboss-aop.deployer/ is in the JBoss AOP distribution within the jboss-40-install/ directory.

JBoss 4.x Application Server works out of the box with precompiled applications. If you want to do load-time transformations, you must edit jboss-aop.deployer/META-INF/jboss-service.xml as follows:

The jboss-aop.deployer file contains some MBeans that deploy and manage the AOP framework.

                  <mbean code="org.jboss.aop.deployment.AspectManagerService"
         name="jboss.aop:service=AspectManager">
         <attribute name="EnableTransformer">false</attribute>
         <!-- only relevant when EnableTransformer is true -->
         <attribute name="SuppressTransformationErrors">true</attribute>
         <!-- only relevant when Enabletransformer is true.  Optimization is optional
         only just in case there is a bug in it -->
         <attribute name="Optimized">true</attribute>
         <attribute name="Verbose">false</attribute>
      </mbean>

      <mbean code="org.jboss.aop.deployment.AspectDeployer"
         name="jboss.aop:service=AspectDeployer">
      </mbean>
    

By default, JBoss application server will not do load-time bytecode manipulation of AOP files. You can turn load-time on by setting the EnableTransformer attribute to true. If SuppressTransformationErrors is true failed bytecode transformation will only give an error warning. This flag is needed because the JSP compiler does not run within a JBoss classloader and the AOP loader cannot resolve classes from this JSP classloader.

10.3.3. JBoss 4.x and JDK 5

The JDK 5.0 integration to do loadtime transformations is much more stable and reliable than the 4.0 version and it is highly suggested that you consider moving to both JDK 5 and JBoss AOP's integration with JDK 5 if you want to do loadtime transformations. JDK 1.4 loadtime works, but it requires custom classloaders and not all libraries will use the JBoss class loader (i.e. JSPs).

JBoss AOP comes distributed with the JBoss 4.x Application Server. The version that comes with JBoss 4.x does not take advantage of JDK 5.0 features. It is best to install the jboss-aop-jdk50.deployer/ distribution into your JBoss Application Server install base. See the "Installing" chapter for more details.

If you want to do load-time transformations with JBoss 4 and JDK 5, there are two steps you must take.

The jboss-aop-jdk50.deployer file contains some MBeans that deploy and manage the AOP framework.

                  <mbean code="org.jboss.aop.deployment.AspectManagerServiceJDK5"
         name="jboss.aop:service=AspectManager">
         <attribute name="EnableTransformer">false</attribute>
         <!-- only relevant when EnableTransformer is true -->
         <attribute name="SuppressTransformationErrors">true</attribute>
         <!-- only relevant when Enabletransformer is true.  Optimization is optional
         only just in case there is a bug in it -->
         <attribute name="Optimized">true</attribute>
         <attribute name="Verbose">false</attribute>
      </mbean>

      <mbean code="org.jboss.aop.deployment.AspectDeployer"
         name="jboss.aop:service=AspectDeployer">
      </mbean>
    

By default, JBoss application server will not do load-time bytecode manipulation of AOP files. You can turn load-time on by setting the EnableTransformer attribute to true. If SuppressTransformationErrors is true failed bytecode transformation will only give an error warning. This flag is needed because the JSP compiler does not run within a JBoss classloader and the AOP loader cannot resolve classes from this JSP classloader.

The next step is to copy the pluggable-instrumentor.jar from the lib-50 directory of your JBoss AOP distribution to the bin/ directory of your JBoss AOP application server installation. Next edit run.sh or run.bat (depending on what OS you're on) and add the following to the JAVA_OPTS environment variable

set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME% -javaagent:pluggable-instrumentor.jar
         

After modifying JAVA_OPTS and setting the EnableTransformations to true, then you should be ready to go.

10.3.4. JBoss Application Server 3.2.x and JDK 1.4

JBoss AOP can also work with JBoss 3.2.7 (maybe 3.2.6) and higher in the JBoss 3.2 series. Look in the Installing chapter on how to install the JAR files.

After installing, you need to modify the jboss-3.2.7/server/xxx/conf/jboss-service.xml file to add these mbean definitions. They are similar to the 4.0 release, but notice the '32' added to the class name.

               <mbean code="org.jboss.aop.deployment.AspectManagerService32"
         name="jboss.aop:service=AspectManager">
         <attribute name="EnableTransformer">false</attribute>
         <!-- only relevant when EnableTransformer is true -->
         <attribute name="SuppressTransformationErrors">true</attribute>
         <!-- only relevant when Enabletransformer is true.  Optimization is optional
         only just in case there is a bug in it -->
         <attribute name="Optimized">true</attribute>
         <attribute name="Verbose">false</attribute>
      </mbean>

      <mbean code="org.jboss.aop.deployment.AspectDeployer32"
         name="jboss.aop:service=AspectDeployer">
      </mbean>
      

Also, copy the base-aop.xml file into the server/xxx/deploy/ directory if you want to use any of JBoss Aspects.

10.1. JBoss 3.2.x and JDK 5

The JDK 5.0 integration to do loadtime transformations is much more stable and reliable than the JDK 1.4 integration it is highly suggested that you consider moving to both JDK 5 and JBoss AOP's integration with JDK 5 if you want to do loadtime transformations. JDK 1.4 loadtime works, but it requires custom classloaders and not all libraries will use the JBoss class loader (i.e. JSPs).

To use JDK 5 loadtime with JBoss 3.2.x make sure you follow the directions in the 'Installing' chapter.

If you want to do load-time transformations with JBoss 3.2.7 and JDK 5, there are two steps you must take.

After installing, you need to modify the jboss-3.2.7/server/xxx/conf/jboss-service.xml file to add these mbean definitions. They are similar to the 4.0 release, but notice the '32' added to the class name.

               <mbean code="org.jboss.aop.deployment.AspectManagerService32JDK5"
         name="jboss.aop:service=AspectManager">
         <attribute name="EnableTransformer">false</attribute>
         <!-- only relevant when EnableTransformer is true -->
         <attribute name="SuppressTransformationErrors">true</attribute>
         <!-- only relevant when Enabletransformer is true.  Optimization is optional
         only just in case there is a bug in it -->
         <attribute name="Optimized">true</attribute>
         <attribute name="Verbose">false</attribute>
      </mbean>

      <mbean code="org.jboss.aop.deployment.AspectDeployer32"
         name="jboss.aop:service=AspectDeployer">
      </mbean>
      

Also, copy the base-aop.xml file into the server/xxx/deploy/ directory if you want to use any of JBoss Aspects.

By default, JBoss application server will not do load-time bytecode manipulation of AOP files. You can turn load-time on by setting the EnableTransformer attribute to true. If SuppressTransformationErrors is true failed bytecode transformation will only give an error warning. This flag is needed because the JSP compiler does not run within a JBoss classloader and the AOP loader cannot resolve classes from this JSP classloader.

The next step is to copy the pluggable-instrumentor.jar from the lib-50 directory of your JBoss AOP distribution to the bin/ directory of your JBoss AOP application server installation. Next edit run.sh or run.bat (depending on what OS you're on) and add the following to the JAVA_OPTS environment variable

set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME% -javaagent:pluggable-instrumentor.jar
      

After modifying JAVA_OPTS and setting the EnableTransformations to true, then you should be ready to go.