Section 14.3. PROGRAMMING TRANSFORMATION


14.3. PROGRAMMING TRANSFORMATION

In the transformation architecture employed by JOIE, there are four main roles: the target program, the transformer, auxiliary code, and run-time support classes. The target is the original, untransformed program. The transformer is a classor collection of classesthat contains the logic to edit and manipulate the target. As part of that manipulation, transformers may insert new, already compiled, units of functionality directly into the target; these units are found in auxiliary classes, which may be bundled together with the transformer.

Auxiliary classes do not appear by name in the final running program; the transformer copies portions of their definitions into the target classes. Finally, a set of classes provides run-time support for the transformed classes. Typically, a transformer author bundles together the transformer, auxiliary classes, and run-time classes.

The distinction between auxiliary classes and transformer classes is important. Auxiliary classes are not classes that assist the transformer. They do not execute during the transformation process. Rather, they contain fragments of code that the transformer inserts into the target. Auxiliary classes lose their identity during transformation. The transformed application contains their code but no references to their names. This is analogous to the "base/meta" distinction in metaprogramming [12]. Here, both the target and the auxiliary classes are base code, while the transformer is the metaprogram that operates on both. Additionally, the transformer can obtain base code from other sources, such as by internally containing or referencing program fragments or by dynamic generation during transformation. However, the use of auxiliary classes represents good transformer-programming style.

Run-time classes are akin to auxiliary classes in that they do not execute during the transformation and are part of the resulting application. In contrast, however, the run-time classes are not copied into the target but retain their identity. Typically, the code found in auxiliary classes refers to run-time classes by name.

Making the transformer an executable (rather than declarative) program has implications for both selecting sites for transformation and inserting code. Since the transformer is a fully fledged program with private state, it can be extremely selective and customized about where and how it chooses to operate. For example, it could choose transformation sites based on the other content of the target method, apply only a set number of transformations, or act only when a method met some criteria (such as being a leaf method).

14.3.1. Selection

Key to the design of JOIE is its ability to carefully specify the selection of targets of transformation, including the points at which to insert code and the selection of target classes. Contrast this to systems that provide a set of permissible join points, including call sites, field accesses, and method boundaries; these systems are more intuitive and simpler. JOIE, by allowing arbitrary access to instructions, provides a more powerful and more dangerous interface, especially when coupled with the programmable nature of transformers described previously. For example, a transformer in JOIE can limit a transformation to once per basic block or, more powerfully, can insert code only if that location is not dominated by code inserted earlier.

Bytecode transformation can also target the entire program. Whole-program transformation can add a feature to every class of an application or, conversely, verify that certain properties are true of every loaded class. For example, one could extend every object in a system to be Observable. Whole-program transformation is best done at load time, as classes cannot execute in the JVM until they have been through the classloading process.

In contrast, a selective transformation targets a specific subset of application classes. The targets for a selective transformer might be listed in a configuration file, or the transformer can infer the targets from inspection of classes that reference them.

Sometimes, the programmer of the original, unmodified program will want to pass information about that program to a transformer to aid in selection. For example, while it can be difficult for a transformer to determine which methods leave a data structure in a consistent state, the programmer usually knows. In these cases, the programmer can define a labeling interface whose name is known to the transformer. A labeling interface is simply a standard Java interface (that is, a named set of method names with no implementations) that is used to pass information to the transformer. For example, if a method of a class were part of an interface called Consistent, the transformer would know to treat that method as one that left the data structure intact.

14.3.2. Use in AOSD

Separating the transformation logic from the inserted content is another important design choice. In binary architectures, aspects define their own placement. In composer architectures such as JOIE, a third entity applies aspects to designated locations in the code. These designs are not mutually exclusive, and most systems allow some mixture of the two, for example, by letting aspects refer to others. In general, however, composer architectures, especially when coupled with late or dynamic application of aspects (through transformation or otherwise), are an important building block for a more distributed and dynamic model of software development.

Binary architectures are best suited toward the use of aspect-oriented programming as an augmentation to traditional programming, improving the ability of a single programmer or coordinated team of programmers to separate concerns. However, composer architectures additionally support a model in which applications can be assembled, transformed, and adapted by third parties, including the end user. This has particular application toward adding aspects to legacy code [10]; in an important sense, however, all code is legacy code.

This broader model offers two advantages over tightly-bound aspect development: programs can be smaller, incurring the size cost of additional features only when clients request them, and transportable code can adapt to new services or interfaces made available by some hosts.

Lightweight. Placing certain aspects of functionality in transformers allows applications to be shipped with only their core functionality; no extras, such as logging or instrumentation, are included. This makes the resulting application cleaner and more lightweight and thus easier to transport over the Internet. The cost to transform the code and support the additional features is borne only by those sites that specifically request that functionality.

This has advantages for software management as well. Imagine an application that has five optional features implemented as bytecode transformations. That means there are thirty-two potential executable images of that program, one for every combination of included features. In a system that applies transformations only when requested, only the original (untransformed) program is stored. While postponing the decision of applying features does incur a (small) performance cost, it may be a preferable option when the potential executable images number in the hundreds or even thousands and when different users may require different subsets of available features.

Adaptable. Transportable programs assume a standard set of APIs that they use to invoke system services. Some hosts may offer extended services, such as a replication service or persistent store of objects. Standard transportable code will not know about these APIs and thus will be unable to use them. If appropriate, load-time transformation can modify the applications to use a new service's API (for example, by redirecting constructors to the persistent store). This allows the original version of the application to be platform-independent and still take advantage of new features on enhanced platforms.

However, most broadly, the advantage of this model of code development is that the potential number of programs increases significantly. If aspects, in whatever implementation form, remain locked inside development groups, they will only be used for a single application. If aspects are designed to be as orthogonal as possible, applicable to a broad range of target programs, then the number of potential programs increases as the product of available programs and aspects.



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