Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] How to provide external pcd definition?

This question has been vexing me for the last few days. Any configuration 
of a pointcut would have to go through the AspectJ compiler, so what 
you're currently doing is about as good as it can get right now. 

You could imagine an XML syntax that gets turned into an aspect by some 
build step, e.g.

<aspect name="DatabaseTestAspect" extends=" AbstractDatabaseTestAspect">
  <pointcut name="applicationCode">within(patterntesting..*)</pointcut>
  <pointcut name="allowedCode">within(patterntesting.db..*)</pointcut>
</aspect>

(just for illustration, not a real syntax)

but is that really so much easier to understand than:

aspect DatabaseTestAspect extends AbstractDatabaseTestAspect {
  pointcut applicationCode() : within(patterntesting..*);
  pointcut allowedCode() : within(patterntesting.db..*);
}

? Especially when you've still got to pass the result through the compiler 
anyway.

I've been talking a lot with the Spring folks at the TSS Symposium, and I 
can see a case for wanting true runtime configuration of pointcut values 
for some infrastructure (auxiliary) aspects - the kind of things that the 
J2EE community is very used to specifying in config files rather than in 
code. One of the exciting things that came out of those discussions is a 
way to use Spring's IoC capabilities to configure aspects (more on that 
soon), but this capability doesn't extend to configuring pointcuts (just 
things like the DataSource for a persistence aspect to use etc.). I wanted 
to enable pointcut configuration in the same way, so I've built a private 
prototype today that shows one way it could be done. Here's how it looks, 
and I'd be interested in feedback as to whether others would find this 
useful:

Firstly, a new utility class: JoinPointMatcher.  JoinPointMatcher is 
constructed with a string (in the expected usage this is obtained from a 
config file, but it could be generated in the program itself at runtime 
for extreme use cases) which contains an AspectJ pointcut expression, 
e.g.:

JoinPointMatcher jpm = new JoinPointMatcher("within(patterntesting..*)");

At any join point, you can ask JoinPointMatcher whether or not it matches: 
 if( jpm.matches(thisJoinPoint)) ...

Here's an aspect that allows runtime configuration using this mechanism:

aspect DynamicPointcutConstructionExample {

  private static JoinPointMatcher jpm;

  public void setPointcutExpression(String pointcutExpr) {
    jpm = new JoinPointMatcher(pointcutExpr);
  }

  // this pointcut is used to narrow down as far as possible at compile 
time the set of places
  // at which a dynamic pointcut could match (for efficiency)
  pointcut scope() : within(org.xyz.foo); 

 before() : scope() && if(jpm.matches(thisJoinPoint)) {
    System.out.println("I matched!!");
 }
 
}

The consequence you pay for using dynamic pointcuts (I'm using the word 
dynamic in analogy to the use of "dynamic" in DII, it may not be the best 
term) is that the pointcut matching is (very much) less efficient since 
the jpm.match code is driven for every join point in the scope (whereas 
the same pointcut specified at compile time would cause the advice to 
execute exactly where it needs to with no additional overhead or 
redundancy). If a dynamic pointcut proved to be too slow, you could always 
switch back to a traditional statically specified pc. 

If you're using Spring with the above example, you can configure the 
aspect with e.g.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
"http://www.springframework.org/dtd/spring-beans.dtd";>
<beans>
    <!-- what follows is an example syntax for specifying a factoryMethod, 

         I hope we end up with something very close to this in Spring -->
    <bean id="dynamicPointcutConstructionExample" 
          class="DynamicPointcutConstructionExample" 
          factoryMethod="aspectOf">
        <property name="pointcutExpression">
           execution(* *(..)) && this(Foo)
        </property>
    </bean> 
</beans>

Spring will set the value of the pointcutExpression attribute when the 
aspect is constructed. Many thanks are due to Rod Johnson for the 
inspiration to look into this.

[For the AspectJ developers, here's how the prototype currently works: 

JoinPointMatcher uses the PatternParser class to build a Pointcut 
(simple).

I then added a new match method in the Pointcut hierarchy that takes a 
JoinPoint instead of a shadow, and implemented match(JoinPoint) down the 
hierarchy to do the right thing. I had to add match(Class) methods to 
TypePatterns too. All the changes were self-contained, and the logic 
mirrors the matching logic for shadows.

Restrictions in the implementation are that you can't use cflow or 
cflowbelow in a dynamic pointcut (matching is done solely on the current 
join point), you can't use if() (don't want to go off into code), and you 
can't provide context information (bind "this(foo)" to a parameter "foo") 
or refer to other pointcuts.

Essentially I've written a convenience class for writing a powerful form 
of if() pcds.
]

Love it? Hate it? Let me know...

Cheers, Adrian.

I know, I know, I digressed for a day - Back to 1.2rc2 and AJDT 
tomorrow....

-- Adrian
Adrian_Colyer@xxxxxxxxxx

aspectj-users-admin@xxxxxxxxxxx wrote on 07/05/2004 09:17:35:

> Hi,
> 
> On the Pattern Testing project (http://patterntesting.sf.net), we have
> aspects that enforce some design rules. For example:
> 
> public abstract aspect AbstractDatabaseTestAspect
> {
>     /**
>      * Specify what is application code that should be subject to the
>      * pattern test.
>      * 
>      * Ex: <code>pointcut applicationCode():
> within(patterntesting.*)</code>
>      */
>     public abstract pointcut applicationCode();
> 
>     /**
>      * Specify which classes are allowed to call JDBC.
>      */
>     public abstract pointcut allowedCode();
> 
>     /**
>      * Specify which JDBC calls are forbidden.
>      */
>     pointcut forbiddenCalls() :
>         call(public * java.sql..*(..)) ||
>         call(public * javax.sql..*(..));
> 
>     /**
>      * Raise error if violations found.
>      */
>     declare error: (applicationCode() && forbiddenCalls()) &&
> !allowedCode() :
>         "It is not allowed to use the JDBC API from here";
> }
> 
> Now, the question is: How can we make the applicationCode and
> allowedCode pointcuts configurable by the end users? 
> 
> Of course one solution is to have create classes that extend the
> abstract aspect. However that sounds complex when compared to simple
> configuration data (the end users would need to create a project where
> to put the code, etc).
> 
> Any idea?
> 
> Note: The solution we're using so far (but which I don't like because
> it's tied to the build system) is to use Ant filters:
> 
> public aspect DatabaseTestAspect extends AbstractDatabaseTestAspect
> {
>     public pointcut applicationCode() :
>         @maven.patterntesting.suite.java.database.applicationCode@;
>     public pointcut allowedCode() :
>         @maven.patterntesting.suite.java.database.allowedCode@;
> }
> 
> Thanks
> -Vincent
> 
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/aspectj-users



Back to the top