Hooksets

Hooksets allow us to select _where_ an aspect will apply.

In Reflex, Hookset is an interface that defines two highly-related to the Reflex internals methods. This is the reason why two implementations are provided:

  • PrimitiveHookset, that is able to match a set of points in the aplication according to a given operation.
  • CompositeHookset, that is able to compose other hooksets and match any of the application points matched by the hooksets it is composed of.

Execution Points

Here, we have talked aboud “execution points”. Formalizing what they are, we can say that an execution point is defined as an operation occurring at the application. Operations can be any of the following:

  • Message Send, represented by the MsgSend class. This operation matches statements that are method invocations:
object.hashCode() or string.substring(0, 5);
  • Message reception, represented by the MsgReceive class. This operation matches all the body statements of a method. It is the calle side operation for a message send:
public int hashCode(){
        <all statements>
}
  • Instantiation, represented by the Instantiation class. This operation matches statements using the keyword “new”:
new Object(); or new String("hello world!");
  • Creation, represented by the Creation class. This operation matches all the body statements of a contructor. It is the callee side operation for an instantiation:
public String(){
        <all statements>
}
  • Field access, represented by the FieldAccess class. This operation matches all statements that represents field accesses (both read and write):
System.out.println(this.x) or this.y = 228;
  • Cast, represented by the Cast class. This operation matches statements where a cast is used:
(Object) object; or (Appendable) string.replace(" ", "_");

With this stated, we can review the API of PrimitiveHookset. In general terms, only the constructor is of interest:

public PrimitiveHookset(Class aOperation,
                        ClassSelector aClassSelector,
                        OperationSelector aOperationSelector)

As you can see, it takes the operation it must match and two additional parameters we have not seen yet: a ClassSelector and an OperationSelector. We will review them now.

Selectors

Class Selectors

The existence of class selectors is to avoid examining all the classes of the system: they are asked to know if the class can contain execution points that can be matched by any Hookset. If none of the class selectors of all hooksets aswer that the class is of interest, Reflex simply does not analyze that class.

The ClassSelector interface is defined as follows:

public interface ClassSelector{
    public boolean accept(RClass aClass);
}

And its unique method accept returns true if the given class should be selected.

Operation Selectors

If a class selector selects a class, Reflex will analyze that class and will reify all operations on it. Then for each of these operations, the operation selectori will be asked if the operation is of interest. If it returns true, the assosiated hookset is said to match to that operation in particular.

The OperationSelector interface is defined as follows:

public interface OperationSelector{
    public boolean accept(Operation aOp, RClass aClass);
}

Where its unique method accept should return true if the given operation occurrence, found in the given class, should be selected.

As you can see, the hookset matching mechanism in Reflex is pretty powerfull, and, at the same time, performant.

One of the things we intentionally skipped is the presence of all those R* classes (that are reifications of the different structures of the application). We will review them later in this {section].