Section 16.2. DESIGN NOTATION


16.2. DESIGN NOTATION

This section describes our UML profile to support the design of aspects with JAC. Stereotypes are proposed to qualify classes implementing a non-functional concern (Section 16.2.1) and to qualify pointcut relations (Section 16.2.2). An example using these two concepts is given in Section 16.2.3. Section 16.2.4 discusses the similarities between AOP and the use-provide relationship.

16.2.1. Aspect Component Classes

Aspect components (ACs) are the central point of our AO framework. They are the implementation units that define extra characteristics that crosscut a set of base objects. They are defined in classes called AC classes. The key characteristic of JAC is that the base objects that are involved in a crosscut are not necessarily located in a single container.

An AC class is tagged with the <<aspect>> stereotype. It contains attributes and methods whose semantics differ from regular methods. AC methods are meant to extend the semantics of regular classes. The extension is performed on well-defined implementation points so that these points actually use aspect services to integrate new concerns. For example, a base class can be made to use a cache interface if the aspect implements some caching concern.

Each AC method defines some code and extends the semantics of some base methods according to a modality defined by a stereotype. The stereotypes for an AC method m are:

<<before>> m(...) Method m is executed before a given point (to be specified later, see Section 16.2.2) of the base program.

<<after>> m(...) Method m is executed after a given point of the refined program.

<<around>> m(...) A part of m is executed before and another part is executed after a given point of the refined program (these two parts are defined within the implementation of m).

<<replace>> m(...) Method m modifies a given point of the extended program implementation by replacing it by the implementation of m.

<<role>> m(...) Method m can be invoked on the objects that are extended by the AC class; moreover, m can access the extended class attributes and the attributes of the AC class. This is similar to the introduction concept of AspectJ.

For example, Figure 16-1 shows the caching AC class Caching (with the <<aspect>> stereotype). As its name suggests, this AC class provides a caching extension mechanism. The job of storing and retrieving values from the cache is delegated to the Cache (regular) class. The whenWrite method of the AC class Caching is tagged with the <<after>> stereotype. It is executed after any base method associated with whenWrite in the pointcut definition (see Section 16.2.2). The whenRead method is tagged with <<around>>. It is executed before and after some base methods.

Figure 16-1. Definition of a caching concern with an AC class.


16.2.2. Pointcut Definition

A pointcut relation links an AC method belonging to an AC class to a set of elements of a base program. Pointcuts in JAC are limited to method calls; we do not introspect at the instruction level. Several arguments justify this decision. First, experiments with the fully reflective compiler OpenJava [32] taught us that reifying the whole code structure produces an unacceptable performance for real applications. Second, before extending the semantics of an application, it is necessary to understand its original semantics (we cannot extend something that is not clearly stated). Most of the time the original semantics are defined through an API, that is, primarily through method signatures. So base methods are definitively the best place to perform semantic extensions.

JAC supports pointcuts on both classes as on individual instances.

16.2.2.1 Class-Level Pointcut

This level is similar to the one found in AspectJ. All instances of the classes involved in the pointcut are extended by the aspect component. In this case, a pointcut relation is an oriented association from an AC class towards one or several classes. The association is stereotyped with <<pointcut>>. The roles have special semantics; they mention which methods of the client class are extended by which AC methods. The semantics of the elements mentioned in Figure 16-2 appear in the following list.

  • A pointcut relation p must go from an AC class A to a class C (if several classes are involved in the pointcut, several links are drawn between the AC class and the classes).

  • Cardinality c1 is the number of aspect instances of A that can be related to one member of C (default is 0-1).

  • Cardinality c2 is the number of members of C that can be related to one instance of A (default is * for all).

  • Role r1 is the name of an AC method defined in A that is applied at each base program point denoted by role r2.

  • Role r2 defines a base program crosscut; i.e., a set of join points. R2 is a logical expression (with AND, OR, and NOT operators) where each term is of the form <qualifier> <methodExpression>.

    • Two mains qualifiers are used: ? denotes a method execution point, and ! denotes a method invocation point.

    • <methodExpression> is either a fully defined method prototype (e.g., get():int) or a partially-defined one with regular expressions (e.g., get*(*):int matches all methods whose name starts with "get," that return an integer, and that take any parameters), or an expression based on the keyword defined in Table 16-1. For instance, GETTERS(a, b) matches the getter methods for fields a and b. Like in component frameworks such as JavaBeans, naming conventions are assumed on method names: getters/setters should be named get/set followed by the field name (starting in uppercase). Adders/removers should be named add/remove and take an object as a unique parameter. Introspection and bytecode analysis are performed each time a new class is loaded in the JAC framework. A meta model of the class is constructed on-the-fly with annotations that support the semantics defined in Table 16-1. For instance, each method bytecode is parsed to determine whether some fields are modified or not. If so, the method is tagged as a modifier in the RTTI aspect.

      Table 16-1. Keywords Allowed in Pointcut Expressions

      Keywords

      Semantics

      ALL

      All the methods

      STATICS

      All the static methods

      CONSTRUCTORS

      All the constructors

      MODIFIERS

      All the methods that modify the object state, i.e., all that modify at least one of the fields

      ACCESSORS

      All the methods that read the object state

      GETTERS[(...)]

      The getters

      SETTERS[(...)]

      The setters

      ADDERS[(...)]

      The methods that add an object to a collection

      REMOVERS[(...)]

      The methods that remove an object from a collection

      FIELDGETTERS

      All the getters for primitive fields

      FIELDSETTERS

      All the setters for primitive fields

      REFGETTERS

      All the reference getters

      REFSETTERS

      All the reference setters

      COLGETTERS

      All the collection getters

      COLSETTERS

      All the collection setters


  • As any UML model element, the pointcut relation can be "tag" to express extra semantics that can be used when implementing the model toward a concrete platform; some semantics examples are shown in further sections.

Figure 16-2. The pointcut association: relating aspects to classes.


Figure 16-3 shows two pointcut relations that implement a caching aspect by using the AC class defined in Figure 16-1. This aspect diagram must be read as follows:

  • After the execution of any setter (a method that changes the object state) of a Server object, the program must execute the whenWrite AC method.

  • Around (i.e., before and after) the execution of any getter (a method that reads the object state) of a server object, the program must execute the whenRead AC method.

Figure 16-3. The full caching aspect.


16.2.2.2 Instance-Level Pointcut

Besides the previously described mechanism, JAC also allows developers to define pointcuts on a per-instance basis. This can be useful in several cases. For instance, a persistence framework may need to define objects as persistent roots from which other referenced objects persist. A multi-user application may want to exchange data between several users by using specific objects. In a distributed environment, server objects may need to be customized, because they must cope with heterogeneous running contexts (in terms of network properties, provided and expected quality of service, and so forth.). In all these cases, instances belonging to the same class need to be extended differently.

In Java, classes are straightforwardly named. Objects, on the other hand, present a problem: There is no direct naming scheme for identifying individual objects in Java. The solution taken in JAC is to let the framework attach a unique name to each created instance: The name is the concatenation of the class name in lowercase and of an auto-incremented integer (e.g., server0 designates the first created instance of class Server). The framework provides an API a way to retrieve objects based on their name and to customize names assigned to objects. For instance, a field known to be a primary key may be used to name objects. To let designers express a per-instance pointcut, aspect component side roles in the UML diagram (i.e., r1 in Figure 16-2) can be extended with an instance name or a regular expression on instance names. For instance, ?SETTERS|server0 designates the execution points of the setter methods of instance server0, and ?GETTERS|server[1-3] designates the execution points of the getter methods of instances server1, server2, and server3.

When distribution comes into play, pointcut definitions can also be filtered based on container names (a container name being an RMI or CORBA URL depending on the chosen communication protocol between JAC remote containers). The idea is to let designers express behaviors that are dependent on the context in which components are deployed. For instance, one may want to install an authentication aspect only on specific critical hosts, whereas the rest of the application deployed on other hosts stays unmodified, or one may need to install a logging aspect only on a given container. To allow this, pointcut expressions can be extended with container names or regular expressions on container names. Merged with the previous extension for instance names, this leads to a complete scheme where pointcut expressions are of the form: qualifier methodExpression | instanceExpression | containerExpression with instanceExpression and containerExpression being optional. For instance, ?ACCESSORS||rmi://myHost/s1 designates the accessors execution points of instances located on JAC container rmi://myHost/s1.

16.2.3. A First Simple Example

This section illustrates the programming model of JAC based on the Caching aspect of Figure 16-3. The details of the API and some tutorials can be found on the JAC web site [10].

Listing 16-1 gives the code of the Caching aspect component. An aspect component extends the jac.core.AspectComponent class. Among other things, this class provides a method for expressing a pointcut. The parameters of this method are the base class this pointcut designates, the qualifier methodExpression as a string, the class containing the AC method, and the AC method involved in the pointcut. Listing 16-1 defines two such pointcuts. Additional pointcut methods are available when instanceExpression and containerExpression are to be associated with the pointcut.

Listing 16-1. A simple aspect component implementing a caching concern
 import jac.core.AspectComponent; import jac.core.Wrapper; import jac.core.Interaction; public class Caching extends AspectComponent {   public Caching() {     pointcut(       "Server","?SETTERS",CachingWrapper.class,"whenWrite");     pointcut(       "Server","?GETTERS",CachingWrapper.class,"whenRead");   } public class CachingWrapper extends Wrapper {   private Cache cache = new Cache();   public void whenWrite( Interaction i ) {     proceed();     Object value = i.arg[0];     cache.setValue(value);   }   public Object whenRead( Interaction i ) {     Object value = cache.getValue();     if ( value == null )       value = proceed();     cache.setValue(value);     return value; } } } 

AC methods are defined in wrapper classes (that extend the jac.core.Wrapper class). AC methods accept only a single parameter, a jac.core.Interaction instance. They may return any parameters. The rationale behind this constraint is that AC methods are upcalled by the JAC framework whenever a call to their base method is issued or executed (i.e., whenever the call matches the pointcut expression). An interaction object i provides data about the current call: arguments of the call (in the i.arg array), a reference to the base object (i.wrappee), and some methods to store and retrieve context parameters; for instance, parameters that can be added by an AC method on the caller side and that can later on be retrieved on the receiver side by another AC method.

16.2.4. Extended Design Notation for Distribution

16.2.4.1 The Group Paradigm

In the caching example, the semantic modification introduced by the caching concern into the application is quite symmetric. Concretely, all objects modified to implement caches (the Server objects) can be seen as modified by the same abstract transformation rule. However, one may want to weave the caching aspect to different classes. Thus, another designation mechanism is needed to express the fact that a set of well-defined objects implements the same concern.

This need for a new kind of structured elements brings us to focus on the group paradigm. A group is an abstract representation of a set of instances that do not necessary have homogeneous functional types, but are logically grouped together, because they implement the same service (server groups) or use the same one (client groups). Elements of a group "share the same common secret."

Figure 16-4 represents the application of the caching aspect on a group of servers that implements the server part of a simple client/server application. We use an instance diagram so that it becomes obvious that the group on the top of the figure is a non-uniform set of instances (the three instances a, b, and c belong to three different classes A, B, and C). As shown in this figure, the application of the caching aspect creates a new group that contains instances of a Cache class that provides the caching functionality. In other words, we can say that these Cache instances belong to a server group that provides a caching functionality for the client group formed by the a, b, and c servers.

Figure 16-4. Relating aspects to groups.


16.2.4.2 A Group-Based Definition of Aspects

Abstractly, the introduction of the caching concern within the original client/server application is done by the use of the services the Cache group interface provides to the servers group. This is represented in UML by using the <<use>> relation, as shown in Figure 16-5. In the general case, implementing a new concern may require using several interfaces. In these cases, several clients can be related to several servers through some <<use>> relations. Finally, a simple but sufficient definition of an aspect within this context is:

Figure 16-5. The use relationship between a client group (the base program) and a server group (the aspect program).


Definition 1 An aspect is the implementation of one or many use-provide relationship(s) between one or many client group(s) and one or many server groups.

The model of Figure 16-5 clearly brings up a use-provide relationship between a client group (the servers), and a server group (the caches) that defines the group-level services getValue(), setValue(Object), and invalidate(). The implementation of this relationship requires modifying the client group member object's implementation to introduce the caching concern.

At the analysis level, the application designer can add a tagged value aspect: aspectName to all the <<use>> relationships implemented by the aspect called aspectName to express that a use-provide relationship is implemented in an aspect-oriented fashion (see Figure 16-5). Thus group-oriented modeling allows the designer to specify in a comprehensive way which parts of the application are aspects and which parts are not. In fact, for each modeled group-level use-provide relationship, aspect-oriented techniques can be used to separate concerns within the final implementation. Note that this modeling, which is a high-level view of the application, defers the specification of pointcuts to some later stage refinements using the notation presented in Sections 16.2.1 and 16.2.2. Finally, each time the designer encounters the pattern of one or several use-provide relationships between groups, he can ask himself if an aspect would be well suited in this case.

Whether to apply an aspect is mainly related to designer experience and choices. However, we can give some clues on when an aspect is better suited than a classical design. Aspects are often better when

The client group is heterogeneous. This means that the use of the server services is spread over all the client-group member classes. This is in essence a crosscutting concern, and some extra design is necessary to cleanly modularize all the dependencies involved. In this case, the use of an aspect can greatly simplify the programmer's task and help ensure good maintainability and evolvability of the final implementation, even if some concerns are added afterwards.

Several homogeneous client groups use the same server group. This is exactly the same situation as the previous one since several homogeneous groups can be modeled via one heterogeneous group.

Several client groups use several server groups but seem to be of the same concern. This is a more contextual choice that depends on the knowledge of the modeled domain.

Figure 16-6 sums up the notions introduced in this section and proposes a UML metamodel where additions introduced by JAC are drawn with bold lines.

Figure 16-6. The UML extension metamodel.




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