Section 15.5. THE BCEL WEAVER


15.5. THE BCEL WEAVER

In addition to the generic interception and nested loading functionality available to every weaver, JMangler also includes a fully functional weaver. The BCEL weaver provided with JMangler offers an API for the implementation of transformers components (or simply, transformers) and the ability to load sets of transformers and apply their transformations to all classes of a program. Added benefits over the direct use of BCEL [4, 11, 12] are the notion of transformer components, the simple composition of such components based on a textual configuration file, support for enforcing binary compatibility of transformations, and support for conflict-free automatic composition of independently developed transformer components.

15.5.1. Transformations and Aspects

Weaving can be seen as transformation of classes. Accordingly, an aspect can be interpreted as the specification of such a transformation that determines what is to be transformed and how it should be transformed. This can be generalized as the specification of conditions, interface transformations, and code transformations.

Conditions. Conditions are arbitrary Java Boolean expressions. Conditions enable implementation of the filter conditions of ComposeJ [6, 45] and the pointcut definitions of AspectJ [30].

Interface transformations. By default, JMangler supports all transformations of class files that do not violate binary compatibility [22]:

  • Addition of classes, interfaces, fields, and methods

  • Changes to a method's throws clause

  • Changes to a class's extends clause that do not reduce the set of direct and indirect superclasses

  • Changes to a class's implements clause that do not reduce the set of direct and indirect superinterfaces

  • Addition and changes of annotations that respect binary compatibility.

These transformations allow implementing the interface modifications expressible in current aspect languages, such as the introductions of AspectJ [30] or the hypermodule definitions of Hyper/J [39, 40]. If desired, the system can also perform transformations that break binary compatibility, such as the removal of methods.

Code transformations. Code transformations are changes of method code. They allow expressing the advices of AspectJ, traversals of DJ [38], filter actions of Composition Filters [6, 45], and method combination rules of Hyper/J [39, 40].

15.5.2. Transformers

Conditions and transformations that conceptually belong together can be implemented in one transformer component.

Transformers are Java classes that implement specific interfaces (Interface Transformer and CodeTransformer). A transformer component that implements the operations of the InterfaceTransformer interface can perform one or many related interface transformations. The same is true for code transformations. A transformer can play both roles by implementing both interfaces. Thus, it is possible for one component to provide a consistent set of related interface and code transformations. For instance, an accessor transformer needs interface transformations to create the accessor methods and code transformations to enforce their invocation in place of direct variable accesses.

15.5.3. Use of Transformers

Transformers are the basic unit of deployment and composition in the BCEL weaver. The transformers that should be applied to the classes of a program are specified in a configuration file that is passed as a parameter to the invocation of JMangler along with the main class of the program and the program arguments (see Appendix 15.A).

This scheme eases transformer component deployment in two ways: there is no need to write any code in order to apply and compose transformers, and the application of transformers is independent of the base programs to which they should be applied.

15.5.4. Unanticipated Composition of Transformers

Multiple transformers can be applied jointly to the same program by listing them together in one configuration file and by specifying the desired order of execution. This provides a simple way of composing existing transformers. However, it also raises one of the main challenges in the design of JMangler and of aspect systems in general: unanticipated composition of independently developed transformers.

The main issue here is that an execution order cannot be specified for transformers that have been developed independently without being specifically designed for joint use. Whenever independently developed transformers are provided as black boxes (which is the core idea of component-oriented development), the composer most likely does not have enough knowledge of their design and implementation in order to decide on the proper composition order. The same is true for independently developed aspects.

In this context, the problem is to determine automatically in which order transformers should be combined to achieve the intended semantics while avoiding unwanted side effects.

In the current version, JMangler does not have any way of determining order automatically.[4] However, we have reduced the scope of the problem by identifying a class of transformations for which order is irrelevant. It is possible to apply them iteratively until a fixed point is reached. In particular, iterative application of a set of positively triggered, monotonic interface transformations[5] is guaranteed to produce a unique fixed point, independent of the order in which the transformations are applied. Section 15.5.6 presents a short example that illustrates the effect of fixed point iteration. A detailed one is contained in [33].

[4] We have developed an automatic conflict detection and ordering mechanism [3, 32]. However, its integration into JMangler is a topic for future work.

[5] A transformation is positively triggered if it is initiated by the existence of a particular property of a program but must not be caused by the absence of a property. A transformation is monotonic if it adds properties to a program but does not remove properties.

This insight has influenced the design of JMangler in three ways:

  1. There is a conceptual and API-level separation of interface transformations and code transformations.

  2. JMangler supports by default only interface transformations that preserve binary compatibility, which is a different way of saying that it supports only monotonic interface transformations.

  3. JMangler provides the ability to iterate interface transformations until a fixed point is reached.

15.5.5. The Transformation Process

Figure 15-5 illustrates the previously described transformation process. The transformers specified in the configuration file passed as parameters to JMangler are applied to every loaded class. The transformation proceeds in two phases.

Figure 15-5. Transformation process implemented in JMangler's BCEL weaver: First, the interface transformations are applied iteratively until a fixed point is reached, then the code transformers are applied sequentially in the order specified in the configuration file.


In the first phase, interface transformers are activated:

  • Each interface transformer analyzes the classes under consideration, decides which transformations are to be carried out, and requests these transformations from the BCEL weaver.

  • The weaver collects the transformation requests of all interface transformers, checks the validity of the requested transformations (with respect to binary compatibility / monotonicity), and performs the transformations (in an arbitrary order).

  • This process is repeated until no further interface modification requests are issued. If an illegal transformation is detected, the process is aborted.

In the second phase, the code transformers are activated. They are executed exactly in the order indicated in the configuration file. Each code transformer analyzes the classes under consideration, decides which transformations are to be carried out, and performs these transformations directly, using the BCEL API [4, 11, 12].

15.5.6. Example

Consider a logging transformer, whose purpose is to log execution of all methods that call certain security sensitive methods. It can be implemented as a combined interface and code transformer.

Assume method m in class class should be logged. Then the interface transformer part creates a method m_log in class, which calls m after performing logging actions. The code transformer replaces calls to the original method m by calls to m_log at every join point where logging should be performed.

Now assume another independently developed interface transformer that adds a method to the program, say more2Log, which also fulfils the criterion for being logged.

Iterative execution of the two interface transformers guarantees that there exists a more2Log_log method when the logging code transformer is activated. Thus, the invariant assumed by the code transformer is fulfilled.

If transformers were executed just once, their user would need to know enough of their internal working in order to determine that the second transformer needs to be activated before the first one. Even worse, if the transformers were mutually dependent, there would be no way of using them together without iterative application [33].

This example illustrates that fixed point iteration provides the guarantee that each interface transformation is applied to the entire program, including parts added by other interface transformers. Code transformers can therefore rely on the fact that the invariants they assume are indeed met throughout the program.

Now that we know how to compose and apply existing transformers with JMangler and understand the transformation process, the only missing part of the picture is how to write transformers. This is explained separately for interface and code transformers.

15.5.7. Creation of Interface Transformers

From a technical point of view, an interface transformer is a Java class that implements the interface InterfaceTransformerComponent. The main method in this interface, ExtensionSet transformInterface(Unextendable ClassSet[6]), analyzes a set of classes and determines a set of extensions that should be performed on these classes.

[6] An UnextendableClassSet is unextendable just in the sense that transformers cannot add or remove classes from it. However, they can modify its classes, and the framework can add new classes that get loaded during the transformation process.

For instance, the transformer shown in Listing 15-1 requests the addition of the interface java.lang.Serializable to each class in the class set passed as parameter.

Listing 15-1. An interface transformer that adds the interface java.lang.Serializable to each class that does not implement it already
 public class MyTransformer implements InterfaceTransformerComponent {   // The interface to be added.   private String interfaceName = "java.lang.Serializable";   // This method will be invoked by JMangler to compute the   // interface transformations requested by this transformer   // component.   public ExtensionSet transformInterface (UnextendableClassSet cs) {     ExtensionSet es = new ExtensionSet();     // Analyze and transform all classes in the class set.     Iterator iter = cs.getIteratorForTransformableClasses();     while (iter.hasNext()) {       // The BCEL representation of a class file.       ClassGen clas = (ClassGen)iter.next();       // The conditional transformation.       if (!Condition.implementsInterface (clas, interfaceName)) {         es.addInterfaceToClass(this,                                clas.getClassName(),                                interfaceName);       }     }     return es; // Give JMangler the collected transformation                // requests.   } } 

A complete version of this and many other transformers can be found on the JMangler web site and in the samples package of the JMangler distribution. The samples can be taken as templates for writing interface transformers. This is easily done after a short study of the classes ClassGen and ExtensionSet. The class ClassGen is part of the BCEL library [4, 11, 12] and provides the basic operations to analyze and transform a class file. All monotonic interface modifications listed in Section 15.5.1 have their counterparts as methods of the ExtensionSet set class, whose purpose is to collect transformation requests and execute them under the control of JMangler, as described in Section 15.5.5.

15.5.8. Creation of Code Transformers

A code transformer is a Java class that implements the interface CodeTrans-formerComponent. The main method in this interface, transformCode (UnextendableClassSet) analyzes the set of classes passed as parameter and modifies them directly using the BCEL API.

Creating code transformations requires an above-average understanding of the internal workings of the Java Virtual Machine, its instruction set, its class file format, and the BCEL library. However, since many tasks follow quite fixed idioms, learning to program at this level is not as difficult as it may appear. A tool that is very helpful in this context is the BCELifier [4]. From a plain Java method, it creates the BCEL code that will create exactly the input method when executed. BCELifier is provided on the BCEL web site and is also included in the JMangler 3 release.

An example of an advanced application, code coverage, that can be conveniently expressed in about one page of code is presented in Appendix 15.A. A short introduction to code coverage is given in Section 15.6.3.2.



Aspect-Oriented Software Development
Aspect-Oriented Software Development with Use Cases
ISBN: 0321268881
EAN: 2147483647
Year: 2003
Pages: 307

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net