[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-dev] interfaces, pointcuts, and libraries

Hi Ron, Adrian -

Some snippets from the emails Ron attached:

> extensible pointcuts ... would allow one to use an abstractly
> defined pointcut outside the scope of an abstract aspect.

> How about the following proposal, as a starting point for discussion:
> Whenever using a pointcut (such as in advice) it should be instantiated
> for ALL (known) pointcuts derived from that pointcut (i.e., pointcuts
> that extend the base definition in a derived class or aspect).

I'm not sure I understand the proposal quite yet.

For the following aspects:

abstract aspect AA {
    abstract pointcut apc();
}
aspect A extends AA {
    pointcut apc(): {definition};
    ...
}
aspect A2 extends AA {
    pointcut apc(): {definition};
    ...
}

// Proposed uses of AA outside of AA+
aspect B perthis(AA.apc()) {
    ...
}

class C {
    pointcut cpc() : AA.apc() && {definition};
}

aspect CA {
    before() C.cpc() { ... }
}

// perhaps even as Arno suggests
aspect AAA {
    declare pointcut : AA.apc() : {definition};
}

Do you mean if there is a pointcut that refers to apc() in any manner
(e.g., AA.apc() or A.apc() or apc() in a derived scope), directly
or indirectly, then any aspect containing that pointcut should be
instantiated once for each definition of apc()?  Can you say in the
above code how many aspects would be instantiated (assuming that
contains all the definitions of apc())?  Do we exclude derived aspects
from this rule?  Do we only include extrinsic references using
the form AA.apc()?

Since there is a separate set of advice running for each aspect
instantiated, wouldn't instantiating an aspect for each cause all
advice in each such aspect to be run that many times?  Conversely,
is there any way to run the advice for each such pointcut definition
with the same aspect instance?  Would that make sense for a
stateful aspect?

Wes

Ron Bodkin wrote:

It is exactly considerations such as these that motivated the proposal for extensible pointcuts. They would allow one to use an abstractly defined pointcut outside the scope of an abstract aspect. They are not quite as powerful as some alternative ideas for separating aspect interface and implementation (e.g., Caesar's), but would be tremendously valuable.

Because it's fairly hard to dig the discussion out of the old users@xxxxxxxxxxx archives, I've attached two emails from the most relevant discussion thread as background reading :-) Jim - as we look forward to AspectJ 1.2, it would be great if you could post the old list of feature candidates for 1.1 (I believe you wrote more detail on this feature that almost made it).

Ron

Ron Bodkin
Chief Technology Officer
New Aspects of Security
m: (415) 509-2895


------------Original Message-------------
From: Wes Isberg <wes@xxxxxxxxxxxxxx>
To: aspectj-dev@xxxxxxxxxxx
Date: Fri, Jul-25-2003 10:30 AM
Subject: Re: [aspectj-dev] interfaces, pointcuts, and libraries

Wow.  Very interesting discoveries!

But it's a bug.

  "Abstract pointcuts may only be declared
   within abstract aspects"

  Programming Guide, Semantics appendix

Here's my speculation as to why; Jim or Erik can
chime in on the actual reasons.

Pointcuts are resolved at weave-time, i.e., staticly,
If advice refers via an interface, it's not clear to
me which implementation should be used:

   interface I {
       abstract pointcut pc();
   }
   before () : I.pc() { ... }

   class A implements I {
      pointcut pc() : within(A);
   }

   class B implements I {
      pointcut pc() : target(A);
   }

If advice has to refer to implementation types,
then it doesn't seem like it's part of an interface.

It doesn't seem like this would support incremental
weaving, if the advice or aspects depended on the
number of (other) implementing classes.

For subaspects implementing abstract pointcuts,
then there is advice for each instance; could this
be a similar case?  I'm not sure how.

You could do "one for each implementing class",
but that would make it hard to understand when aspects
should be instantiated. If there are two concrete aspects
using an interface reference to a pointcut that has
3 implementations, then are there 6 aspect instances?
That are created when the interface-implementation classes
are loaded?  What if these are cflow aspects?

The nice thing about putting abstract pointcuts in aspects
is that the crosscutting specification is local to that
aspect hierarchy.  One answer to my objections is to
restrict the scope of the interface pointcuts to the
implementations themselves, but that seems contrary to
the purpose.  That can be done with abstract aspects
(except that classes can't extend them).

Wes

Adrian Colyer wrote:

AspectJ lets us declare pointcuts within aspects, classes and interfaces. To create 'library' pointcuts I need to be able to declare pointcuts in an interface (and let users of the library program to the interface), and then have implementers of the interface provide concrete implementations of those pointcuts. Exploring the behaviour of AspectJ 1.1 I see that we are part of the way there, but not fully. What I am about to describe is partially bug and partially feature request...

Today I can write:

public interface Foo {

  public pointcut bar();

}

This compiles happily, and I can refer to Foo.bar() in advice (it doesn't match any joinpoints).

If I write

class C implements Foo {}

this does not cause a compilation error (I believe it should, since C does not define pointcut bar which it's interface contract says it should).

If I write

class C implements Foo {
 public pointcut bar() : execution(... ...);
}

this compiles happily. Writing advice against Foo.bar does not match anything, writing advice against C.bar() matches the execution joinpoints. The desired behaviour is that writing advice against Foo.bar should match against the C definition.

If I write

aspect A implements Foo {}

this does not cause a compilation error (I believe it should, since C does not define pointcut bar()).


If I change the interface definition to

public interface Foo {
 public abstract pointcut bar();
}

then compilation of A fails with "inherited abstract pointcut Foo.bar() is not made concrete in A" (good, but tells me that the pointcut is not being implicitly made abstract when defined in an interface). Compilation of the empty C declaration still does not produce the compilation error.

How I think I would like this to behave is that pointcuts declared in interfaces are implicitly abstract (just like method definitions in interfaces). If a class or aspect declares that it implements the interface without providing a concrete definition of the pointcut then this is a compilation error. Clients should be able to write advice against the interface, and the advice will apply to joinpoints matching any of the concrete implementations of interface in the system (same rules as for abstract / concrete aspect pairs).

Why this is important: * I can create a standard interface that clients program to
* Multiple parties can implement the interface to provide concrete implementations that make sense within their system. These can even be binary so that implementation details are never exposed to clients.


What do others think?

-- Adrian
Adrian_Colyer@xxxxxxxxxx

_______________________________________________ aspectj-dev mailing list aspectj-dev@xxxxxxxxxxx http://dev.eclipse.org/mailman/listinfo/aspectj-dev



------------------------------------------------------------------------

Subject:
AW: Problem with reusing (abstract) pointcuts
From:
Arno.Schmidmeier@xxxxxxxxxxxxxx
Date:
Tue, 8 Jan 2002 06:12:07 PST
To:
gregor@xxxxxxxxx, Arno.Schmidmeier@xxxxxxxxxxxxxx, hugunin@xxxxxxxxxxxxxx


Hello,

Here is a more concrete example, ...
What I have created by simplifing actual code from one of our finished projects.
I replaced all the real interactions with the ODBMS through system.out.println() calls.

Note: In the real project, there were a bunch of classes like ServiceElements, (more complex calculations, more methods, more dataelements, all stored persistently in an Objectivity database).
Each having its corrsponding <>PersistenceAdapter.


Note1:
The actual example does not work as expected, see the previous mails in this thread, ...
However I hope it gives you an good understanding about the intention.

Note 2:
I found the pattern also in other scenarious, e.g. at the ORB integration, etc.

public class AbstractPointCutReuserTest {

   public static void main(String[] args) {
       ServiceElement Element=new ServiceElement();
       Element.setActive(true);
       System.out.println("The Element is Active:"+Element.isActive());
   }
}

class ServiceElement{
   public void setActive(boolean Active){
       this.Active=Active;
   }

   public boolean isActive(){
       return Active;
   }

   boolean Active=false;
}

abstract aspect AbstractPersistenceAdapter{

   public abstract pointcut WritingMethods();

   public abstract pointcut ReadingMethods();

   public pointcut ExternalWMethods();

   public pointcut ExternalRMethods();

   before(): WritingMethods(){
       System.out.println("Must execute markModified on"+thisJoinPoint.getTarget());
       System.out.println("Transaction Must be open");
   }

   before(): ReadingMethods(){
       System.out.println("Must execute markModified on"+thisJoinPoint.getTarget());
       System.out.println("Transaction Must be open");
   }
}

aspect ServiceElementPersistenceAdapter extends AbstractPersistenceAdapter{
   public pointcut WritingMethods():execution(* ServiceElement.setActive(boolean));

   public pointcut ReadingMethods():execution(* ServiceElement.isActive());
}


abstract aspect TransactionAdapter dominates PersistenceAdapter{

   pointcut pc():AbstractPersistenceAdapter.ExternalWMethods()||AbstractPersistenceAdapter.ExternalRMethods();

   Object around(): pc(){
       System.out.println("Open TransAction");
       Object obj=proceed();
       System.out.println("Close Transaction");
       return obj;
   }
}


abstract aspect RetryFailingTransactionHandler dominates TransactionAdapter{ public static int MAXCOUNT=10;

   pointcut pc():AbstractPersistenceAdapter.ExternalWMethods()||AbstractPersistenceAdapter.ExternalRMethods();

   Object around(): pc(){
       int count=0;
       Object obj=null;
       while(true){
           try{
               obj=proceed();
               break;
           }catch(RuntimeException ex){
               count++;
               ex.printStackTrace();
               if (count>=MAXCOUNT)
                   throw ex;
           }
       }
       return obj;
   }
}

abstract aspect BenchmarkTransactions dominates RetryFailingTransactionHandler{
   public static int MAXCOUNT=10;

   pointcut pc():AbstractPersistenceAdapter.ExternalWMethods()||AbstractPersistenceAdapter.ExternalRMethods();

   Object around(): pc(){
       long first=System.currentTimeMillis();
       Object obj=proceed();
       long later=System.currentTimeMillis();
       System.out.println("Method needed: "+(later-first)+" Milliseconds");
       return obj;
   }
}


regards Arno


-----Ursprüngliche Nachricht----- Von: Gregor Kiczales [mailto:gregor@xxxxxxxxx] Gesendet: Montag, 7. Januar 2002 19:51 An: Arno.Schmidmeier@xxxxxxxxxxxxxx; hugunin@xxxxxxxxxxxxxx Betreff: Re: Problem with reusing (abstract) pointcuts


For me, examples work best when they are "real", or an abstraction of real.

So, for example, an aspect like the DisplayUpdating aspect we show in "Getting Started with AspectJ"
is what I like to see.

Aspects with names like foo and bar are not as useful for me, because all I can see from them is
what the mechanism should do.  I can't glean the essence of what you are trying to say.  So examples
like that aren't as helpful in trying to think about other ways of saying the same thing.



----- Original Message ----- From: HYPERLINK "mailto:Arno.Schmidmeier@xxxxxxxxxxxxxx"Arno.Schmidmeier@xxxxxxxxxxxxxx To: HYPERLINK "mailto:gregor@xxxxxxxxx"gregor@xxxxxxxxx ; HYPERLINK "mailto:hugunin@xxxxxxxxxxxxxx"hugunin@xxxxxxxxxxxxxx ; HYPERLINK "mailto:Arno.Schmidmeier@xxxxxxxxxxxxxx"Arno.Schmidmeier@xxxxxxxxxxxxxx Sent: Monday, January 07, 2002 5:08 AM
Subject: AW: Problem with reusing (abstract) pointcuts



Hello,

What should the example look like?
A short description of a whole application, some design patterns or some classes and aspects, demonstrating the expected use?
For the last, I expect my sample at the beginning of this thread would be a good starting point.
If not what is missing?

regards
   Arno

-----Ursprüngliche Nachricht-----
Von: Gregor Kiczales [mailto:gregor@xxxxxxxxx]
Gesendet: Freitag, 28. Dezember 2001 09:44
An: HYPERLINK "mailto:rbodkin@xxxxxxxxxxxxxx"rbodkin@xxxxxxxxxxxxxx; HYPERLINK "mailto:hugunin@xxxxxxxxxxxxxx"hugunin@xxxxxxxxxxxxxx; HYPERLINK "mailto:Arno.Schmidmeier@xxxxxxxxxxxxxx"Arno.Schmidmeier@xxxxxxxxxxxxxx; users@xxxxxxxxxxx
Betreff: Re: Problem with reusing (abstract) pointcuts


I agree there is a whole in the language here. As Jim said, it would be nice to have some more examples of how people want to use it to know how best to fix it.

The following might help people come up with such examples.  Its the closest thing to
the mechanism Jim described that I can do in the current language.  It isn't super-pretty,
but it does give the flavor of pointcuts that are both extensible and globally advisable.
It works by using multiple pointcuts, and it requires using aspects that extend a base one.

Warning, it isn't beautiful!  But its easy, when reading code written this way, to imagine
its trivial conversion to a language semantics like Jim described.

The general idea is as follows:



abstract aspect BaseAspect {

   /* add to this */
   abstract pointcut when();

   before(): when() { beforeHook(); }
   after():  when() { afterHook();  }

   private void beforeHook() { }
   private void afterHook()  { }

/* define advice on these */
pointcut beforeHook(): call(void Moving.beforeHook());
pointcut afterHook(): call(void Moving.afterHook());
}


aspect A extends BaseAspect {
pointcut when(): call(public * *.*(..));
}


aspect B extends BaseAspect {
pointcut when(): call(private * *.*(..));
}


aspect Foo {
before(): BaseAspect.beforeHook() { }
after(): BaseAspect.afterHook() { }


}




----- Original Message ----- From: HYPERLINK "mailto:rbodkin@xxxxxxxxxxxxxx"";>Bodkin, Ron <rbodkin@xxxxxxxxxxxxxx> To: HYPERLINK "mailto:hugunin@xxxxxxxxxxxxxx"";>Hugunin, Jim <hugunin@xxxxxxxxxxxxxx> ; HYPERLINK "mailto:'Arno.Schmidmeier@xxxxxxxxxxxxxx'"'Arno.Schmidmeier@xxxxxxxxxxxxxx' ; HYPERLINK "mailto:users@xxxxxxxxxxx"users@xxxxxxxxxxx Sent: Thursday, December 20, 2001 2:23 PM
Subject: RE: Problem with reusing (abstract) pointcuts



I think extensible pointcuts would be very valuable for building aspect libraries.


I think there are two, related, problems doing so today:
1) You have to directly extend an aspect to apply pointcuts to your system
2) You can't refer to an extensible (or abstract) pointcut definition in an aspect (or class) that's external to it

These imply a need to extend all the aspects in a library to use it, thereby violating encapsulation (you need to extend implementation aspects). A preferable alternative would be allowing one to write configuration aspects.

The extensible pointcut proposal could fix both of these problems. I would expect advice in another aspect to be able to get the most-extended version of a pointcut. In Jim's example, one could write advice in a DebugDisplay aspect that refers to Display.move(), which would intercept any call in the fully extended version.

This would allow one to define all the "public interface" pointcuts for a library in a single configuration aspect, and a user could apply the library by simply extending the pointcuts in one aspect.

I wrote more about this on Nov. 1 ("perthis and abstract pointcuts question"), but I like adding extensible aspects rather than changing abstract aspects to behave this way.

Ron

-----Original Message-----
From: Hugunin, Jim <hugunin@xxxxxxxxxxxxxx> [mailto:hugunin@xxxxxxxxxxxxxx] Sent: Thursday, December 20, 2001 12:02 PM
To: 'Arno.Schmidmeier@xxxxxxxxxxxxxx'; users@xxxxxxxxxxx
Subject: RE: Problem with reusing (abstract) pointcuts



In AspectJ-1.0, the correct behavior when given this program should be to produce a compile-time error, "AbsAbs.pc2() references an abstract pointcut, so it can't be used in a static context". This will be fixed for 1.0.2.

However, there's something very interesting that you're trying to do here.  There might be a way to extend the language in AspectJ-1.1 to support this sort of functionality.  A short compelling example for why this feature is important might help us to better understand it.

I've occasionally wanted a variant of this feature that completely ignores the aspect hierarchy.  Here's an extremely rough example of what that might look like (new syntax is in all-caps to make it stand out and emphasize the fact that this is a very rough idea):

class Display {
 EXTENSIBLE public pointcut move();
 ...
}

class Point {
 EXTEND pointcut Display.move(): call(void Point.setX(int)) || call(void Point.setY(int));
 ...
}

class Line {
EXTEND pointcut Display.move(): call(void Line.set ... }


Just like in our current figure example (see CACM article), this Display.move() pointcut can be very useful to give a name to a particular group of join points.  The change here is that the pointcut can be specified in pieces rather than as a monolithic entity.  The value of specifying the pointcut separately here is that it feels like it maps better on to the existing modularity of the system.  The developer of the Point class can update the appropriate pointcut whenever a new method is added that makes a point move.  I think that this idea is similar to what you're looking for with your version of abstract pointcuts.

I don't know if this is related to your desired use of abstract pointcuts or not, or at this point even if this idea would help improve the quality of AspectJ code.  My proposal above is intended mainly to provide a rough example for a semi-concrete way that I'd like to be able to discuss these sorts of features.

-Jim


-----Original Message----- From: Arno.Schmidmeier@xxxxxxxxxxxxxx [mailto:Arno.Schmidmeier@xxxxxxxxxxxxxx] Sent: Wednesday, December 12, 2001 7:52 AM To: users@xxxxxxxxxxx Subject: Problem with reusing (abstract) pointcuts



Hello,

Following sample:

public class AbstractPointCutReuserTest {

public AbstractPointCutReuserTest() { } public static void main(String[] args) { AbstractPointCutReuserTest abstractPointCutReuserTest1 = new AbstractPointCutReuserTest(); abstractPointCutReuserTest1.foo(); abstractPointCutReuserTest1.bar(); }

public void foo(){ System.out.println("foo"); }

public void bar(){ System.out.println("bar"); }

}

abstract aspect AbsAbs{ pointcut pc2():pc();

abstract pointcut pc();

pointcut pc3():execution(* AbstractPointCutReuserTest.foo());

}

aspect absfoo extends AbsAbs{

pointcut pc():execution(* AbstractPointCutReuserTest.foo());

before(): pc(){ System.out.println("absfoo"); } }

aspect absfoo2 extends AbsAbs{ pointcut pc():execution(* AbstractPointCutReuserTest.bar());

before(): pc(){ System.out.println("absfoo2"); } }


aspect XY{ before ():AbsAbs.pc2(){ System.out.println("pc2 XY"); }


before ():AbsAbs.pc3(){ System.out.println("pc3 XY"); }

} compiling and running it produces following output: pc3 XY absfoo foo absfoo2 bar


However what I expected would be: either a compile time error, because pc2, is made up from an abstract pointcut, or something like pc3 XY pc3 XY absfoo foo pc2 XY absfoo2 bar


regards Arno

P.S. I am using aspectJ 1.0



------------------------------------------------------------------------

Subject:
Re: perthis and abstract pointcuts question
From:
Ron Bodkin <rjbodkin@xxxxxxxxx>
Date:
Thu, 1 Nov 2001 12:18:02 PST
To:
"Hugunin, Jim <hugunin@xxxxxxxxxxxxxx>" <hugunin@xxxxxxxxxxxxxx>


I think it would be really helpful to allow using abstract pointcuts that are implemented by a derived aspect outside that derived aspect. Another case where it would be useful is if you'd like to have one configuration class/aspect determine how a library/framework of abstract aspects applies to your concrete use, rather than having to extend each implementation aspect. This reduces coupling and unscatters your configuration.


How about the following proposal, as a starting point for discussion:

Whenever using a pointcut (such as in advice) it should be instantiated for ALL (known) pointcuts derived from that pointcut (i.e., pointcuts that extend the base definition in a derived class or aspect).

This would let you use the library/framework in different ways for different layers of your application (e.g., logging in the view and model layers or error handling). It's important that pointcuts are only useful at weave time to generate woven code - they aren't usefully "invoked" polymorphically. So it's appropriate to identify all the known derived pointcuts at weave time (unlike in OO inheritance where you need to be open to new code that's not known at compile time).

A potential drawback is a combinatorial explosion of pointcuts, but I see that as unlikely in practice.

Thoughts?
Ron

Hugunin, Jim wrote:

<snip>

Your version below won't work because a qualified reference to a pointcut, like "TransactionalObjects.persistent()" means use the persistent() pointcut as it is declared in the aspect TransactionalObjects -- and in that aspect you've declared this pointcut to match nothing. If you make this pointcut declaration explicitly abstract, i.e. "abstract pointcut persistent();" you'll get a decent error message out of ajc for this sort of mistake. The only way to use an overriden pointcut is in a subtype of the declaring aspect where the reference can be resolved relative to the subaspect.

Let me know if this works for you - Jim



-----Original Message-----
From: Frank Sauer [mailto:Frank.Sauer@xxxxxxxxxx]
Sent: Wednesday, October 31, 2001 11:41 AM
To: 'AspectJ User List'
Subject: perthis and abstract pointcuts question


I'm not sure if I'm going to be able to fully explain what I'm trying to do,
but
I'll give it a shot:


I'm trying to construct a persistence layer that can turn make any given set
of
domain classes transactional. It keeps track of all modifications to those
classes
and at transactional boundaries commits the transaction. If any
transactional
method throws an exception, all modifications are rolled back. I've got most
of this
working with the following aspects:


package persistence;
abstract aspect TransactionalObjects {
    pointcut persistent();    // defines classes to be tracked
    pointcut transactional();    // defines transactional methods
    pointcut dirty(Object o): (persistent() && this(o) && set(* *.*));

    // various advices
}
in client:

aspect MyTransactionalObjects extends TransactionalObjects {
    pointcut persistent(): within(domain.*);
    pointcut transactional():
        call(* Client.createCustomer(..)) ||
        ...
}

In other words, the clinet ONLY has to make some pointcuts concrete
in order to use the persistence framework. So far so good, works like
a charm, but now I want to introduce a UUID into all persistent objects.


There's two choice that I can see right now:

make the user add the following to his MyTransactionalObjects:

aspect MyTransactionalObjects extends TransactionalObjects {

    declare parents: domain.Person || domain.Address extends UUID;

    pointcut persistent(): within(domain.*);
    pointcut transactional():
        call(* Client.createCustomer(..)) ||
        ...
}

The problem with this is that the framework is not guaranteed to always have
a UUID for each persistent object because whoever is using it has to properly
declare the parents, so I tried:


package persistence;

aspect UUIDObject extends UUID perthis(TransactionalObjects.persistent()) {
}


This way, I thought, there would always be a UUID as long as there are any
persistent classes defined. However, when I try to get to the UUID using:


    UUIDObject.aspectOf(<an instance of a class in domain package>),
I get:

org.aspectj.lang.NoAspectBoundException
    at persistence.UUIDObject.aspectOf(UUIDObject.java:3)

Now, if I change the above to:

aspect UUIDObjects extends UUID perthis(MyTransactionalObjects.persistent())
{
}


In other words it's now using a concrete pointcut, it works fine.

The problem with this is that now the framework has to refer to a
non-framework aspect
(MyTransactionalObjects) wich would break the decoupling...

Is this just another manifestation of bug 559, or is this something
different entirely?

Frank Sauer
The Technical Resource Connection, Inc.
a wholly owned subsidiary of Perot Systems
Tampa, FL
http://www.trcinc.com
-----------------------------------------------
Java: The best argument for Smalltalk since C++

__________________________________________________
AspectJ users mailing list   -   users@xxxxxxxxxxx
To be removed send mail to users-admin@xxxxxxxxxxx
or visit http://aspectj.org/lists

__________________________________________________
AspectJ users mailing list   -   users@xxxxxxxxxxx
To be removed send mail to users-admin@xxxxxxxxxxx
or visit http://aspectj.org/lists