August 2003
[ jonas ] 08:10, Friday, 15 August 2003

Using the new 0.8 version of AspectWerkz it is now a breeze to instrument your Servlets, EJBs or WebServices at runtime.

In this example I will show how you use AspectWerkz together with WebLogic Server. Please note that AspectWerkz is not in any way tied to WLS, it is a pure generic AOP solution that works equally good inside any application server.

Even though I am fed up with using tracing as a way of demonstrating AOP, this is exactly what I am going to do. This due to simplicity and to be able focus on the important areas. Like, how to get it to work.

So now I will instrument the examplesServer application in WLS which contains all interesting parts in J2EE: SLSB, SFSB, CMP, BMP, MDB, Servlets, WebServices etc.

First I write a simple XML definition file:

<!DOCTYPE aspectwerkz PUBLIC
    "-//AspectWerkz//DTD 0.8//EN"
    "http://aspectwerkz.codehaus.org/dtd/aspectwerkz_0_8.dtd">

<aspectwerkz id="samples">
    <advice-def name="log" class="examples.logging.LoggingAdvice" deployment-model="perJVM"/>
	
    <aspect name="testWLS">
        <pointcut-def name="allMethods" type="method" pattern="* examples..*+.*(..)"/>
 
        <bind-advice pointcut="allMethods">
            <advice-ref name="log"/>
        </bind-advice>
    </aspect>
</aspectwerkz>

Here you can see that I define one advice that does the tracing, one pointcut matching all methods in the whole examples application and then I simply 'bind' the advice to the pointcut.

So now all I have to do is to start up the application server (in this case WLS) along with AspectWerkz. For this I have many options. First I can post-process my class files before deployment using the aspectwerkz -offline ... compiler. Second there are some more interesting 'online' alternatives. For all the 'online' options see the AspectWerkz documentation.

For simplicity I am using the command line tool bin/aspectwerkz which is a unification of the HotSwap and the Transparent bootclasspath options (see the documention for details). This tool autodetects the version of the JVM I am using and is chosing the best option for me.

So what I have to do is to alter the startup script for WLS a little bit. You have to alter the last part in the script:

"%JAVA_HOME%\bin\java" %JAVA_VM% %MEM_ARGS% %JAVA_OPTIONS% 
	-Dweblogic.Name=%SERVER_NAME% -Dweblogic.ProductionModeEnabled=%PRODUCTION_MODE% 
	-Djava.security.policy="%WL_HOME%\server\lib\weblogic.policy" weblogic.Server 
So it looks like this:
set ASPECTWERKZ_HOME=C:\src\aspectwerkz
set AW_OPT=-Daspectwerkz.definition.file=C:\bea\weblogic81\mydomain\aspectwerkz.xml

%ASPECTWERKZ_HOME%\bin\aspectwerkz %JAVA_VM% %MEM_ARGS% %JAVA_OPTIONS% %AW_OPT% 
	-Dweblogic.Name=%SERVER_NAME% -Dweblogic.ProductionModeEnabled=%PRODUCTION_MODE% 
	-Djava.security.policy="%WL_HOME%\server\lib\weblogic.policy" weblogic.Server 
As you can see here I am simply setting the ASPECTWERKZ_HOME , passing the definition file to the JVM using the -Daspectwerkz.definition.file JVM option and then replacing the regular call to %JAVA_HOME%\bin\java with the call to %ASPECTWERKZ_HOME%\bin\aspectwerkz .

So now all we have to do is to start up the server and run the examples. Running, for example, the CMP example produces the folllowing output (as you can see AspectWerkz has no problem with the ejbc generated stubs):

...
--> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1_HomeImpl_WLSkel::invoke
  --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1_HomeImpl::create
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_initialize
      --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_initialize
        --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_initialize_persistent
        <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_initialize_persistent
      <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_initialize
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_initialize
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setEntityContext
      --> examples.ejb20.basic.containerManaged.AccountBean::setEntityContext
        --> examples.ejb20.basic.containerManaged.AccountBean::id
        <-- examples.ejb20.basic.containerManaged.AccountBean::id
        --> examples.ejb20.basic.containerManaged.AccountBean::log
setEntityContext called (12773520, PK = nullctx)
        <-- examples.ejb20.basic.containerManaged.AccountBean::log
      <-- examples.ejb20.basic.containerManaged.AccountBean::setEntityContext
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setEntityContext
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setEJBContext
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setEJBContext
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setup
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setup
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setBusy
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setBusy
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::ejbCreate
      --> examples.ejb20.basic.containerManaged.AccountBean::ejbCreate
        --> examples.ejb20.basic.containerManaged.AccountBean::log
AccountBean.ejbCreate( id = 12773520, PK = 10020, initial balance = $ 3000.0)
        <-- examples.ejb20.basic.containerManaged.AccountBean::log
        --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setAccountId
        <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setAccountId
        --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setBalance
        <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setBalance
        --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setAccountType
        <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::setAccountType
      <-- examples.ejb20.basic.containerManaged.AccountBean::ejbCreate
      --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::pkCheck
      <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::pkCheck
      --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getPrimaryKey
      <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getPrimaryKey
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::ejbCreate
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getEJBContext
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getEJBContext
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setLoadUser
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setLoadUser
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::ejbPostCreate
      --> examples.ejb20.basic.containerManaged.AccountBean::ejbPostCreate
        --> examples.ejb20.basic.containerManaged.AccountBean::id
          --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
          <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
          --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
          <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
        <-- examples.ejb20.basic.containerManaged.AccountBean::id
        --> examples.ejb20.basic.containerManaged.AccountBean::log
AccountBean.ejbPostCreate (12773520, PK = 10020)
        <-- examples.ejb20.basic.containerManaged.AccountBean::log
      <-- examples.ejb20.basic.containerManaged.AccountBean::ejbPostCreate
      --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_create
        --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setBeanParamsForCreateArray
        <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setBeanParamsForCreateArray
      <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_create
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::ejbPostCreate
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setBusy
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setBusy
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::ejbStore
      --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_store
        --> examples.ejb20.basic.containerManaged.AccountBean::ejbStore
          --> examples.ejb20.basic.containerManaged.AccountBean::id
            --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
            <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
            --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
            <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
          <-- examples.ejb20.basic.containerManaged.AccountBean::id
          --> examples.ejb20.basic.containerManaged.AccountBean::log
AccountBean.ejbStore (12773520, PK = 10020)
          <-- examples.ejb20.basic.containerManaged.AccountBean::log
        <-- examples.ejb20.basic.containerManaged.AccountBean::ejbStore
        --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
        <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_getMethodState
      <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_store
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::ejbStore
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_isBusy
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_isBusy
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setLoadUser
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_setLoadUser
    --> examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_isCreatorOfTx
    <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1__WebLogic_CMP_RDBMS::__WL_isCreatorOfTx
  <-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1_HomeImpl::create
<-- examples.ejb20.basic.containerManaged.containerManaged_9ufdc1_HomeImpl_WLSkel::invoke
...

You can find the AspectWerkz 0.8 distribution here.

[ jonas ] 20:09, Wednesday, 13 August 2003

Today me and Alex released the 0.8 version of AspectWerkz.

This new release have been tested and verified to work for servlets and all types of EJBs under WebLogic Server 7 and 8.1 using both online and offline mode.

JMangler has been thrown out for a completely new and customized solution that apart from solving some of the shortcomings and bugs in JMangler also provides completely new and interesting possibilities. Here are the options currently supported for online mode:

  • HotSwap
    A first JVM launchs your target application in a second JVM. The first JVM hooks AspectWerkz in the second one just before the main class (and all dependencies) gets loaded, and then connects to the stdout / stderr / stdin stream ot the second JVM to make them appear as usual thru the first JVM.
  • Transparent bootclasspath
    For JVM or java version like 1.3 which don't support class replacement at runtime (HotSwap), this option allows for same mechanism by putting an enhanced class loader in the target application VM bootclasspath.
  • Native HotSwap
    A native C JVM extension running in the target application VM handles the replacement of the class loader by the enhanced one.
  • Remote HotSwap
    The application VM is launched suspended. The replacement of the enhanced class loader is done thru a separate manual process, which can easily be scripted.
  • Prepared bootclasspath
    The enhanced class loader is builded and packaged as a jar file in a first separate manual process, which can easily be scripted. The application VM is launched with options to use this enhanced class loader.
  • Auto detection of java 1.3 and java 1.4

Some of the other new features are:

  • JDK 1.3 compatibility.
  • Runtime attributes -> XML compiler (no more metaData dir and meta-data compilers needed, one aspectwerkz.xml per application).
  • Offline compiler refactored. Now support rollback on error facility.
  • Released under a BSD-style license.
  • Non-reentrancy option for join points.
  • Definition validator.
  • Documentation updated and reorganized.

The new release can be downloaded from here.

A more detailed paper describing the new online architecture can be downloaded from here

.