Aspect Oriented Programming (AOP) with .NET and J2EE
by Thomas GIL (thomas.gil@dotnetguru.org)


Introduction

Functional, structured, object oriented programming... The last decades brought many developments and mutations in the way we design and program. And to be honest, the last step (to the Object world) will still take some time since the conceptual gap to cross is quite important.

Anyway, enthusiasts and people who constantly watch technological evolutions will ask : “what's next ?” What is still to be invented, what can we improve in the way we design and code ? Well, according to us, the next big mutation will be the one of Aspect Oriented Programming (AOP).

This article is first an introduction to ideas and motivations which lead to aspect oriented programming. We'll give the context and some definitions, and then we'll have a look at available tools; this will go through a selective panorama of both C#/.NET and Java/J2EE environments, according to our tradition on DotNetGuru.

As a conclusion to this file, we'll go down in the conceptual layers and take an interest in primitive tools that allow to generate and to analyse Java or C# code. The aim will be both to give you the ability to take advantage of those tools in your own projects, and who knows, maybe to implement your own “aspect weaver” (more on this later).

Motivations and definition of Aspect Oriented Programming (AOP)

What's the aim of AOP ?

Everything comes from a simple statement : whatever the way we develop, we never manage not to write redundant code. You can be a code or a design guru, be it in procedural programming, functional, by constraint, by predicate, ruled-based or even in object oriented programming, there will always be a situation when you'll have to write repetitive things to manage some recurrent needs.

Let's give some examples, all coming from the Object world. How could we handle the following needs without writing two times the same code :

Object oriented programming will help us to put in factor what other kinds of programming force us to repeat through the code of our projects.

The kind of problem targeted by AOP

The following example is very well known in the Java AOP world and illustrates the problem : in the code of Tomcat JSP/Servlet engine, some technical needs are very localized (reading configuration files, XML parsing), some other are spread over a few classes (HTTP requests management, regular expressions), but there are still other features that are located nearly everywhere in the code (for example : calling the log framework to be able to diagnose problems that occur, as well as to keep a trace of the requests the server handles).



Figure A : Distribution of the code that manages some features in the Tomcat Web Server

If unfortunately (for the Tomcat project) the log framework evolves, many changes would have to be made, spread over nearly all the code. We can imagine two solutions to this crisis situation :

Is AOP limited to Object Oriented programming languages ?

No, since the problem we just described isn't new at all. It already existed when we developed in procedural languages. In fact, it was even worse since we couldn't use inheritance !

Hence, it is absolutely legal to think of using AOP in C, Cobol... And some developers already did it in fact : development teams of the FreeBSD Open Source operating system. The OS is written in C of course, and AOP has been introduced to handle in a uniform way the data pre-fetching”. The tool they used is named AspectC, which is in a re-implementation phase itself : FreeBSD teams have been delighted by the opportunities provided by this tool, and have wished to enhance it in order to implement other aspects in their system.

AOP definition

To sum up, aspect oriented programming is a new technique to put in factor some responsibilities whose implementation is a priori spread over a whole system, be it object oriented.

Nota bene : an AOP synonym that you'll necessarily meet while browsing on the Web is AOSD (for Aspect Oriented Software Development). The reference web site in this domain is http://aosd.net. And as soon as you get to the first page, you'll find a definition for AOP : Aspect-oriented software development is a new technology for separation of concerns (SOC) in software development. The techniques of AOSD make it possible to modularize crosscutting aspects of a system.

Concrete implementations of AOP

Two different approaches can implement the nice concept of AOP. The first one will be to separate aspects from the code on which we want to apply them (code that we'll name the “base code”). A third party language enables us to explicit the relationships between the base code and the aspects. Flexible and very powerful, this approach is sometimes judged as “a bit too magic” : the developer of one particular class may be amazed to see it behave differently from what she has really written, and will constantly wonder “which aspect has been applied to my class ?”. Hence, we'll need efficient traceability tools. AspectJ follows this approach, and since this project is well appreciated and marketed, this approach tends to become “the AOP way”.

Another option would be to develop aspects, and then to “mark” the code using an adapted syntax. The advantage is that the relationship between base code and aspects becomes explicit, and then developers never wonder whether they have to implement a feature or if an aspect will take it in charge : they see which aspects they invoke (which doesn't free them from knowing what the aspects semantics are). This second approach is followed by Microsoft with the introduction of standard .NET Attributes, and by some code generation tools like Xdoclet in Java. The question is : is it still AOP... well, this is a real debate that you can read on the web.

The next sections will present both techniques and give examples of implementations in Java/J2EE as well as in C#/.NET.

.NET Attributes and interceptors

Example of a standard Attribute

[In the whole article, we will go on using the Attribute word for the AOP oriented syntax, and “field” for the attributes of our classes]

Whatever the language they have chosen, nearly every .NET developer already has manipulated .NET Attributes : it is about those little markers we put as declaration headers (they can precede methods, classes, fields, namespaces...) and that enhance these declarations. The simplest example is the one of conditional compilation : suffices to prefix a method declaration by the Attribute [Conditional(“COMPILATION_VAR”)] so that the compiler makes every call to this method conditional (depending on the presence of the COMPILATION_VAR). A simple example will refresh our memory :

#define DEBUG

namespace AOP {

using System;

using System.Diagnostics;
public class ConditionalTest {
[Conditional("DEBUG")]
public static void DisplayTrace(string msg)
{
Console.WriteLine(msg);
}
public static void Main()
{
DisplayTrace("In the Main() method");
}
}
}

TestConditional.cs

In this example, we defined the DEBUG variable right in the code, but of course in a real project we'd do that in the project properties or in the compiler's command line properties. This way, we could choose a global compilation mode for the whole project, and in RELEASE mode we could execute only the really required code.

We can say that this constitutes our first Aspect : a recurrent and coherent behavior (to execute or not to execute a method's body) is applied to all the methods that are marked by the [Conditional] Attribute.

Remark : for those who read about the [Conditional] Attribute for the first time in this article, please note that the methods you'll mark this way must return void, and they mustn't have any side effect; otherwise their conditional compilation would have an impact on the basic behavior of the program.

Defining custom Attributes

To enhance the semantic of .NET syntactic elements is nice. It would be a pity if this possibility would be only accessible to the framework itself ! Hopefully, it isn't the case : we can develop our own Attributes and we can associate them to any kind of elements in the programming language we use (C#, VB.NET...). How ? That's pretty simple : an Attribute is... a class that inherits from System.Attribute.

For example, suppose we want to “mark” some classes in an object model as persistent classes (in a database). We would start by defining the AutomatiquePersistence Attribute :

namespace AOP {

[System.AttributeUsage( System.AttributeTargets.Class)]
public class AutomaticPersistenceAttribute : System.Attribute{
private
bool lazyLoading;
private
string mappingName;
public
AutomaticPersistenceAttribute (string mappingName){this.mappingName = mappingName;}
public string MappingName {get{return mappingName;}}
public bool LazyLoading{get{ return lazyLoading;}set{ lazyLoading = value;}}
}
}

AutomaticPersistenceAttribute.cs

The general naming convention is to suffix this kind of class by the “Attribute” word, so that we can easily distinguish Attribute classes from standard classes. .NET compilers as well will expect your Attributes to be named this way.

On the other hand, you'll notice that the AutomaticPersistenceAttribute is marked itself by a standard Attribute : AttributeUsage. This enables the compiler to check that our attribute will only be used on the targeted syntactic elements – in our example, we limited the applicability of the AutomaticPersistenceAttribute to classes. Hence, it would be illegal (and the compiler will insult us) to apply it to a method, a struct or a namespace.

Well. Our Attribute being developed, let's apply it to a business class (a ShoppingCart for example) :

namespace AOP {

[AutomaticPersistence("ShoppingCart", LazyLoading = true )]

public class ShoppingCart{

// ...

}

}
ShoppingCart.cs

The syntax we used between brackets looks like a call to the constructor of our AutomaticPersistenceAttribute. In fact, it's exactly what happens, at least for the first parameter. As you probably have guessed, the second one corresponds to the invocation of the setter of the LazyLoading property.

This raises two questions :

Aswering the first question is trivial, we simply have to analyze the assembly that contains our ShoppingCart class using the ILDASM.exe tool [Translation : in French, ShoppingCart is called “CaddieVirtuel”] :



Figure B : Contents of an assembly whose classes are marked by Attributes

The truncated value on the right side of the Figure B corresponds to the “ShoppingCart” that we provided between quotes in the C# code. The data we provide to Attributes are stored in the assembly that calls those Attributes.

And to understand when the constructor of AutomaticPersistenceAttribute will really be called, we propose to add a simple System.Console.WriteLine("In the constructor of PersistanceAutomatiqueAttribute");.

Then, we'll implement two tests. The first one will be to instanciate the ShoppingCart class :

namespace AOP {

public class PersistenceManager {

public static void Main(string[] args){

ShoppingCart cart = new ShoppingCart();

}

}

}

PersistenceManager.cs

Result ? Nothing appears on the console. The constructor of our AutomaticPersistenceAttribute hasn't been invoked.

Second try : let's use .NET Reflection to read the meta-data of the VirtualCart class :

namespace AOP {

public class GestionnairePersistance{

public static void Main(string[] args) {

CaddieVirtuel cad = new CaddieVirtuel();

foreach (System.Attribute a in cad.GetType().GetCustomAttributes(true)) {

if (a is PersistanceAutomatiqueAttribute){

PersistanceAutomatiqueAttribute paa =

a as PersistanceAutomatiqueAttribute;

System.Console.WriteLine(paa.NomMapping);

System.Console.WriteLine(paa.LazyLoading);

}

}

}

}

}

GestionnairePersistance.cs

This time, the results is more expressive :



Figure C : The results when we use Reflection on a class that is marked by AutomaticPersistenceAttribute

So the constructor of a custom Attribute is invoked when we read it thanks to .NET reflection.

Conclusion : Attributes can mark specific locations in the .NET code and can associate meta-data to this mark (stored in the Assembly). But the behavior of an Attribute is... to do nothing till anyone uses reflection on it. Hence, this mechanism can be useful (classes using Reflection can get the meta-data) but not sufficient to implement real Aspects : indeed, how could we install some code before and after the invocation of methods on an object ? How to add a method to a class ? It seems impossible... At least, we lack an element to reach this goal.

.NET interceptors

Maybe you remember the articles Sami Jaber published about the .NET Remoting framework. It was about clients and servers, proxies and skeletons, channels, messages and MessageSink. We'll take advantage of a part of this infrastructure to put an interceptor between our business object ans its client.

Without getting into deep details (that you can read here), suffices to understand that :



Figure D : .NET interception infrastructure

Hence, it would be enough to install a custom MessageSink before every business object in order to be able to trigger code before and after methods invocations or even attributes access. This technique is very powerful... and we propose to lead you to put it in practice through a simple example : an interceptor that will count the number of access (methods invocations, attributes access) on a target object.

namespace AOP {

using System;

using System.Runtime.Remoting.Activation;

using System.Runtime.Remoting.Contexts;

using System.Runtime.Remoting.Messaging;

// Our interceptor

public class DNGAspectCompteur : ImessageSink{

private int nbHits;

private IMessageSink suivant;

public DNGAspectCompteur(IMessageSink suivant){

this.suivant = suivant;

}

public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink msgSink) {

throw new Exception("Pas implémenté");

}

public IMessageSink NextSink {

get{ throw new Exception("Pas implémenté"); }

}

public IMessage SyncProcessMessage(IMessage msg) {

IMessage resultat = null;

nbHits++;

// We could put some code before the invocation
resultat = suivant.SyncProcessMessage(msg);

// We could put some code after the invocation

return resultat;

}

~DNGAspectCompteur() {

Console.WriteLine ("Nombre total d'accès à l'objet : {0}", nbHits);

}

}

}

DNGAspectCompteur.cs

As for the target object, there is no complexity except that it must inherit from ContextBoundObject.

namespace AOP {

using System;

[DNGCompteur]

public class DNGObservable : ContextBoundObject{

public int i = 5;

public void Test(){

Console.WriteLine("dans test");

}

public static void Main(){

DNGObservable o = new DNGObservable();

o.i = 4;

o.Test();

o.i = 5;

}

}

}

DNGObservable.cs

As you have probably guessed, we associate our interceptor (DNGAspectCompteur) to the DNGObservable class thanks to the [DNGCompteur] Attribute. And here is the most tricky part : the DNGCompteur Attribute is a bit special, since it has to be triggered automatically (it is out of question to way for some other object to come and read our Attribute using Reflection !). This is only possible if :

  1. The Attribute inherits from ContextAttribute instead of Attribute

  2. The target object must inherit from ContextBoundObject, otherwise our Attribute wouldn't be awakened automatically.

Let's go : here is the code we have to write to associate our Attribute (DNGCompteur) to the interceptor (DNGAspectCompteur):

namespace AOP {

using System;

using System.Runtime.Remoting.Activation;

using System.Runtime.Remoting.Contexts;

using System.Runtime.Remoting.Messaging;

// Factory d'intercepteurs

public class DNGAspectCompteurProperty :

IContextProperty, IcontributeObjectSink{

public IMessageSink GetObjectSink (System.MarshalByRefObject o, IMessageSink next) {

return new DNGAspectCompteur(next);

}

public void Freeze(Context ctx){}

public bool IsNewContextOK(Context ctx){return true;}

public string Name{get{return "dngproperty";}}

}

// Installe la factory d'intercepteurs dans l'infrastructure d'interception .NET

[AttributeUsage(AttributeTargets.Class)]

public class DNGCompteurAttribute : ContextAttribute {

public DNGCompteurAttribute() : base("dngcontext"){}

public override void GetPropertiesForNewContext(IConstructionCallMessage ccm) {

ccm.ContextProperties.Add(new DNGAspectCompteurProperty ());

}

}

}

DNGObservable.cs

To better understand the previous code, let's play the role of the CLR, and start at the Main method:

Once everything is initialized, we get back to the Main method :

To simplify our example, we didn't talk about the possibility to invoke the target object's methods asynchronously... but as you have read in the code, it wouldn't be very different from what we have shown.

Attributes + Interceptors = Aspect ?

What we call an Aspect (we'll come back on this terminology in the AspectJ presentation below) corresponds to the fact of applying a set of Advice (code enhancements) to a set of elements in the base code (typically to a set of classes).

Using ContextAttributes to install MessageSink interceptors answers a part of the problem : the assignment of aspects to syntactic elements we want to enhance. But we still have to link MessageSinks to the additional code we want to trigger before and after accessing the target objects (the advice).

On this point, many ideas come to our minds :

It is exactly the way CLAW works. Unfortunately, this tools isn't supported any more by its author, John Lam (check his weblog to understand why)

Our point of view

Using Attributes and MessageSinks is pretty simple, it is sexy, and completely integrated to the .NET Framework. Unfortunately, it brings some drawbacks :

To conclude, this technique is acceptable :

According to us, this is unfortunately not the best technique to implement AOP in .NET. However, we wanted to explain it precisely both to satisfy your curiosity and so that you can understand the grounds of our preference for the “AspectJ” like tools.

The Java Xdoclet

No panic : the aim isn't to present this tool, which is well known in the Java world and that generates code and deployment descriptors for EJB, Servlets and JSP. To read such a prose, we forward you to the official XDoclet Web site.

No, we only want to draw your attention to the fact that the XDoclet approach in Java is very close to using Attributes in .NET, at least in a syntactic point of view. On the XDoclet front page, they speak about “Attribute Oriented Programming”...

A reminder on how Doclets work

For those who haven't programmed in Java for too long, remember : it is possible to put some special comments just before declaring packages, classes, methods and fields. Those comments are named “JavaDoc comments”. As we can guess, those comments initially aimed at generating (HTML) documentation automatically. But nothing prevents us to rely on the same mechanism to generate other kinds of files, and why not code !? The only things to do are :

The rest, ie going through the Java code to look for JavaDoc comments, is fully automated by the associated tool : javadoc.exe. And thanks to a command line option, we can tell it which Doclet to use to interpret special comments.

Developping an EJB using Xdoclet

Developing Enterprise JavaBeans without a tool is heavy, repetitive and boring. Because we have to produce many files (Java classes, XML configuration files) in which there are many redundancies :

Well, the times when we had to produce those files manually is bygone. Today, most of EJB developers use either a code generation tool based on UML (such as Together Control Center for example), or the XDoclet. We can't resist to the pleasure to give you a little example of a Java class, enhanced by the required JavaDoc tags to generate all the related files. This example is taken from a little project that manages courses in a training company... :

package beans;

import java.util.Collection;

import javax.ejb.*;

import javax.naming.InitialContext;

import util.XHome;

/** 

* @ejb.bean type="CMP" view-type="local" primkey-field = "id"

* schema="Course" name="Course" local-jndi-name="beans/Course" 

* @ejb.finder signature = "java.util.Collection findAll()"

* @ejb.finder signature = "beans.CourseLocal findByCode(java.lang.String code)" 

* query = "SELECT OBJECT(c) FROM Course c WHERE c.code = ?1"

* @ejb.pk class = "java.lang.Integer"

*/

public abstract class CourseBean implements EntityBean {/**

* @ejb.pk-field 

* @ejb.persistent-field

* @ejb.interface-method */

public abstract Integer getId();

public abstract void setId(Integer id);

/**

* @ejb.persistent-field

* @ejb.interface-method */

public abstract String getCode();

/** @ejb.interface-method */

public abstract void setCode(String code);

/** 

* @ejb.persistent-field

* @ejb.interface-method */

public abstract int getDuration();

/** @ejb.interface-method */

public abstract void setDuration(int duration);

/** 

* @ejb.persistent-field

* @ejb.interface-method */

public abstract String getDurationUnit();

/** @ejb.interface-method */

public abstract void setDurationUnit(String durationUnit);

/** 

* @ejb.persistent-field 

* @ejb.interface-method */

public abstract String getLabRatio();

/** @ejb.interface-method */

public abstract void setLabRatio(String labRatio);

/** 

* @ejb.persistent-field

* @ejb.interface-method */

public abstract String getLanguage();

/** @ejb.interface-method */

public abstract void setLanguage(String language);

/** 

* @ejb.persistent-field

* @ejb.interface-method */

public abstract String getTitle();

/** @ejb.interface-method */

public abstract void setTitle(String title);

/** @ejb.relation name="Course-Objectives"

* role-name="Course-Has-Objectives" 

* target-ejb="Objective"

* @ejb.interface-method */

public abstract Collection getObjectives();

/** @ejb.interface-method */

public abstract void setObjectives(Collection objectives);

/** @ejb.create-method */

public Integer ejbCreate() throws CreateException {

setId(XHome.getNewPK("Course"));

return null;

}

public void ejbPostCreate() {}

public void setEntityContext(EntityContext context) {}

public void unsetEntityContext() {}

public void ejbRemove() {}

public void ejbLoad() {}

public void ejbStore() {}

public void ejbActivate() {}

public void ejbPassivate() {}

}

CourseBean.cs

You'll say “what's the relationship with Aspect Oriented Programming ?”. Well a priori not too much. But if you get closer, this principle looks like using Attributes and interceptors in .NET :

This idea was close enough in our opinion to deserve being mentioned in an AOP article.

AspectJ

Let's change approaches. After seeing how to use Attributes or JavaDoc comments to decorate code in order to enhance it using intelligent interceptors, we'll focus on AspectJ, whose philosophy advocates a pure separation of the aspects code from the “base” code.

Introduction

AspectJ is a pretty ambitious project that aims at defining and applying aspects on Java classes. This project has been linving on its own for a long time, but it is now supported by the eclipse.org community. Hence, you'll find the last versions of the tool as well as a plug-in to use it from Eclipse on this site.

AspectJ isn't the only AOP available in the Java world, as you'll see on this tools review. However, it is probably the most advanced and well-known one. Its definitions are accepted by AOP actors, and are taken as “biblical definitions” by the other tools of the same domain (that we'll see later in the .NET world). Then, we propose to have a look at a short glossary :


Keyword

Definition

Advice

A piece of code (in Java for AspectJ) that is doomed to be inserted into classes of the “base” code. One advice can be associated to a whole set of locations in the code.

Joinpoint

Identification of a location in the “base” code wherer we'll be able to insert advice. In fact, it is not really a location, but more of a moment, an special event. For example, the moment when a constructor or a method is called, when a field is accessed...

Pointcut

A pointcut is a precision on a Java event : it allows to identify the invocation of one particular method, on instances of one particular class...

AspectJ supports wildcards (* and ..) to identify a set of interception locations in a very precise way.

It is also possible to define custom pointcuts, that's to say to name a group of interception locations, in order to simplify the applying of an advice on many locations of the base code.

Aspect

An aspect groups :

  • Definitions of named interception locations

  • Associations of interception locations to advice

  • Introduction of fields or methods into the base classes

Every aspect is stored in a file named à la Java (same name as the aspect, plus a .java extension) located in a standard package. It really looks like a class, except that the keyword is aspect (of course).

Weaver

A compiler that applies (or introduces) aspects to the base code

AspectJ behavior is very simple : nearly everything happens during project compile time. The compilation order is the following :

So at runtime, we execute a bytecode which has been compiled after the aspect weaving. A priori, noting is specific to AspectJ in the code we execute, hence we don't have to put anything in the CLASSPATH. In practice, when we develop more subtle Advice (that use introspection to know on which syntactic element they are applied), we'll need to add a little library (aspectjrt.jar) of 29 ko.

AspectJ in practice

It is possible to use the AspectJ weaver in a command prompt and to develop aspects using any text editor. This will probably be the preferred way for Vi, (X)Emacs, UltraEdit or Nedit fans.

Another technique : AspectJ comes with a graphical aspect browser. Here is a little snapshot of this tool (don't pay attention to the aspect that is open, we'll come back on it later).



Figure E : AspectJ Browser

But the most interesting way is probably to use the Aspect Plug-in, specifically developed for Eclipse. It allows to :

In practince, we found this plug-in quite stable and very well integrated to the Eclipse IDE habits. For example, an aspect compilation error appears as a red little bullet in the margin and in the tasks list, exactly like a standard Java compilation error.

An iterative example

To illustrate this presentation of AspectJ, we propose to write an aspect that will count the number of access to an instance of a Java class, just like we did in the “.NET Attributes and interceptors” section.

1. Accessing methods

Let's start creating an aspect named DNGCompteur. Then we add a pointcut to tell AspectJ where we want to trigger code.

package org.dng.aop.aspects;

public aspect DNGCompteur {

pointcut invocationMethodes():

call(* org.dng.aop..*.*(..)) && !within(DNGCompteur);

before(): invocationMethodes() {

System.out.println("Avant l'acces a une methode");

}

}

}

DNGCompteur.java

The literal translation of this aspect is something like : before() each method call() on an instance of a class located in the package org.dng.aop or in any sub-package (org.dng.aop..*.*), except in invocations that would occur inside the DNGCompteur itself ( !within(DNGCompteur) ), we want to invoke the Advice System.out.println("Avant l'acces a une methode");.

We put the constraint !within(DNGCompteur) to avoid any recursive method invocation...

The following code shows the base code on which we'll apply the preceding aspect :

package org.dng.aop.base;

public class Observable {

private int valeur;

public void test(){

System.out.println("Dans la methode test de Observable");

}

public int getValeur() {

return valeur;

}

public void setValeur(int valeur) {

this.valeur = valeur;

}

}

/******/

public class Test {

public static void main(String[] args) {

Observable obs = new Observable();

obs.test();

System.out.println( obs.getValeur() );

}

}

Observable.java et Test.java

You have noticed that this code is totally naive : it doesn't expect what's going to happen to it. However, after weaving the DNGCompteur aspect, launching the Test.main method gives the following result :





Figure F.1 : Access counter

Our Advice has a problem : it isn't capable of saying which method is going to be called. To resolve this, it has to use a special kind of introspection using a “magic” object provided by AspectJ : the JoinPoint representation.

Let's modify our aspect :

package org.dng.aop.aspects;

public aspect DNGCompteur {

pointcut invocationMethodes():

call(* org.dng.aop..*.*(..)) && !within(DNGCompteur);

before(): invocationMethodes() {

System.out.println("Avant l'acces a une methode\n\t" + thisJoinPoint);

}

}

DNGCompteur.java

Which has the following impact :



Figure F.2 : Access counter



2. Accessing fields

Following the same logic, we could weave an aspect to the fields access. You know the principle :

package org.dng.aop.aspects;

public aspect DNGCompteur {

pointcut sollicitationQuelconque():

(call(* org.dng.aop..*.*(..)) ||

get(* org.dng.aop..*))

&& !within(DNGCompteur);

before(): sollicitationQuelconque() {

System.out.println ("Avant l'acces a : \n\t " + thisJoinPoint);

}

}

}

DNGCompteur.java

No surprise, the result also counts fields access on the Observable object (read access only thanks to get() ) :



Figure F.3 : Access counter



3. Adding a field and a getter for our counter

For the moment, we only react to method invocations and fields access. How to enhance our example to count the number of access on one particular object (here, an Observable) ?

You'll say : “if anyone has to bear this responsibility, it must be the Observable object itself”. I totally agree. But it wasn't designed in this perspective... Anyway, we'll use another feature of AspectJ named “Introduction” that will allow us to add a new field to the Observable class as well as a getter to read and display this field value at the end of our program.

package org.dng.aop.aspects;

public aspect DNGCompteur {

private int org.dng.aop.base.Observable.compteurHits;

public int org.dng.aop.base.Observable.getCompteurHits(){

return compteurHits;

}

pointcut sollicitationQuelconque():

(call(* org.dng.aop..*.*(..)) ||

get(* org.dng.aop..*))

&& !within(DNGCompteur);

before(): sollicitationQuelconque() {

System.out.println ("Avant l'acces a : \n\t " + thisJoinPoint);

}

}

}

DNGCompteur.java

Since we are curious, we wanted to have a look at the modifications the weaving made on the Observable class. To do so, we simply decompiled it using jad. The result is self-explanatory :

// Decompiled by Jad v1.5.7f. Copyright 2000 Pavel Kouznetsov.

// Source File Name: Observable.java

package org.dng.aop.base;

import java.io.PrintStream;

import org.aspectj.runtime.reflect.Factory;

import org.dng.aop.aspects.DNGCompteur;

public class Observable{

public Observable(){

DNGCompteur.ajc$interFieldInit$org_dng_aop_aspects_DNGCompteur$org_dng_aop_base_Observable$compteurHits(this);

}

public void test(){

System.out.println("Dans la methode test de Observable");

}

public int getValeur(){

Observable observable = this;

Object aobj[];

org.aspectj.lang.JoinPoint joinpoint = Factory.makeJP(ajc$tjp_0, this, observable, aobj = new Object[0]);

DNGCompteur.ajc$perSingletonInstance.ajc$before$org_dng_aop_aspects_DNGCompteur$154(joinpoint);

return observable.valeur;

}

public void setValeur(int arg0){

valeur = arg0;

}

public int getCompteurHits(){

}

private int valeur;

public int ajc$interField$org_dng_aop_aspects_DNGCompteur$compteurHits;

public static final org.aspectj.lang.JoinPoint.StaticPart ajc$tjp_0;

static {

Factory factory = new Factory("Observable.java", Class.forName("org.dng.aop.base.Observable"));

ajc$tjp_0 = factory.makeSJP("field-get", factory.makeFieldSig("2-valeur-org.dng.aop.base.Observable-int-"), 11);

}

}
}

Observable.jad, decompiled after the weaving of DNGCompteur

As we can see, DNGCompteur is used to insert Advice, but that the field itself is really located in the Observable class.

4. Incrementing the counter and getting its final value

What remains to be done ? To increment this new field we introduced in the Observable class in our Advice. To do so, the instance of Observable on which we want to work (compteurHits) must be declared in the pointcut, otherwise it wouldn't be accessible from the associated advice :

package org.dng.aop.aspects;

public aspect DNGCompteur {

private int org.dng.aop.base.Observable.compteurHits;

public int org.dng.aop.base.Observable.getCompteurHits(){

return compteurHits;

}

pointcut sollicitationQuelconque(org.dng.aop.base.Observable o):

(call(* org.dng.aop..*.*(..)) ||

get(* org.dng.aop..*))

&& !within(DNGCompteur)

&& target (o);

before(org.dng.aop.base.Observable o): sollicitationQuelconque(o) {

o.compteurHits++;

System.out.println("Nombre hits : "+o.compteurHits);

}

}

DNGCompteur.java

The result makes no surprise :



Figure F.4 : Access counter

However, it is interesting to note that in the base code, the compteurHits field and its getter become accessible ! Which means it is legal to invoke obs.getCompteurHits(), even though this method hasn't been declared in the Observable class !

Summary

AspectJ is very simple to manipulate and proves to be a very powerful tool. After this little usage example, we can ask to ourselves which kind of need can be answered by this tool :

There are many example, and you'll probably find innovative AOP applications on your own projects !

AspectC#, Weave.NET, [AspectDNG ?]

The problem

One question comes to everybody's mind : “is there an equivalent of AspectJ in the .NET world ?”

Unfortunately, the answer is no. Some projects have started, such as Weave.NET, AspectC#... but the are still at the early stages of development.

AspectC# seems to be the one that seems ahead of the other is the result of a very interesting student thesis that you can read here, and that has been continuated by Donal Lafferty. AspectC# is downloadable for free. It is a simple command-line weaver that reads an XML configuration file to associate aspects to base code. But this product is quite limited for the moment : it doesn't propose any JoinPoint on field access for example, not anything for delegates, structs, Attributes... It is still in alpha version, and its web page isn't very confident in the pace of the development to come... Well we are far away from the comprehensiveness, the support and the permanence of AspectJ.

Hence, we feel a bit of frustration : we are at the beginning of a new software development era, and we cannot try AOP because no tool is available on the .NET platform.

The idea

DotNetGuru would like to follow the AOP trend today and provide you with the benefits of our adhesion to this move. Sami Jaber and me have the wish to develop our own aspect weaver (let's call it AspectDNG) and to put its code into LGPL licence.

But as you know, it wasn't DotNetGuru's first objective (or role) to develop tools on the .NET platform. Hence, we would like you to give us some feedback to determine if :

Well, the question is open... It is up to you to decide. You wish is to answer your needs at best, hence it is your responsibility to tell us if this project would have the same added value as the articles we could write instead of developing AspectDNG.

The decision will be taken in some time, depending on the global trend we'll get in the comments of this article. Let's say that the decision will be taken in a purely democratic way, a way we would like the world to follow...

Code generation tools

For anyone who could be interested by...

... we would like to take a tour of the different techniques that the .NET platform proposes in this domain.

Emit

System.Reflection.Emit is a standard API in the .NET framework that enables to generate MSIL code on the fly. It is a very useful tool if you want to create a compiler (a PHP to MSIL compiler for example), but it prooves to be tool low level in the scope of code generation or, more generally, code management.

CodeDom

System.CodeDom is another interface, a higher level one, whose objective is to stand for an abstract syntactic tree (an AST) in form of .NET objects. As you can imagine, CodeDom is to .NET code what the DOM is for XML documents.

The biggest advantage of CodeDom is to be completely abstract, and completely independent from any programming language. This memory representation will then be transformable into C#, VB.NET or any other .NET language supposing we have the right code generator.

A little example will give us an idea of the abstraction level with CodeDom :

namespace AOP {

using System;

using System.CodeDom;

using System.CodeDom.Compiler;

public class CodeDom {

public static void Main(string[] args){

// Unité de compilation ou de génération 

codeCodeCompileUnit ccu = new CodeCompileUnit();

// Nouveau namespaceCodeNamespace 

ns = new CodeNamespace("DngNamespace");

ccu.Namespaces.Add(ns);

// Nouvelle classe

CodeTypeDeclaration c = new CodeTypeDeclaration("DngClass");

ns.Types.Add(c);

c.IsClass = true;

// Nouvelle méthode

CodeEntryPointMethod m = new CodeEntryPointMethod();

c.Members.Add(m);

// Première manière d'ajouter une instruction

CodeMethodInvokeExpression expr =

new CodeMethodInvokeExpression ( new CodeTypeReferenceExpression("System.Console"),

"WriteLine", new CodePrimitiveExpression("Hello World!") );

m.Statements.Add(new CodeExpressionStatement(expr));

// Seconde manière, quasiment équivalents

m.Statements.Add(new CodeSnippetStatement("System.Console.WriteLine(\"Hello\");")); 

// Génération de codeCodeDomProvider comp;

// C#

comp = new Microsoft.CSharp.CSharpCodeProvider();

comp.CreateGenerator().GenerateCodeFromCompileUnit

(ccu, Console.Out, new CodeGeneratorOptions());

// VB.NET

comp = new Microsoft.VisualBasic.VBCodeProvider();

comp.CreateGenerator().GenerateCodeFromCompileUnit

(ccu, Console.Out, new CodeGeneratorOptions());

}

}

}

DNGCompteur.java

The result seems satisfying :

C#

namespace AO {

namespace DngNamespace {

public class DngClass {

public static void Main() {

System.Console.WriteLine("Hello World!");

System.Console.WriteLine("Hello");

}

}

}

}

VB


Option Strict Off

Option Explicit On

Namespace DngNamespace

Public Class DngClass

Public Shared Sub Main()

System.Console.WriteLine("Hello World!")

System.Console.WriteLine("Hello");

End Sub

End Class

End Namespace


A code generated by System.CodeDom

But if you look closer, using a literal line of code in our code generator proves to be fatal in VB.NET. Indeed, the semi-colon at the end of the instruction doesn't respect the VB.NET syntax. Ok, it seems that if we really want to use CodeDom to generate code in multiple languages, we'll have to use the abstraction classes instead of generating text through a “snippet”.

CodeDom seemed interesting for us to generate code. We thought we had found the right tool to develop our aspect weaver. Hence, we tried to do the contrary : to read code (C# or VB.NET) to generate automatically a CodeDom tree in memory. And yes, there is a CodeDomProvider which has a CreateParser() method. Well, this is a trap : this method, in the standard framework, always returns a null (for C# and for VB.NET). Microsoft doesn't provide any parser implementation in standard. Anyway, someone else has probably implemented this for his own needs on a project... Indeed, you'll fine an OpenSource implementation of a C# that generates CodeDom trees : CS CODEDOM (available on http://ivanz.webpark.cz/csparser.html and on http://sourceforge.net/projects/cscodedomparser/). This implementation relies on MCS, the C# parser that provides the Mono project...

Well, CodeDom seems full of promises, but it lacks a set of parsers for standard .NET languages : C#, VB.NET, MC++, Jscript.NET and J#.

Conclusion

Aspect Oriented Programming is orthogonal to the other programming techniques (object, procedural...) and can be used as complement. Our feeling is that its future can be glorious since it resolves in a very simple and elegant way some problems that are not solvable without it, problems that put the maintainability of our big project at risk.

Putting into factor technical needs and weaving code to a set of classes in a project is a natural approach. It is fully integrated in the Java world, and will probably be in a short future in .NET.

The next step will be to get accustomed to using aspects, the same way we got accustomed to using objects. We are confident in the fact that using aspects the right way will take some time. As for objects, it will be simpler if we create and learn some new Design Patterns...



Author : Thomas GIL

Translator : Thomas GIL

Copyright January 2004

Resources

An excellent site on AOP : http://www.aosd.net/