Thursday, May 27, 2004

AOP integration in Tomcat 5

(imported from, read comments there)

On several recent ML post AspectWerkz users complained about getting into troubles when hooking in AOP in Tomcat 5. Steve provided good feedback but ... there is off course a damned better way to handle that !

Here is a little hands on that gives the idea for a 5 minutes shot.
Pretty much straigthforward based on

  • cvs head ie the next 1.0 beta and not 0.10

  • no integration detail, just some bin/aspectwerkz.bat magic

  • aop.xml deployed wihin the target application itself

  • a little fix in a strange file in qdox-1-3.jar

I was concerned about this issue and had an hectic face to face burger discussion with Jonas about "my" so called seamless integration of AOP... I needed to sit down on that and hack, too bad for the jet lag in this crazy GMT 9h far from home SF BEA eWorld clock.

Since the Codehaus had to migrate some CVS details today, the little qdox.jar fix that is needed cannot be commited, but just do it yourself if you want to go on with those explanations. Or wait tomorrow since Bob the despot is around there as well... He'll fix that for me if he is not too busy on the new Codehaus / BEA BeeHive stuff there.

So I took a Tomcat 5 from Apache, unzipped the stuff on my windows box.
I checked that it was fine with the bin/startup.bat and shutted it down to spread AOP in.

Then I made sure that AW *cvs head* was builded, and ASPECTWERKZ_HOME and JAVA_HOME was set.

I decided to give a try to this integration issue and decided to start with a silly tracing aspect that is sitting in AW samples (examples.logging.JavaLoggingAspect). I then builded the samples with a maven target (aspectwerkz:samples:compile)and had a new target/aspectwerkz-samples.jar ready to use.

Then I just opened this bin/catalina.bat that is actually starting things and added this just before the comment:

rem Execute Java with the applicable properties

to have AOP seamless integration:

set CLASSPATH=%CLASSPATH%;%ASPECTWERKZ_HOME%\target\aspectwerkz-samples.jar
set _EXECJAVA=%ASPECTWERKZ_HOME%\bin\aspectwerkz.bat
set JAVA_OPTS=%JAVA_OPTS% -Daspectwerkz.transform.verbose=false

So as you see I go with the bin\aspectwerkz.bat way, which is the easiest kick off stuff we provide, with adaptive behavior regarding Java version detection etc, even if when it comes to production usage I would rather use some JRockit VM.

You will have noticed that I just added my silly tracing sample aspect in the CLASSPATH and replaced bin/java call by bin/aspectwerkz.bat - not taking care about the details.

From there, Tomcat started up *almost* fine. The AW/lib/qdox-1.3.jar has a strange file that Tomcat complains about... Just dropped this from the qdox.jar and we are up and running with AOP online mode / class load time weaving / AOP container from cvs head.

Time to bind my system level tracing Aspect to some application.
I did a try by writting a 5 lines aop.xml file (actually copy pasted it from AW samples/hotdeployed.xml) and dropping it in Tomcat samples in webapps\servlets-examples\META-INF\aop.xml, since this is what we now provided in cvs head (and not in 0.10).

Once that done, nothing happened. I added some tracing stuff (-Daspectwerkz.transform.verbose=true) and figured out (with a bit of pain since toString() on Tomcat classloader is damned too much verbose..) that Tomcat classloader is not taking this META-INF topmost stuff into account.

I decided to move that to the WEB-INF/classes path, so ending up in webapps\servlets-examples\WEB-INF\classes\META-INF\aop.xml [file below]. I ll double check that later since this WEB-INF/.../META-INF is a bit strange there.

and here it is (once I browsed to http://localhost:8080/servlets-examples/)

METHOD_EXECUTION--> filters.ExampleFilter::doFilter
METHOD_EXECUTION--> HelloWorldExample::doGet
METHOD_EXECUTION<-- HelloWorldExample::doGet
METHOD_EXECUTION--> filters.ExampleFilter::toString
METHOD_EXECUTION<-- filters.ExampleFilter::toString
METHOD_EXECUTION<-- filters.ExampleFilter::doFilter
METHOD_EXECUTION--> filters.ExampleFilter::doFilter
METHOD_EXECUTION--> SessionExample::doGet
METHOD_EXECUTION--> listeners.SessionListener::sessionCreated
METHOD_EXECUTION--> listeners.SessionListener::log
METHOD_EXECUTION<-- listeners.SessionListener::log
METHOD_EXECUTION<-- listeners.SessionListener::sessionCreated
METHOD_EXECUTION<-- SessionExample::doGet
METHOD_EXECUTION--> filters.ExampleFilter::toString
METHOD_EXECUTION<-- filters.ExampleFilter::toString
METHOD_EXECUTION<-- filters.ExampleFilter::doFilter


<!DOCTYPE aspectwerkz PUBLIC
<system id="sample">
<aspect class="examples.logging.JavaLoggingAspect">
<pointcut name="pc" expression="execution(* *..*.*(..))"/>
<advice name="logMethod" type="around" bind-to="pc"/>

We are almost there and 1.0 will be damned good don't you think ?