Skip to main content

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

Another question is whether abstract aspects could play the same role.
While extending aspects is less flexible, it has the property that
the implementation is determinate for incremental weaving.

Here's some pseudo-code for a programmer using a library of J2EE
pointcuts that is implemented by different vendors.  The last step
can be the selection of the vendor, when deploying:

------- pseudo-code...
---- AspectJ J2EE library

abstract aspect EjbPointcuts {
   abstract pointcut ejbInit();
   abstract pointcut ejbActivation();
   abstract pointcut ejbPassivation();
   abstract pointcut ejbPersisting();
   abstract pointcut ejbMessage();
   ...
}
abstract aspect JmsPointcuts { ... }
abstract aspect ServletPointcuts { ... }
abstract aspect JSPPointcuts { ... }

---- {vendor} J2EE library

abstract aspect VendorEjbPointcuts extends EjbPointcuts {
    {define pointcuts}...
}
...

---- programmer writes to AspectJ J2EE library

abstract aspect BankTransactions extends EjbPointcuts {
    Object around() : ejbMessage()
        && call(void Account.deposit(int)) {
        ...
    }
    ...
}

---- application assembler/deployer hooks everything up

aspect BankTransactionsAssembly extends BankTransactions {
    declare parents: BankTransactions extends VendorEjbPointcuts;
}

------- end of pseudo-code...

This approach poses single-inheritance problems that might drive
towards a single abstract aspect and deter reuse of other
abstract aspects, so it's obviously not ideal.  It might lead to
a practice of using the library pointcuts from other aspects:

----
-- programmer code
/** concretize the EjbPointcuts for use */
abstract aspect BankTransactionPoints extends EjbPointcuts {
    ...
    public pointcut depositTransaction() : ejbMessage()
         && call(void Account.deposit(int);
}

aspect BankTransactions extends Transactions {
    /** concretize the abstract pointcuts in Transactions */
    pointcut transactionalMessage() :
        BankTransactionPoints.depositTransaction();
    ...
}
-- application assembler/deployer

aspect BankTransactionsAssembly extends BankTransactions {
    declare parents: BankTransactionPoints extends VendorEjbPointcuts;
}

----

This approach localizes the pointcut definitions in the vendor aspect,
which is loaded before any aspect or class that is affected by
the aspect, so it preserves incremental load-time weaving.
(Indeed, a vendor controlling the weaver could implement custom
join points not based on the normal Java programming model without
affecting the AspectJ language.)

So before I'd want to support interface pointcuts that prevented
implementations of AspectJ from doing incremental weaving, I'd like
to see a few libraries using abstract aspects and know that they
can't do what people would like to do with libraries.

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



Back to the top