Aspect-Oriented Programming and JBoss
Pages: 1, 2
Example 2. Using Metadata
The TracingInterceptor does not trace field access because it
is a bit too verbose. It is a common practice for developers to implement
get() and set() methods to encapsulate field access.
It would be nice if the TracingInterceptor could filter out and
not trace these methods. This example shows you how to use JBoss AOP metadata
to implement this filtering on a per-method basis. Usually, metadata is used
for more complex things like defining transaction attributes, per-method
security roles, or persistence mappings, but this example should be good enough
to illustrate how metadata could be used in an AOP-enabled application.
Defining Class Metadata
To add this filtering functionality, we will provide a flag that you can use
to turn tracing off. We will go back to our AOP XML file to define the tags
that will remove tracing for get() and set()
methods. Actually, it's kind of pointless to be tracing the main() function,
so let's filter that out, too.
<?xml version="1.0" encoding="UTF-8">
<aop>
<class-metadata group="tracing" class="POJO">
<method name="(get.*)|(set.*)">
<filter>true</filter>
</method>
<method name="main">
<filter>true</filter>
</method>
</class-metadata>
</aop>
The above XML defines a grouping of attributes called tracing.
The filter attribute will be attached to every method starting with get or set.
The regular expression format uses JDK-1.4-defined expressions. This metadata
can be accessed within the TracingInterceptor through the
Invocation object.
Accessing Metadata
For this metadata to be useful, it must be accessible at runtime. Class
metadata is accessible through the Invocation object. To make use
of it in our example, the TracingInterceptor must be modified a
tiny bit.
public class TracingInterceptor implements Interceptor
{
public String getName() { return TracingInterceptor; }
public InvocationResponse invoke(Invocation invocation)
throws Throwable
{
String filter = (String)invocation.getMetaData(tracing, filter);
if (filter != null && filter.equals(true))
return invocation.invokeNext();
String message = null;
if (invocation.getType() == InvocationType.METHOD)
{
Method method = MethodInvocation.getMethod(invocation);
message = method: + method.getName();
}
else if (invocation.getType() == InvocationType.CONSTRUCTOR)
{
Constructor c = ConstructorInvocation.getConstructor(invocation);
message = constructor: + c.toString();
}
else
{
// Do nothing for fields. Just too verbose.
return invocation.invokeNext();
}
System.out.println(Entering + message);
// Continue on. Invoke the real method or constructor.
InvocationResponse rsp = invocation.invokeNext();
System.out.println(Leaving + message);
return rsp;
}
}
Running Example 2
The POJO class has been expanded a bit to add get() and
set() methods.
public class POJO
{
public POJO() {}
public void helloWorld() { System.out.println(Hello World!); }
private int counter = 0;
public int getCounter() { return counter; }
public void setCounter(int val) { counter = val; }
public static void main(String[] args)
{
POJO pojo = new POJO();
pojo.helloWorld();
pojo.setCounter(32);
System.out.println(counter is: + pojo.getCounter());
}
}
The TracingInterceptor will intercept calls to
main(), POJO(), and helloWorld(). The
output should look like this:
Entering constructor: public POJO()
Leaving constructor: public POJO()
Entering method: helloWorld
Hello World!
Leaving method: helloWorld
You can download JBoss AOP and sample code here. To compile and execute:
$ cd oreilly-aop/example2
$ export CLASSPATH=.;jboss-common.jar;jboss-aop.jar;javassist.jar
$ javac *.java
$ java -Djava.system.class.loader=org.jboss.aop.standalone.SystemClassLoader POJO
Example 3. Using Introductions
It would be cool if we could turn tracing off and on for specific instances.
JBoss AOP has an API to attach metadata to an object instance, but let's
pretend an actual tracing API is a better solution. In this example, we'll
change the definition of the POJO class itself through the use of
an introduction. We will force the POJO class to implement a
tracing interface and provide a mix-in class that handles the new tracing API.
This will be the tracing interface:
public interface Tracing
{
public void enableTracing();
public void disableTracing();
}
Defining a Mix-in Class
The Tracing interface will be implemented in a mix-in class.
An instance of this mix-in class will be attached to the POJO
class when a POJO is instantiated. Here's the implementation:
import org.jboss.aop.Advised;
public class TracingMixin implements Tracing
{
Advised advised;
Public TracingMixin(Object obj)
{
this.advised = (Advised)obj;
}
public void enableTracing()
{
advised._getInstanceAdvisor().getMetaData().addMetaData(
"tracing", "filter", true);
}
public void disableTracing()
{
advised._getInstanceAdvisor().getMetaData().addMetaData(
"tracing", "filter", false);
}
}
The enableTracing() method attaches the filter
attribute to the object instance. The disableTracing() method
does the same, but turns the filter attribute to false. These two
methods are examples of how metadata can be applied to more than the class
level. That metadata can applied at the instance level, as well.
Attaching an Introduction
Okay, so we've defined the tracing interface and implemented the mix-in
class. The next step is to apply the introduction to the POJO
class. As for interceptors, we must define another pointcut in XML. Let's see
what this looks like.
<?xml version="1.0" encoding="UTF-8">
<aop>
<introduction-pointcut class="POJO">
<mixin>
<interfaces>Tracing</interfaces>
<class>TracingMixin</class>
<construction>new TracingMixin(this)</construction>
</mixin>
</introduction-pointcut>
</aop>
The above pointcut will force the POJO class to implement the
Tracing interface. Now, when an instance of POJO is instantiated, an instance of TracingMixin will also be
instantiated. The way TracingMixin is instantiated is defined
in the <construction> tag. You can put any one-line Java code
you want in the <construction> tag.
Running Example 3
The POJO class has been expanded a bit to show how the
Tracing API can now be accessed. The
TracingInterceptor hasn't changed from Example 2.
public class POJO
{
public POJO() {}
public void helloWorld() { System.out.println(Hello World!); }
public static void main(String[] args)
{
POJO pojo = new POJO();
Tracing trace = (Tracing)this;
pojo.helloWorld();
System.out.println("Turn off tracing.");
trace.disableTracing();
pojo.helloWorld();
System.out.println("Turn on tracing.");
trace.enableTracing();
pojo.helloWorld();
}
}
Notice that we can typecast POJO to the Tracing
interface. The output should look like this:
Entering constructor: POJO()
Leaving constructor: POJO()
Entering method: helloWorld
Hello World!
Leaving method: helloWorld
Turn off tracing.
Entering method: disableTracing
Leaving method: disableTracing
Hello World!
Turn on tracing.
Entering method: helloWorld
Hello World!
Leaving method: helloWorld
Notice that the interceptor-pointcut that added the
TracingInterceptor also applies to the methods introduced by the
Tracing introduction.
To compile and run this example:
$ cd oreilly-aop/example3
$ export CLASSPATH=.;jboss-common.jar;jboss-aop.jar;javassist.jar
$ javac *.java
$ java -Djava.system.class.loader=org.jboss.aop.standalone.SystemClassLoader POJO
Conclusions
Aspect-oriented programming is a powerful new tool for software development. With JBoss 4.0, you can implement your own interceptors, metadata, and introductions, to make your software development process more dynamic and fluid. Come visit us at www.jboss.org for more detailed documentation. There are a few surprises waiting for you, as we've implemented a suite of services on top of our new framework. Have a look and happy coding.
Bill Burke is a Fellow at the JBoss division of REd Hat Inc. A long time JBoss contributor and architect, his current project is RESTEasy, RESTful Web Services for Java.
Adrian Brock is Director of Support for JBossGroup, LLC.
Return to ONJava.com.
- Trackback from http://www.bejug.org/confluenceBeJUG/display/BeJUG/AOP+Workshop
AOP Workshop
2004-09-29 14:51:17 [View]
-
THIS ARTICLE IS OUT OF DATE
2004-08-25 18:51:36 Bill Burke |
[View]
-
THIS ARTICLE IS OUT OF DATE
2004-06-23 14:14:42 Bill Burke |
[View]
-
Pros and cons
2004-02-19 08:32:47 fabcar [View]
-
Pros and cons
2004-02-19 08:53:43 patriot1burke [View]
-
Running examples in Eclipse.
2004-01-20 09:16:26 anonymous2 [View]
-
Comments on Article
2003-12-30 15:32:58 anonymous2 [View]
-
it's not intercepting!! - just Hello World!
2003-11-28 13:12:06 anonymous2 [View]
-
it's not intercepting!! - just Hello World!
2003-12-16 14:06:26 anonymous2 [View]
-
the example does'nt execute
2003-10-08 00:17:56 anonymous2 [View]
-
the example does'nt execute
2003-10-08 05:36:29 anonymous2 [View]
-
source syntax errors
2003-10-07 11:44:02 anonymous2 [View]
-
more details
2003-06-10 12:05:53 anonymous2 [View]
-
This is total nonsense.
2003-08-27 15:21:46 anonymous2 [View]
-
Uncompatible with J2EE
2003-06-06 00:32:00 anonymous2 [View]
-
Uncompatible with J2EE
2003-06-30 07:03:43 patriot1burke [View]
-
Uncompatible with J2EE
2003-06-30 06:55:30 anonymous2 [View]
-
A bit of concern around this AOP framework implementation.
2003-06-05 19:12:54 vlovsky [View]
-
Performance
2003-06-04 06:29:37 anonymous2 [View]
-
Performance
2003-06-04 06:42:27 anonymous2 [View]
-
access method return value
2003-06-03 09:15:52 anonymous2 [View]
-
access method return value
2003-06-03 09:25:28 anonymous2 [View]
-
access method return value
2003-06-03 09:21:43 patriot1burke [View]
-
access method parameters
2003-06-03 08:15:50 anonymous2 [View]
-
access method parameters
2003-06-03 08:31:11 anonymous2 [View]
-
Why inventing new AOP and not using existing one?
2003-06-03 00:04:05 mszklano [View]
-
Why inventing new AOP and not using existing one?
2003-06-03 07:52:34 patriot1burke [View]
-
Co-existence of JDO and JBoss AOP?
2003-06-02 19:01:58 tomdavies [View]
-
Co-existence of JDO and JBoss AOP?
2003-06-03 09:27:04 patriot1burke [View]
-
For those skeptics...
2003-05-30 23:58:46 anonymous2 [View]
-
Logging and tracing code
2003-05-29 11:03:41 anonymous2 [View]
-
Logging and tracing code
2003-05-29 11:10:37 warjort [View]
-
Logging and tracing code
2003-05-29 14:22:58 anonymous2 [View]
-
Logging and tracing code
2003-05-29 15:24:12 warjort [View]
-
Logging and tracing code
2003-05-29 16:23:22 anonymous2 [View]
-
Production
2003-05-30 09:26:43 anonymous2 [View]
-
Production
2003-05-30 09:40:03 anonymous2 [View]
-
Answering your well-founded skeptism
2003-05-29 20:29:01 patriot1burke [View]
-
Your code doesn't compile . . .
2003-05-29 09:09:35 sammefford [View]