Bingo (in file Aspects.java, see
below): an aspect defining a lottery-style discount intended to
improve customer fidelity: each 1000th customer pays only half of
its purchase.
Sicount: an aspect for regular discounts
(10%, say) which are applied each time the accumulated value of
purchases of a given customer exceeds a certain threshold (100
euro, say).
Profiling: allowing the shop manager to count the
number of discounts granted.
Checkout: an abstract aspect factoring out
common functionality of the lottery and regular aspects.
examples/javazon/src) is composed of the following files:
definition of the aspect
defining regular discounts (class Discount):
while (true) {
Order o = nextShip(c);
accPurchases += o.total();
System.out.println("\taspect discount: accumulated purchases of "
+ c + " is " + accPurchases);
if (accPurchases > Discount.discountThreshold) {
Event e2 = nextCheckout(c);
System.out.print("\taspect discount: ");
float discount = computeDiscount(Discount.discountRate, c);
Set tmp = new HashSet();
tmp.add(new Product("discount", -discount));
c.shoppingCart.add(tmp);
accPurchases -= Discount.discountThreshold;
}
}
The aspect accumulates the purchases of the customer c.
This accumulation is performed when an order of this client is
shipped. The method nextShip takes the client reference
c as a parameter and waits for a call to method
Order.ship of the base application for the client
c. When the accumulated purchases exceed a threshold, a
discount will be applied the next time this client calls the method
buy. So, a discount is applied by this aspect only if
the pattern ship();...;buy() corresponding to a sequence
of two base method calls is matched in a context where the accumulated
purchase value exceeds the threshold.
This last point illustrates how to express crosscuts representing relations between events using our approach. An aspect definition may wait for sequences of events, extract contextual information from these events and use this information to perform an action.
main of class Test:
Monitor.monitor.aspects = new Root(new Seq(new Profiling(), new Fst(new Bingo(3,25), new Discount())));This initialization defines a sequential composition of two aspects (
Profiling and another composition of Bingo
and Discount ) such that discounts are profiled (operator
Seq and always - i.e., in particular, if both discount
aspects interact - at most one discount is applied
profiling crosscuts are matched (the composition operator
Fst tries to apply its first argument and only applies
the second if the first has not been applied).
This term demonstrates that aspect
composition can be controlled programmatically. Furthermore, it
exemplifies dynamic aspect instantiated (even though it occurs only at
program start in this example).
Profiling, an excerpt of which is shown here:
while (true) {
Event e = nextComputeDiscount();
this.isCrosscutting = true;
n++;
System.out.println("\taspect profile: "
+ "number of discounts and bingos = " + n);
}
In the loop, events of calls to method computeDiscount
are counted, a method which is defined in the abstract aspect
Checkout and inherited by the Bingo an
Discount aspects.
Discount aspects provides a more
interested example of dynamic instantiation of aspects. Let's have a
another look at an excerpt of this aspect:
public void definition() {
Customer c = newCustomer();
insert(new Discount());
while (true) {
Order o = nextShip(c);
accPurchases += o.total();
System.out.println("\taspect discount: accumulated purchases of "
+ c + " is " + accPurchases);
if (accPurchases > Discount.discountThreshold) {
Event e2 = nextCheckout(c);
System.out.print("\taspect discount: ");
float discount = computeDiscount(Discount.discountRate, c);
Set tmp = new HashSet();
tmp.add(new Product("discount", -discount));
c.shoppingCart.add(tmp);
accPurchases -= Discount.discountThreshold;
}
}
}
In order to express that discounts are applied on a per-customer
basis, we use dynamic instantiation of aspects. In the body of method
definition, we therefore wait for the next customer
creation (newCustomer), dynamically create a new instance
of the discount aspect and insert it into the tree
representing the collection of aspects associated to the monitor.
This new instance is then ready to manage the next (a.k.a. future) new
customer.
make
javazon or the ant build system ant javazon. This
executes the following tasks (all executables are generated/executed
in directory examples/javazon/exec): :
TestInstrumentation which
defines which classes and/or methods are to be instrumented with
events.
{Javazon,Aspects}.java with event-generating
statements.
exec-directory.
Test.
Welcome to www.javazon.com
...
shipping p2 to c2
aspect discount: accumulated purchases of c1 is 40.0
shipping p1 to c1
aspect profile: number of discounts and bingos = 2
apply discount of 10% to c2
aspect profile: number of discounts and bingos = 3
apply discount of 25% (i.e.5.0) to c1
...
This demonstrates that the different discounts crosscuts the execution
of the base program, the profiling aspect applies to the discounting
aspects and that the profiling action is performed before discounting.
Monitoring of aspects which are applied to other aspects are handled by managing recursive invocations of the monitor.
Aspects are represented at runtime as a DAG, which is traversed by the monitor to give all aspects the possibility to react to a particular event while implementing the specified aspect compositions.
Instrumentation configuration is done by defining a class (in the e-shop example: TestInstrumentation.java:) which is compiled and loaded at runtime using Java's class loading mechanism.