====== JAsCo Quick Reference for 0.8.6 ======
This document gives a quick reference overview of the JAsCo language. It is recommended to at least read the language reference partially to understand the general concepts and ideas before using this quick reference. For an in-depth explanation of every feature, see the language reference document as well.
===== Contents: =====
- [[quick#1. Aspect Beans|Aspect Beans]]
- [[quick#2. Connectors|Connectors]]
- [[quick#3. Refining Classes|Refining Classes]]
- [[quick#4. Virtual Mixins|Virtual Mixins]]
- [[quick#5. Combination Strategies|Combination Strategies]]
- [[quick#6. Stateful Aspects|Stateful Aspects]]
- [[quick#7. Miscellaneous|Miscellaneous]]
See the table on the right for a full table of contents.
===== 1. Aspect Beans =====
Contain one or more hooks that define crosscutting behavior in an independent way.
==== 1.0. Example logger aspect bean: ====
class Logger {
hook LogHook {
LogHook(method1(..args)) {
execution(method2);
}
before() {
log("EXECUTING: "+thisJoinPoint.getSignature());
}
}
==== 1.1. Abstract Method Parameters ====
* **method1(..args)**
* any return type,
* any number and type of arguments;
* //args// is visible in advices (type: Object[])
* **method2(String s, int i)**
* any return type,
* first type String, second type int,
* //s// and //i// are visible in advices.
* **long method3(String k, ..myargs):**
* return type long,
* first argument String, any number of arguments after String,
* //k// and //myargs// are visible in advices (type of //myargs//: Object[])
==== 1.2. Abstract Pointcut ====
* **execution(method1):** hook triggers when one of the methods bound to method1 abstract method parameter is executed.
* **call(method1):** hook triggers on invocation of all methods bound to method1 abstract method parameter. (as of 0.9)
* **cflow(method1):** hook triggers when one of the methods bound to method1 is in the control flow of current joinpoint.
* **withincode(method1):** hook triggers when one of the methods bound to method1 is directly invoked by the current joinpoint.
* **target(MyClass):** hook triggers when target object of joinpoint is of type MyClass
* **execution(method1) && !cflow(method2) && target(test.Boe)**: &&, || and ! supported for combining pointcuts
==== 1.3. IsApplicable Condition ====
Additional triggering condition in full Java, returns a boolean. Is equivalent to if pointcut in AspectJ.
isApplicable() {
return isEnabled;
}
==== 1.4. Advices ====
* **before()**: executes before joinpoint. Always void return type.
* **after()**: executes after joinpoint regardless of how the joinpoint executes (exception or normal return). Always void return type.
* **around()**: executes around joinpoint. Return type is Object.
* **after throwing(MyException x)**: Executes after joinpoint when an exception of type MyException is thrown. Use type //Exception// to capture all exceptions. Always void return type.
* **after returning(String x)**: Executes after joinpoint when an object of type String is returned. Use //Object// to capture all returns. Always void return type.
* **around throwing(MyException x)**: Executes around joinpoint when an exception of type MyException is thrown. Allows to alter thrown exception, rethrow it or return normally. Return type is Object.
* **around returning(String s)**: Executes around joinpoint when an object of type String is returned. Allows to alter return value. Return type is Object.
==== 1.5. Special Constructs in Advices ====
* only for around/around returning/around throwing advice: the **proceed** keyword.
* **proceed()**: invokes next advice or orginal behavior with the orignal arguments on original target. Return type is Object.
* **proceed(Object target, Object[] args)**: invokes next advice or orginal behavior with new arguments and target object. Return type is Object.
* **proceed(String s, int k):** Specialized proceed, has signature of call or execution abstract method parameter: method2(String s, int i)
* **thisJoinPoint**: reflection on currently executing joinpoint, [[http://ssel.vub.ac.be/jasco/nightly/doc/jasco/runtime/MethodJoinpoint.html|API docs]].
* **thisJoinPointObject**: Target object of joinpoint. Has type Object or type of target pointcut when //target// pointcut is used. Is null when static method.
==== 1.6. Refinable Methods ====
* allow to postpone implementation of behavior to [[[[documentation:quick#2.4._hook_custimization|the connector]] or to [[documentation:quick#3._refining_classes|type-specific refining classes]].
* can only be invoked from advices
hook securityHook {
...
public refinable Object noAccessPolicy();
...
}
* default implementation supported in case not reimplemented later on:
hook securityHook {
...
public refinable void noAccessPolicy() {
throw new NoAccessException(thisJoinPoint);
}
...
}
===== 2. Connectors =====
Deploys aspect beans onto concrete context.
==== 2.0. Example logger connector: ====
static connector LogDeployer {
Logger.LogHook logaspect = new Logger.LogHook(void test.mymethod());
}
==== 2.1. Hook Instantiation ====
* Binds every abstract method parameter in hook constructor.
* **new Logger.LogHook(void test.mymethod())**
* **new Logger.LogHook(* *.*(*))**: all methods
* **new Logger.LogHook(* test.boepsie*(String, int))**
* **new Logger.LogHook({void test.mymethod(), test.boepsie.mymethod2})**
* **new OtherAspect.LogHook({void test.mymethod(), test.boepsie.mymethod2}, * test.boepsie.balaba(String))**
* **new Security.AccessControl(@secure * *.*(*))**: all methods with annotation @secure
* **new Security.AccessControl(* Logger.LogHook.before())**: aspects on aspects
* **new Security.AccessControl(* ITestInterface.access+())**: on all implementing classes of ITestInterface
* **new Security.AccessControl(* ITestInterface.access++())**: on all implementing classes of ITestInterface, but only those methods that are declared by ITestInterface. Other methods of implemented classes are not affected.
==== 2.2 Automatic Hook Instantiation (aka Aspect Factories) ====
static connector PerThreadConnector {
//predefined factory instantiation
perthread Protocol.ProtocolChecker aspect3 =
new Protocol.ProtocolChecker(....);
//custom factory instantiation
per(TypeOfMyFactory) Protocol.ProtocolChecker aspect5 =
new Protocol.ProtocolChecker(....);
}
//Predefined Aspect Factories://
* **perobject:** one unique hook for every target object instance
* **perclass:** one unique hook for every target class
* **permethod:** one unique hook for every target method
* **perall:** one unique hook for every joinpoint
* **perthread:** one unique hook per executing thread
//Custom Aspect Factories://
They have to implement the [[http://ssel.vub.ac.be/jasco/nightly/doc/jasco/runtime/aspect/factory/IAspectFactory.html|jasco.runtime.aspect.factory.IAspectFactory]] interface.
This interface contains one method, //getAspectInstance//, that is responsible for fetching the aspect instance for the currently executing joinpoint //jp//. The second argument allows to create a new hook instance and initialize it properly as defined in the associated connector.
public interface IAspectFactory {
public IHook getAspectInstance(MethodJoinpoint jp, IAspectInstanceCreator creator);
}
The following code fragment illustrates a custom aspect factory that returns a new hook instance for every class loader that loaded the executing class of the current joinpoint. As such, both the hook and the joinpoint are loaded by the same class loader and thus avoiding possible class loader hell problems.
package test.aspects;
public class PerClassLoaderAspectFactory implements IAspectFactory {
public PerClassLoaderAspectFactory(){}
private Hashtable map = new Hashtable();
IHook getAspectInstance(MethodJoinpoint jp, IAspectInstanceCreator creator) {
IHook instance = (IHook) map.get(jp.getClassLoader());
if(instance==null) {
instance = creator.createNewInstance(jp.getClassLoader());
map.put(jp.getClassLoader(),instance);
}
return instance;
}
}
__Good to know:__
* Custom aspect factories must be public and have a public default constructor (no arguments).
* There is also a convenience class named [[http://ssel.vub.ac.be/jasco/nightly/doc/jasco/runtime/aspect/factory/DefaultAspectFactory.html|DefaultAspectFactory]] available that manages the dictionary for you. Subclasses only need to implement the getKey(MethodJoinpoint) method.
* In case the result of the aspect factory, i.e. hook instance, does not remain constant given all static information in the joinpoint like method name, class name, class loader, return types, argument types, etc... In other words, it depends on some dynamic information, like target object or thread, then the aspect factory must implement the jasco.runtime.DoNotCache interface. This empty interface is merely a marker interface that declares that this aspect factory has to be used for every execution of all joinpoints. Per default, the factory result is optimized by the run-time weaver to only execute once for every static shadow joinpoint.
==== 2.3 Explicit Aspect Bean Instantiation (since 0.8.5 final) ====
Per default, aspect beans are instantiated implicitly using the default constructor. It is also possible to explicitly instantiate the global aspect bean instance for each connector as follows:
class Test {
public Test(String var) {}
hook testHook {
...
}
}
connector TestConnector {
Test test = new Test("a custom string");
Test.testHook hookInstance = new Test.testHook(* *.*(*));
}
__Good to know:__
* Aspect bean instances are shared over the complete connector, regardless of the number of hook instances. For every aspect bean type only one instance per connector may exist.
* When the aspect bean is not explicitly instantiated, the default constructor is used for instantiation
==== 2.4. Hook Invocation ====
* Optionally specify which advices to execute
static connector LogDeployer {
Logger.LogHook lmyloginst = new Logger.LogHook(void test.mymethod());
lmyloginst.before();
}
* allows to specify precedence in case mutiple hooks are instantiated. Precedence is only valid for these hook instances and might vary on advice-type basis.
static connector LogDeployer {
Test.TestAspect aspect1 = new Test.TestAspect(void test.mymethod());
Security.AccessControl aspect2 = new Security.AccessControl(void test.mymethod());
aspect1. before();
aspect2. before();
aspect2. around();
aspect1. around();
}
==== 2.5. Hook Custimization ====
* method invocation on hooks (sets property for that hook instance only):
static connector LogDeployer {
Logger.LogHook mylogger = new Logger.LogHook(void test.mymethod());
mylogger.setLogString("boepsiewoepsie");
}
* Implementation of refinable methods depending on deployment (implements refinable method(s) for that hook instance only):
static connector AccessControlDeployer {
Security.AccessControl test = new Security.AccessControl(void test.mymethod()) {
public refinable void noAccessPolicy() {
System.errorAccess(thisHook.getUser(),thisJoinPoint,thisJoinPointObject);
}
};
}
==== 2.6. Reflection and Fetching Aspect Instances ====
* In order to fetch a connector instance from Java code, do the following:
Connector c = Connector.MyConnectorName.getConnector();
* The [[http://ssel.vub.ac.be/jasco/nightly/doc/jasco/runtime/connector/Connector.html|API docs]]. contains the methods supported by JAsCo connectors.
* In order to fetch aspect instances directly, do the following in case of normal instantiation:
Connector.MyConnectorName.getConnector().myAspectVariableName();
//myAspectVariableName is the var name of the aspect instance in the connector,
//e.g. aspect2 in the connector above
* In order to fetch aspect instances directly, do the following in case of **per*** instantiation:
Connector.MyConnectorName.getConnector().myAspectVariableName(keyForPerInstantiation);
//myAspectVariableName is the var name of the aspect instance in the connector,
//e.g. aspect2 in the connector above
//keyForPerInstantiation is the key to fetch the hook instance,
//e.g. target object in case of perobject, targetclass in case of perclass etc...
===== 3. Refining Classes =====
Implements refinable methods in a type specific manner, the type after the refining token refers to the type of a hook and the type after the for token refers to the type of target objects (i.e. //thisJoinPointObject//) where this refinement is valid for. Use Object to define a global refinement.
The most specific refinement for a certain method is executed, inline refinements in the connector always have precedence over refining classes.
==== 2.0 Example Refining Class ====
class TestRefinement2 refining TestAspect.TestHook for status.DataStore {
public refinable Object getData() { //refinable modifier here as well
DataStore store = thisJoinPointObject;
thisHook.iAmRefining(thisJoinPoint.getName());
return store.getData();
}
}
==== 2.1 Refining Classes ====
class TestRefinement2 refining TestAspect.TestHook for java.io.Serializable
* Implement one or more refinable methods of refining hook or subclasses of hook TestAspect.TestHook
* target object of joinpoint (thisJoinPointObject) has to be of type java.io.Serializable or subtype
==== 2.2 Special keywords for refinable method implementations ====
* **thisJoinPoint**: reflection on currently executing joinpoint, [[http://ssel.vub.ac.be/jasco/nightly/doc/jasco/runtime/MethodJoinpoint.html|API docs]].
* **thisJoinPointObject**: Target object of joinpoint. Has the same type as target object of refinement, e.g. java.io.Serializable
* **thisHook**: refers to hook instance that invoked the refinable method, e.g. TestAspect.TestHook
===== 4. Virtual Mixins =====
Virtual mixins allow to insert the implementation of an interface in target classes so that other aspects can depend on that. This is mainly useful for communicating information between aspects.
In order to cast an object to the mixin interface, use the following code:
//customer is an instance of Customer where the ICustomerInfo mixin
//has been inserted as described below
ICustomerInfo info = (ICustomerInfo) customer;
The ICustomerInfo interface consists of:
interface ICustomerInfo extends jasco.runtime.mixin.IMixin {
public boolean isFrequent();
public boolean setIsFrequent(boolean b);
}
The interface is inserted into a target class by simply declaring a hook that implements the interface and correspondig connector. Notice the perobject modifier in the connector for having one hook instance per customer instance. Otherwise the isFrequent property would be global for all customer instances.
The hook is also able to define regular advices. Those are executed as usual, i.e. for all method executions on customer objects in this case.
class BRFrequent {
hook Introduce implements ICustomerInfo {
private boolean isFrequent=false;
Introduce(void method(..args)) {
execution(method(args));
}
public boolean isFrequent() {
return isFrequent ;
}
public boolean setIsFrequent(boolean b) {
isFrequent=b;
}
}
}
static connector IntroduceMixin {
perobject BRFrequent.Introduce hook1 = new BRFrequent.Introduce(* Customer.*(*));
//the wildcards are important!
}
Now other hooks are able to access this mixin through the following code. Note that the customer variable is an instance of the Customer class.
around returning(double price) {
ICustomerInfo mixin = (ICustomerInfo) customer;
if(mixin.isFrequent())
return applyDiscount(price);
else return price;
}
__Good to know:__
* Casting an object to the inserted mixin is only possible inside hooks, inline refinements in a connector and refining classes
* Anywhere else, you have to use the following: //jasco.runtime.mixin.MixinManager.mixinOf(Object,Class)//
* Mixin interfaces have to implement the empty interface: jasco.runtime.mixin.IMixin
===== 5. Combination Strategies =====
Combination Strategies are able to manage the cooperation of aspects.
==== 0. Example Combination Strategy ====
class ExcludeCombinationStrategy implements CombinationStrategy {
private Object hookA, hookB;
ExcludeCombinationStrategy(Object a,Object b) {
hookA = a;
hookB = b;
}
HookList validateCombinations(Hooklist hlist) {
if (hlist.contains(hookA))
hlist.remove(hookB);
return hlist;
}
}
==== 1. Combination Strategies ====
* Filters the list of applicable hooks at a certain joinpoint
* Also allows to alter properties of encountered hooks
* Executed once for every joinpoint unless implements jasco.runtime.DoNotCache, then executed for every execution of joinpoints
* Added to connector using **addCombinationStrategy** keyword:
static connector DiscountConnector {
Discounts.BirthdayDiscount birthday = ...
Discounts.FrequentDiscount frequent= ...
addCombinationStrategy(new ExcludeCombinationStrategy(frequent, birthday));
}
===== 6. Stateful Aspects =====
TODO, refer to the [[documentation:stateful|tutorial and papers]] for now.
===== 7. Miscellaneous =====
==== 1 . Avoiding JAsCo weaving ====
In order to exclude classes from JAsCo weaving, one has to either [[documentation:running|list them as a jvm launch option]] or supply an annotation in the source code. JAsCo supports an annotation that can be placed on all java elements to exclude it from weaving:
jasco.runtime.annotation.NoJAsCoAOP
e.g. when supplying a class X with this annotation, JAsCo will never touch it.
e.g. when supploying method y of class X with is annotation, JAsCo will never touch method y, but might weave other methods of class X