Files
openlayers/master/examples/test_aspect.html
Éric Lemoine 5d14b9e2d4 Updated
2013-02-20 10:38:25 +01:00

479 lines
17 KiB
HTML

<html>
<head>
<title>aspects</title>
<style type="text/css">
@import "../../../dojo/resources/dojo.css";
</style>
<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug:true"></script>
<script type="text/javascript" src="../aspect.js"></script>
<script type="text/javascript" src="../aspect/cflow.js"></script>
<script type="text/javascript" src="../aspect/tracer.js"></script>
<script type="text/javascript" src="../aspect/timer.js"></script>
<script type="text/javascript" src="../aspect/profiler.js"></script>
<script type="text/javascript" src="../aspect/counter.js"></script>
<script type="text/javascript" src="../aspect/memoizer.js"></script>
<script type="text/javascript" src="../aspect/memoizerGuard.js"></script>
<script type="text/javascript">
dojo.require("dojox.lang.aspect");
dojo.require("dojox.lang.aspect.cflow");
dojo.require("dojox.lang.aspect.tracer");
dojo.require("dojox.lang.aspect.timer");
dojo.require("dojox.lang.aspect.profiler");
dojo.require("dojox.lang.aspect.counter");
dojo.require("dojox.lang.aspect.memoizer");
dojo.require("dojox.lang.aspect.memoizerGuard");
dojo.require("dojo.string");
dojo.require("dojox.lang.functional.listcomp");
var test = function(){
// This is a test class, don't program like this!
var Rect = function(){
this.x = this.y = this.width = this.height = 0;
};
dojo.extend(Rect, {
// getters
getX: function(){ return this.x; },
getY: function(){ return this.y; },
getWidth: function(){ return this.width; },
getHeight: function(){ return this.height; },
// setters
setX: function(val){ this.x = val; },
setY: function(val){ this.y = val; },
setWidth: function(val){ this.width = val; },
setHeight: function(val){ this.height = val; },
// special methods
getPerimeter: function(){ return 2 * (this.width + this.height); },
getArea: function(){ return this.width * this.height; },
getCorner: function(){ return {x: this.x + this.width, y: this.y + this.height}; },
move: function(x, y){ this.x = x; this.y = y; },
makeSquare: function(l){ this.width = this.height = l; },
scale: function(s){ this.width *= s; this.height *= s; },
pointInside: function(x, y){
return this.x <= x && x < (this.x + this.width) &&
this.y <= y && y < (this.y + this.height);
},
assertSquare: function(){
if(this.getHeight() != this.getWidth()){
throw new Error("NOT A SQUARE!");
}
}
});
var aop = dojox.lang.aspect, df = dojox.lang.functional;
// our simple advices
var TraceArguments = {
before: function(/*arguments*/){
var joinPoint = aop.getContext().joinPoint,
args = Array.prototype.join.call(arguments, ", ");
console.log("=> " + joinPoint.targetName + "(" + args + ")");
}
};
var TraceReturns = {
afterReturning: function(retVal){
var joinPoint = aop.getContext().joinPoint;
console.log("<= " + joinPoint.targetName + " returns " + retVal);
},
afterThrowing: function(excp){
var joinPoint = aop.getContext().joinPoint;
console.log("<= " + joinPoint.targetName + " throws: " + excp);
}
};
console.log("create rect1 and call its methods without aspects.");
var rect1 = new Rect;
rect1.move(100, 100);
rect1.makeSquare(200);
rect1.pointInside(150, 250);
console.log("perimeter: " + rect1.getPerimeter());
console.log("area: " + rect1.getArea());
console.log("=================================");
console.log("create rect2, attach advices to the instance, and repeat...");
var rect2 = new Rect;
aop.advise(rect2, /^get/, TraceReturns);
aop.advise(rect2, [/^set/, "move", "makeSquare"], TraceArguments);
aop.advise(rect2, "pointInside", [TraceReturns, TraceArguments]);
rect2.move(100, 100);
rect2.makeSquare(200);
rect2.pointInside(150, 250);
console.log("perimeter: " + rect2.getPerimeter());
console.log("area: " + rect2.getArea());
console.log("=================================");
console.log("attach advices to the Rect class, and repeat with rect1...");
var h1 = aop.advise(Rect, /^get/, TraceReturns);
var h2 = aop.advise(Rect, [/^set/, "move", "makeSquare"], TraceArguments);
var h3 = aop.advise(Rect, "pointInside", [TraceReturns, TraceArguments]);
rect1.move(100, 100);
rect1.makeSquare(200);
rect1.pointInside(150, 250);
console.log("perimeter: " + rect1.getPerimeter());
console.log("area: " + rect1.getArea());
console.log("=================================");
console.log("remove advices for getters and setters from the class, and repeat with rect1...");
aop.unadvise(h1);
aop.unadvise(h2);
rect1.move(100, 100);
rect1.makeSquare(200);
rect1.pointInside(150, 250);
console.log("perimeter: " + rect1.getPerimeter());
console.log("area: " + rect1.getArea());
console.log("=================================");
console.log("repeat with rect2...");
rect2.move(100, 100);
rect2.makeSquare(200);
rect2.pointInside(150, 250);
console.log("perimeter: " + rect2.getPerimeter());
console.log("area: " + rect2.getArea());
console.log("=================================");
console.log("test rect2 with throwing an exception...");
aop.advise(rect2, /^assert/, TraceReturns);
try{
rect2.assertSquare();
rect2.width = 300; // triggering exception
rect2.assertSquare();
}catch(e){
// squelch
}
console.log("=================================");
// more complex dynamic tracing advice
var Trace = function(context){
this.name = context.joinPoint.targetName;
};
dojo.extend(Trace, {
before: function(/*arguments*/){
this.args = Array.prototype.join.call(arguments, ", ");
},
afterReturning: function(retVal){
var buf = "-- " + this.name + "(" + this.args + ")";
if(typeof retVal == "undefined"){
// procedure without a return value
console.log(buf);
}else{
// function with returned value
console.log(buf + " returns: " + retVal);
}
},
afterThrowing: function(excp){
console.log("-- " + this.name + "(" + this.args + ") throws: " + excp);
}
});
// remove tracing for pointInside
aop.unadvise(h3);
console.log("create rect3, and trace all its methods...");
var rect3 = new Rect;
aop.advise(rect3, /^\S/, Trace);
rect3.move(100, 100);
rect3.makeSquare(200);
rect3.pointInside(150, 250);
console.log("perimeter: " + rect3.getPerimeter());
console.log("area: " + rect3.getArea());
rect3.assertSquare();
console.log("=================================");
var TraceAll = function(context, id){
this.name = context.joinPoint.targetName;
this.prefix = dojo.string.pad("", context.depth * 2, "--", true) + "-- #" + (id || 1);
};
dojo.extend(TraceAll, {
before: function(/*arguments*/){
var args = Array.prototype.join.call(arguments, ", ");
console.log(this.prefix + " => before " + this.name + "(" + args + ")");
},
around: function(/*arguments*/){
var args = Array.prototype.join.call(arguments, ", ");
console.log(this.prefix + " => around " + this.name + "(" + args + ")");
var retVal = aop.proceed.apply(null, arguments);
console.log(this.prefix + " <= around " + this.name + " returns " + retVal);
return retVal; // should return a value, if the target returns a value
},
afterReturning: function(retVal){
console.log(this.prefix + " <= afterR " + this.name + " returns " + retVal);
},
afterThrowing: function(excp){
console.log(this.prefix + " <= afterT " + this.name + " throws: " + excp);
},
after: function(){
console.log(this.prefix + " <= after " + this.name);
}
});
console.log("create rect4, and attach two tracer to all its methods...");
var rect4 = new Rect;
aop.advise(rect4, /^\S/, [
function(context){ return new TraceAll(context, 1); },
function(context){ return new TraceAll(context, 2); }
]);
rect4.move(100, 100);
rect4.makeSquare(200);
rect4.pointInside(150, 250);
console.log("perimeter: " + rect4.getPerimeter());
console.log("area: " + rect4.getArea());
try{
rect4.assertSquare();
rect4.width = 300; // triggering exception
rect4.assertSquare();
}catch(e){
// squelch
}
console.log("=================================");
var TraceTopLevel = function(context){
this.name = context.joinPoint.targetName;
};
dojo.extend(TraceTopLevel, {
before: function(/*arguments*/){
var args = Array.prototype.join.call(arguments, ", ");
console.log("=> " + this.name + "(" + args + ")");
},
afterReturning: function(retVal){
console.log("<= " + this.name + " returns: " + retVal);
},
afterThrowing: function(excp){
console.log("<= " + this.name + " throws: " + excp);
}
});
console.log("create rect5, and track only top-level calls...");
var rect5 = new Rect;
aop.advise(rect5, /^\S/,
function(context){
return aop.cflow(context.instance) ? // the advised object
{} : // do nothing
new TraceTopLevel(context); // log top level
}
);
rect5.move(100, 100);
rect5.makeSquare(200);
rect5.pointInside(150, 250);
console.log("perimeter: " + rect5.getPerimeter());
console.log("area: " + rect5.getArea());
try{
rect5.assertSquare();
rect5.width = 300; // triggering exception
rect5.assertSquare();
}catch(e){
// squelch
}
console.log("=================================");
var log = function(){
// log the rect1pointInside state
var dispatcher = "native";
if(rect1.pointInside.target){
if(rect1.pointInside.advices){
dispatcher = "dojox.lang.aspect";
}else if(rect1.pointInside._listeners){
dispatcher = "dojo.connect";
}
}
console.log("Dispatcher: " + dispatcher);
};
console.log("use dojo.connect() on rect1 to trace...");
console.log("Running native method.");
log();
rect1.pointInside(150, 250);
console.log("Connecting an event processor.");
h1 = dojo.connect(rect1, "pointInside", function(){
var args = Array.prototype.join.call(arguments, ", ");
console.log("from dojo.connect(): " + args);
});
log();
rect1.pointInside(150, 250);
console.log("Connecting the TraceAll advice.");
h2 = aop.advise(rect1, "pointInside", TraceAll);
log();
rect1.pointInside(150, 250);
console.log("Disconnecting the event processor.");
dojo.disconnect(h1);
log();
rect1.pointInside(150, 250);
console.log("Disconnecting the advise.");
aop.unadvise(h2);
log();
rect1.pointInside(150, 250);
console.log("Connecting the TraceAll advice.");
h2 = aop.advise(rect1, "pointInside", TraceAll);
log();
rect1.pointInside(150, 250);
console.log("Connecting an event processor.");
h1 = dojo.connect(rect1, "pointInside", function(){
var args = Array.prototype.join.call(arguments, ", ");
console.log("from dojo.connect(): " + args);
});
log();
rect1.pointInside(150, 250);
console.log("Disconnecting the advise.");
aop.unadvise(h2);
log();
rect1.pointInside(150, 250);
console.log("Disconnecting the event processor.");
dojo.disconnect(h1);
log();
rect1.pointInside(150, 250);
console.log("=================================");
console.log("trace all methods of rect1...");
h1 = aop.advise(rect1, /^\S/, aop.tracer(true));
rect1.move(100, 100);
rect1.makeSquare(200);
rect1.pointInside(150, 250);
console.log("perimeter: " + rect1.getPerimeter());
console.log("area: " + rect1.getArea());
try{
rect1.assertSquare();
rect1.width = 300; // triggering exception
rect1.assertSquare();
}catch(e){
// squelch
}
aop.unadvise(h1);
console.log("=================================");
console.log("count all get* methods of rect1...");
var counter = aop.counter();
h1 = aop.advise(rect1, /^get/, counter);
rect1.move(100, 100);
rect1.makeSquare(200);
rect1.pointInside(150, 250);
console.log("perimeter: " + rect1.getPerimeter());
console.log("area: " + rect1.getArea());
try{
rect1.assertSquare();
rect1.width = 300; // triggering exception
rect1.assertSquare();
}catch(e){
// squelch
}
aop.unadvise(h1);
console.log("get* methods were called", counter.calls, "times, with", counter.errors, "errors.");
console.log("=================================");
console.log("time all methods of rect1...");
h1 = aop.advise(rect1, /^\S/, aop.timer());
rect1.move(100, 100);
rect1.makeSquare(200);
rect1.pointInside(150, 250);
console.log("perimeter: " + rect1.getPerimeter());
console.log("area: " + rect1.getArea());
try{
rect1.assertSquare();
rect1.width = 300; // triggering exception
rect1.assertSquare();
}catch(e){
// squelch
}
aop.unadvise(h1);
console.log("=================================");
/*
console.log("profile all methods of rect1...");
h1 = aop.advise(rect1, /^\S/, aop.profiler("Profile1"));
rect1.move(100, 100);
rect1.makeSquare(200);
rect1.pointInside(150, 250);
console.log("perimeter: " + rect1.getPerimeter());
console.log("area: " + rect1.getArea());
try{
rect1.assertSquare();
rect1.width = 300; // triggering exception
rect1.assertSquare();
}catch(e){
// squelch
}
aop.unadvise(h1);
console.log("=================================");
*/
var Fibonacci = function(order){
if(arguments.length == 1){
this.setOrder(order);
}else{
this.offset = 2;
}
}
dojo.extend(Fibonacci, {
setOrder: function(order){
this.offset = order + 1;
},
getOrder: function(){
return this.offset - 1;
},
calculate: function(n){
if(n < 0){ return 0; }
if(n == 0){ return 1; }
return this.calculate(n - 1) + this.calculate(n - this.offset);
},
calculateN: function(n, o){
if(n < 0){ return 0; }
if(n == 0){ return 1; }
return this.calculateN(n - 1, o) + this.calculateN(n - 1 - o, o);
}
});
var args = df.listcomp("i for(i = 0; i < 15; ++i)");
console.log("calculate Fibonacci numbers...");
var fib = new Fibonacci;
h1 = aop.advise(fib, /^calculate/, aop.timer("fib"));
console.log("before memoization");
fib.setOrder(0);
console.log("0-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
fib.setOrder(1);
console.log("1-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
fib.setOrder(2);
console.log("2-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
fib.setOrder(3);
console.log("3-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
console.log("after memoization");
h2 = aop.advise(fib, "calculate", aop.memoizer());
h3 = aop.advise(fib, /^set/, aop.memoizerGuard("calculate"));
fib.setOrder(0);
console.log("0-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
fib.setOrder(1);
console.log("1-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
fib.setOrder(2);
console.log("2-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
fib.setOrder(3);
console.log("3-order:", dojo.map(args, dojo.hitch(fib, "calculate")));
aop.unadvise(h3);
aop.unadvise(h2);
console.log("before memoization");
console.log(fib.calculateN(15, 0));
console.log(fib.calculateN(15, 1));
console.log(fib.calculateN(15, 2));
console.log(fib.calculateN(15, 3));
console.log("after memoization");
h2 = aop.advise(fib, "calculateN", aop.memoizer(function(a, b){ return a + "/" + b; }));
h3 = aop.advise(fib, /^set/, aop.memoizerGuard("calculate"));
console.log(fib.calculateN(15, 0));
console.log(fib.calculateN(15, 1));
console.log(fib.calculateN(15, 2));
console.log(fib.calculateN(15, 3));
aop.unadvise(h3);
aop.unadvise(h2);
aop.unadvise(h1);
console.log("=================================");
};
//dojo.addOnLoad(test);
</script>
</head>
<body>
<p>This test is meant to run with Firebug. Open the console to see the output.</p>
<p><button onclick="test()">Start</button></p>
</body>
</html>