Second Workshop on Aspect-Oriented Software Development by the GI SIG 2.1.9 – Object-Oriented Software Development Bonn, February 21-22, 2002
Pascal Costanza G¨ unter Kniesel Katharina Mehner Elke Pulverm¨ uller Andreas Speck (eds.)
Organizing Committee Pascal Costanza University of Bonn Institute of Computer Science III
[email protected] http://www.pascalcostanza.de G¨ unter Kniesel University of Bonn Institute of Computer Science III
[email protected] http://www.cs.uni-bonn.de/∼gk/ Katharina Mehner University of Paderborn Mathematics/Computer Science Department Database and Information Systems Group
[email protected] http://www.upb.de/cs/mehner.html Elke Pulverm¨ uller Universit¨at Karlsruhe Fakult¨ at f¨ ur Informatik, IPD
[email protected] http://i44w3.info.uni-karlsruhe.de/∼pulvermu/ Andreas Speck Intershop Research
[email protected]
Editorial Modularisation as a means to achieve separation of concerns is a key concept in the development of complex software. A fundamental goal is the independent specification of system aspects and their subsequent integration. There have been several novel approaches which try to find new dimensions for separation of concerns beyond the “traditional” concepts of module and class. For examples of such “advanced separation of concerns” we cite Adaptive Programming, Aspect-Oriented Programming, Composition Filters, Hyperspaces, role modeling, Subject-Oriented Programming, and so on. Recently such approaches have been subsumed under the umbrella term Aspect-Oriented Software Development (AOSD), whose themes, in addition to programming language extensions, also encompass enhancements of traditional analysis and design methodologies. Such a new and emerging field has yet to garner a uniform conception of its scope and a definition of its central terms. After the success of the first workshop by the GI on this topic, and in the run-up to the 1st International Conference on Aspect-Oriented Software Development (April, 23-26, 2002), the aim of this workshop is again to provide room for fruitful discussions among various academic and industrial working groups who are involved with issues of aspect-oriented software development and related themes. We have accepted 11 papers for this year’s workshop whose topics cover a broad range from theoretical reasoning about aspect-oriented systems to practical applications thereof. They are all included in this technical report. They can additionally be downloaded from the workshop’s website which can be found at http://i44w3.info.uni-karlsruhe.de/∼pulvermu/workshops/aosd2002/. Further results from the discussions of the actual workshop are also available at this site. The organizers are indebted to the members of the program committee for their support, and to the authors for their submissions. P. Costanza, G. Kniesel, K. Mehner, E. Pulverm¨ uller, A. Speck
Program Committee Mehmet Aksit, University of Twente, Netherlands Kai B¨ollert, Ilmenau Technical University, Germany Pascal Costanza, University of Bonn, Germany G¨ unter Kniesel, University of Bonn, Germany Ralf L¨ammel, Free University of Amsterdam, Netherlands Katharina Mehner, University of Paderborn, Germany Mira Mezini, Technical University of Darmstadt, Germany Elke Pulverm¨ uller, University of Karlsruhe, Germany Andreas Speck, Intershop Research, Jena, Germany ´ Mario S¨ udholt, Ecole des Mines de Nantes, France Shmuel Tyszberowicz, University of Tel Aviv, Israel
Contents I
Implementing and Reasoning about Aspects
1 C. Constantinides, T. Skotiniotis Reasoning About a Classification of Cross-Cutting Concerns in Object-Oriented Systems
1
2 S. Hanenberg, R. Unland A Proposal For Classifying Tangled Code
7
3 A.M. Reina, J. Torres Analysing the navigational aspect
13
4 A. Speck, M. Clauss, B. Franczyk Concerns of Variability in “bottom-up” Product-Lines
19
II
Aspects and Distributed Systems
5 R. K. Joshi, N. Agrawal AspectJ Implementation of Dynamically Pluggable Filter Objects in Distributed Environment
25
6 P. Kellom¨aki Formal Aspects for Distributed Systems
35
7 H. Mili, H. Mcheick, S. Sadou Distribution and aspects
41
III
Language Extensions, Frameworks & Tool Support
8 K. Gybels Using a logic language to express cross-cutting through dynamic joinpoints
49
9 R. Hirschfeld Advice Activation in AspectS
55
10 S. Schonger, E. Pulvermueller, S. Sarstedt Aspect Oriented Programming and Component Weaving: Using XML Representations of Abstract Syntax Trees
59
11 D. Vollmann Visibility of Join-Points in AOP and Implementation Languages
65
Part I
Implementing and Reasoning about Aspects
Reasoning About a Classification of Crosscutting Concerns in Object-Oriented Systems Constantinos A. Constantinides Department of Computer Science and Information Systems Birkbeck College, University of London
Therapon Skotiniotis College of Computer Science Northeastern University
[email protected]
[email protected]
Abstract In this paper, we discuss some issues regarding the nature and behavior of crosscutting concerns in OO systems. We further argue that aspects must be defined as first-class abstractions in order to be manipulated as such and thus to provide for reusability and dynamic adaptability as well as for the creation of dynamically loadable aspect repositories.
1. INTRODUCTION Object Orientation has provided the means to modularize data abstractions along with operations on them. It further provided mechanisms to group, reuse and extend behavior as well as internal component structure. Recent research has demonstrated that OOP gives rise to certain problematic issues. More specifically, inheritance anomalies [18] emerged from the discussions on conflicts between synchronization and reuse and the need for better separation between synchronization code and the main functionality in concurrent programs. Generalizing on inheritance anomalies, code tangling [16] has given rise to Aspect-Oriented Software Development (AOSD), with several technologies being developed to tackle this issue while forcing software engineers to revisit the notion of concerns and issues of their separation. A component is a structure that addresses a concern. At the implementation level it is defined by a module with welldefined behavior and an interface that can be used as a building block for large software systems. A desired property, albeit not a necessary condition, includes plug-compatibility in order to minimize code duplication and maximize code reuse. An object is an example of a component and the dominant decomposition of Object-Oriented Analysis and Design (OOA/D) has stressed the importance of a component hierarchy. On the other hand there should, in our opinion, be a difference between an aspect at a conceptual level and one at the implementation level. Conceptually an aspect is a concern that affects the semantics or the performance of other concerns. At implementation level of traditional paradigms, an aspect cannot be localized in a single functional or reusable module. Different AOSD technologies support the notion of an aspect as a modular unit that encapsulates a related set of actions that take place at well-defined execution points throughout the base program referred to as joinpoints. Under AOSD, both design and implementation stages maintain a clear view of the concerns in the problem domain. If developers view the system as a black-box during requirements and analysis, they will then focus on the main functionality of the system and up to that point decomposition would be functional and component-dominant, with aspects as second-class if present at all. Aspects would tend to arise more clearly during design and they will eventually have to be treated as equal with components in the sense that the
eventual design class diagram will be built with no dominance of components over aspects. Further, the ability to provide component and aspect off-the-shelf (CAOTS) technologies can result in a high level of reuse and thus provide for a faster development, as well as for a high level of software maintenance. In this paper, we discuss some issues regarding the nature and behavior of aspects, and we argue that it would be advantageous if aspects are defined as first-class abstractions in order to be able to be manipulated as such and thus provide for a high level of reusability and dynamic adaptability. This can also enable formal modelling with the support of UML. We further discuss issues that arise in order to obtain CAOTS.
2. SUPPORT FOR CAOTS Although a clear distinction between a component and an aspect was provided in [12, 16], programming languages and tools deployed to enforce AOSD have yet to provide a mechanism (abstraction level) with which CAOTS can be achieved. We believe that a means to group (modularize), as well as to define the behavior of an aspect, will be a step in this direction for the following reasons: (1) modularization will allow for better abstraction and a higher level of reuse, (2) aspect types could then be defined to provide a means to characterize the intended behavior of aspects, and (3) at the moment technologies that support AOSD provide mechanisms to group (and / or organise) aspects depending on the concern that is addressed. For instance, in AspectJ [11] one can define abstract aspects from which new aspects can then be defined through inheritance, thus providing programmers with an aspect hierarchy that holds aspects of similar or sharing behavior. One would argue that the principle of substitutability should apply to aspects. The hierarchy of aspects as specified by inheritance hierarchies denotes subtyping thus supporting code reuse. The inheritance operation, as it is provided by some OO languages like Java is therefore tangled with both concerns. Allowing separate definitions for behavioral subtype and code reuse will allow for better separation at the language level. This separation could be then exploited in order to check that subtypes are used correctly by the runtime system. The issue that we see here is that separation is simply the first step in a divide and conquer technique. Separation alone does not solve all our problems, but rather it refines the problem to smaller, more distinguishable and easily manageable parts. Attaching, or composing these units (components) together in the correct order for a specific problem, will yield the final semantically correct program for the task at hand. Thus, the ability of a language or tool to provide constructs to define each concern has to be complemented with its ability to further allow for the definition of aspect/component com-
position. We would also like for a language or tool to provide a flexible mechanism by which both aspects and components could be easily reused and composed together into a running program.
3. OPEN ISSUES IN AOSD TECHNOLOGIES There are currently a number of different proposals that describe aspect-oriented software architectures. Although the mechanism of weaving lies at the centre of their differences, they all have the same goals: Better abstraction than what has so far been achieved with current (OOP, or other) methodologies, higher modularity and higher degree of reuse. In this section, we would like to raise the following concerns: (1) Some of the open issues regarding the design and implementation of an aspect oriented architecture lie at the means to better express the aspectual properties of systems. Should one use an aspect language or a more general framework? What are the tradeoffs? (2) Another issue is the level at which aspects and components integrate. Should the integration be at the source code or at the object code? (3) To what degree should an aspect oriented architecture support an open system? Should it enable dynamic adaptability? (4) To what degree should reusability be supported? Do we want aspect instances to be made available in dynamically loadable libraries? and (5) Should an architecture further enable formal verification of system properties? Do we want our system to accept all dynamic attachments unconditionally or should a verification step be added to safeguard against inappropriate compositions (either due to an interface mismatch or failure to support pre- and postconditions in aspects or components).
3.1 Static vs. dynamic weaving Aspect thinking has been traditionally present implicitly in software systems where aspects were manually woven into components (and into each other). One difference in the proposals for supporting AOSD resides in the way in which aspects are weaved across the functional components of the system. How weaving will be achieved can depend on a number of factors. One factor is whether one would decide to provide linguistic support for aspect definition and the inlining of aspect code into functional code, or whether one would use other technologies such as reflection (to address aspect definitions on the meta-level) or even a more general framework approach. A distinction can be made here between static and dynamic weaving. Static weaving implies that the code injected into the relative base system is solely dependent on the static properties of the base program. On the other hand dynamic weaving refers to the ability of the language or system to allow for runtime evaluation in order to resolve aspect execution point definitions (pointcuts) and the incorporation of advice at the resolved execution point, as in the case with dynamic joint point designators of AspectJ. For example, the code below pointcut getters() : call (public void getX()) && target(Readers)
specifies getters() to be a dynamic pointcut referring to all calls of getX() to objects of type Reader. AspectJ allows for both a method name as well as the target object to be determined at run-time through regular expressions and late binding respectively, thus providing for dynamic join points.
The pointcut below pointcut Mytracer() : call( * A.get*(..) && this(B))
is the conjecture of all method calls with any return type, whose name matches the pattern get*, on object A, and the currently executing object is of type B. It essentially picks up all possible join points that satisfy both of the predicates as described above. Static weaving (i.e. at source code ala AspectJ) brings about the advantages of comparable running time (to programs written without AOP) and also allowing for a dynamic join point model through the deployment of reflection / call graph analysis. On the down side though, the aspectual code (advice as well as pointcuts) are no longer distinguishable at run-time. Therefore aspects cannot be materialized at runtime making runtime reconfiguration hard (if not impossible). The extend to which a language supports join point definitions is implementation dependent. In AspectJ, for example, the flow graph allows for broad definition of join points. However, AspectJ does not support aspect instantiation or separate compilation. As a result, run-time adaptability is not supported. Other feasible approaches to handle dynamic weaving is to implement aspects using meta-objects. DJ-Aspects [21] is a proposal that addresses dynamic weaving through the use of metaprogramming. Other approaches include the AMF [2, 4, 5] that provides dynamic weaving in a framework. We believe that ideally an implementation should support both static and dynamic weaving.
3.2 Level of weaving and life span of aspects The level of weaving defines the point up to which one manages (or wishes) to achieve separation of concerns in the system and it is also related to the notion of life span of aspects. The level of weaving moves along the compilation axis, and it can be pre-compile, compile or post-compile (execution time) weaving. When aspect code is inlined into component code before compilation, aspects do not exist at run-time. Reflective technologies such as DJ-Aspects address aspect definitions at meta level. With reflective systems, aspect code exist at the source as well as in the run-time system. Aspectoriented frameworks also achieve separation of concerns until execution time.
3.3 Openness property: Static and dynamic adaptability As requirements change and as slightly different problems arise over time, a system must be able to change and evolve. An essential requirement for complex systems is that they shall have an open software architecture by which noninvasive adaptability can be performed, i.e. concerns can be dropped, reconfigured or deployed and be connected with newly installed concerns, without in each case forcing reengineering of either the system itself or the client code. In the context of AOSD, adaptability is essentially a form of composition of concerns. Dynamic adaptability ensures that runtime requirements can be met without the need to halt the running system in order to ensure proper reconfiguration. Essential for the provision of dynamic behavior is the survival of aspects at run-time [17]. Recent work by [15] has further provided a formal approach which allows for dynamic aspect adaptability to be realized from a static, type safe environment.
A categorization of aspects can be beneficial towards the understanding of their nature. In the subsequent subsections a categorization of aspects is presented based on several design dimensions.
traversal specification denotes. Traversal semantics being structure-shy [20], allow for adaptive programs that apply to a range of OO designs (i.e. class graphs). The AMF does not support inter-object crosscutting. On an intra-object level, the AMF supports one aspect definition for each method associated with this aspect.
4.1 Functional vs. non-functional
4.3 Layer span
4. TOWARDS ASPECTS
A
CLASSIFICATION
OF
Since the definition of an aspect is that it is a concern that produces tangling between two or more concerns, the nature of aspects does not confine them to being non-functional requirements. Further, aspects are concerns that are dependent on the problem domain. As a result, aspects may address either functional or non-functional requirements. Functional requirements address the behavior of the system in terms of the services it provides, whereas non-functional requirements attach constraints to these services, thus affecting the performance and semantics of the system. As an example, consider a GUI application that can display quadrilaterals. One would like to enhance the GUI program so that each drawn quadrilateral also has a title bar on its one side so that the user can minimize or maximize the image. Solutions to this problem vary, one way to go about this problem is to extend the existing class (thus acquiring all its operations). This will allow the addition of the code responsible for creating the title bar in the extended class, while still having access to the parent’s code [9, 10]. By capturing the extended operation of the title bar in an aspect one will simply weave the aspect at specific execution points within the program so that it is called when needed. Notice that the aspect solution to the problem does not require any changes to the clients that use the GUI application. The clients can still send their requests to the same objects. In the inheritance solution all clients that would like to use the new title bar feature need to know that there is a different class (the subclass) that implements this functionality so that they can now call the new extended class for the new service. Detailed discussion of this problem (otherwise known as the “extensibility problem”) and its solution using units and mixins can be found in [10]. On the other hand, examples of non-functional requirements include synchronization, scheduling, authentication, tracing, and logging.
It is also important to distinguish between aspects that may exist at the system level and aspects that may exist at the application level while some aspects may cut-across these layers. An example of a multi-layer aspect is Quality of Service, which may span the application layer, the operating system layer, and the network layer as well. Another multi-layer aspect example would be encryption with the existence of different algorithms at each layer.
4.2 Component span
4.4.1 Contracts to verify functional components
In an object-oriented system, aspects could be categorized according to their level of crosscutting in the class hierarchy of a system. This approach can identify intra-class (intraobject) or inter-class (inter-object) aspects. Naturally, the two categories are not mutually exclusive, as one aspect may cut across several methods of one class but at the same time it could cut across different objects. To this end it is necessary to distinguish between aspects on the conceptual level and on an implementation level. Consider a collection of classes that provide different services in a concurrent system. At a conceptual level, synchronization is one possible aspect of concern. However, different technologies would address this aspect differently at the implementation level. AspectJ is able to provide one aspect definition that can address both intra-object and inter-object crosscutting. In the Composition Filters model [1], filters may address intra-object and inter-object concerns as well. DJ/DemeterJ [20] allow one to specify advice (through visitor methods) that will take effect on the subset of classes that the
When assertions are placed in aspect interfaces, componentaspect communication would then be based on well-defined protocols, thus observing the semantics of the system. Using contracts implemented as aspects, developers will be able to allow each program to define pre- and post-conditions as well as invariants. Contract definitions can then be checked at compile or runtime [9] to verify that the composition is valid and correct according to the contracts set forth by the developer. In general we would like to have aspects to be concrete enough to be identified and managed at runtime as first-class entities, but also general enough to support obliviousness and quantification when it comes to AOP [8]. Further, we would like to stress the importance of Aspects as modular and instantiable entities. This ontology of aspects allows for dynamic adaptability to be possible in the AMF. The fact that we can refer to aspects (as classes in AMF) to manage them allows for pluggable and reconfigurable, at runtime, systems.
4.4 Support for assertions and Design by Contract We can also view aspects with respect to the degree to which they can support Design by Contract (DBC) [19]. Under this principle, a software system is viewed as a set of communicating components whose interaction is based on precisely defined specifications of some mutual obligations (contracts). The concept of deploying assertions and DBC in the context of AOP was discussed in [2, 3, 13]. DBC was introduced in the context of the Eiffel programming language, where a contract is “hard-wired” in the class definition and it is inherited. Further, in iContract [14] assertions are propagated along inheritance and interface relationships. Separating contracts from the functional components could achieve a higher level of reusability and adaptability. In the case of concurrent behavior, this would avoid inheritance anomalies. Implementing DBC in an AOSD environment that will view aspects as a first-class abstractions will enable a more flexible and dynamic contract deployment that will facilitate the separation of code reuse from behavior reuse in an inheritance operation. Currently no AOSD technology enforces DBC but the current implementation of AspectJ can support the definition of contracts as aspects through the implementation of pre- and postconditions.
4.4.2 Contracts to verify aspects It is also important to note that we might also need to provide contracts for aspects in order to be able to enforce a runtime check of rules that will guard against an improper run-time deployment of aspects. This would be beneficial for architectures that support run-time adaptability. The reason behind this is that adaptability of aspects may imply alteration of data/execution flow of the base program, resulting in incorrect output or non-graceful termination of the system itself. Since aspects are deployed at specific execution points of the program, but also can be potentially used by other programs (if the concern being addressed is suitable to other problem domains) an issue arises as to when is an aspect “valid”, or “correct” in the context of a given base program. Having the aspect code verifying its correctness with respect to the system it is about to be deployed at, it will provide more correct code and better integration of aspects and base systems. As a result, certain issues need to be addressed: · What is the contract checking semantics between an aspect and a potential system. The issue of aspect invariant needs to be addressed. One question is how do we specify an aspect invariant that has an “around” method (ala AspectJ “around” advice) which alters the result of a base systems method return value? In other words, how would one check and verify that the behavior of an aspect does not violate (falsify) the desired functionality of base systems. Do the solutions provided by the resulting system after the deployment of a new aspect still satisfy the initial requirements? · The order of contract evaluation has to take into account the base system together with aspects that are currently active as well as new aspects that would possibly be deployed. · How would we guarantee the truthfulness of the invariants of base programs? Aspectual behavior could potentially alter the behavior of methods or components. Therefore, aspects of this nature impose some new behavior that affects the functionality of the program. This added behavior should be checked in order to guarantee that the new added code still provides results within the solution domain that the overall system specification defines as acceptable. This checking mechanism will cut across many components at different points of execution. The checking of this sort of case is thus more complex than what we would have faced with DBC in OOP. In other words, how would the system verify that aspects whose advice affect the behavior of programs still provide an acceptable semantics according to the systems specification? A runtime contract check mechanism is also needed (along with a formal proof) that would also check contracts of dynamically added aspects to a system, addressing of course the issues mentioned above as well as issues of substitutability of subtypes (object subtypes or even aspect subtypes if such a categorization is developed). Therefore a contract checking tool should be extended to take care of the validation of contract specification while at the same type maintaining the laws of subtype substitutability [9].
4.5 Relation to time: static and dynamic aspects Another classification can be made according to the aspectcomponent relation over time as well the aspect policy over time. We can identify two cases under this approach: (1) A
run-time association between components and aspects and (2) A dynamic change of aspect policy (Figure 1). Under (1), an aspect A1 may cut across components C1 and C2 at time T1, but then may cut across components C1, C2, C3 at time T2. As a result, the crosscutting was extended at run-time. Under (2) an aspect A1 may cut across components C1, and C2, at time T1 with policy P1, and then at time T2 its policy changes to P2. In this case, policy change may require aspect run-time adaptability, i.e. a replacement of one aspect reference by another. Naturally, we may have a combination of (1) and (2). In both cases the examples refer to real-time environments and as such we imply that dynamic adaptability is supported by the underlying technology. Components C3 Aspect A1 with policy P1
C2 {A1 , P1}
{A1, P1}
{A1, P2}
C1
T1 Aspect Join point
T2
T3
Time
Figure 1. Aspect-component relations over time. An aspect that is introduced at run-time and an aspect whose policy must change at run-time do not necessarily belong to the same category. In order to introduce aspects at run-time requires the provision of an open system. If an aspect has been coded so that it will provide services (behavior) that would be state sensitive (either to system state or another aspect state) is a matter of the aspect (concern) itself. The ability of a system to allow for dynamic aspect deployment provides more flexibility and better software evolution since developers do not have to halt and alter existing aspects, but simply override or extend aspects in order to provide extra functionality / behavior. The reasons for deploying an aspect at runtime are related to system evolution, and they can be in order either to provide new semantics to the system due to a change in requirements, or to alter an existing system policy to meet some new requirements. Based on whether an aspect policy may have to adapt at run-time we can address the notion of static and dynamic aspects. An aspect such as authentication can be considered static, as it is very unlikely that an authentication policy will have to change during program execution. On the other hand, a scheduling policy will most likely have to be adapted at run-time. We can therefore view scheduling as a dynamic aspect. Consider the example of an on-line conference room reservation system where we have a server providing View and Book services. The server would implement the readerswriters protocol to ensure fairness between readers (View) and writers (Book) or perhaps give a priority to writer client requests. The aspects of concern here are synchronization and scheduling. We might then decide to introduce a new service,
namely Cancel. Cancel is a 'write' operation. The introduction of Cancel will give rise to a race between Book and Cancel because our existing scheduling policy had no way of knowing that another 'writer' would have been introduced into the system. So not only scheduling and synchronization were introduced to a new component, but the scheduling policy that applies to existing components will now have to be modified to handle Book and Cancel which are both 'writers'. In this example, one static aspect (synchronization) and one dynamic aspect (scheduling) were introduced at run-time. Aspect languages modify the source code of a class by inserting aspect-specific statements at join points. The result is a highly optimized woven code whose execution speed is comparable to that of code written without AOSD. However, this makes it difficult to later identify aspect-specific statements in woven code. As a consequence, adapting aspects at run-time can be time consuming or not possible at all. On the other hand, aspect-oriented frameworks such as the proposal in [4] trade performance over the provision of dynamic adaptability.
4.6 Level of support for obliviousness It would be interesting to investigate the level to which an aspect supports obliviousness [8] during adaptation time. Will (or should) the introduction of an aspect or a change of policy of an aspect require a modification of client code? Ideally, a system should support non-invasive dynamic adaptability and client code should be oblivious from aspect adaptation. To this effect, language mechanisms can be provided to validate aspect deployment semantics for static adaptability. Further, mechanisms such as contracts can be deployed in order to observe correct system semantics for dynamic adaptability.
4.7 Non-orthogonality It is highly unlikely that aspects are completely independent of each other. Most real-life examples involve aspects that tend to be interdependent. This is termed non-orthogonality between aspects. The issue of non-orthogonality is important as it addresses the overall semantics of the system. Close to this is the issue of the order of activation of aspects. Consider a fine-grained concurrent system that supports the readerswriters protocol: the "before" behavior of a service dictates that synchronization should be evaluated before scheduling. If authentication is introduced, it has to be evaluated before synchronization. However, the "after" behavior of a service dictates that updating scheduling counters must be performed before synchronization. // "before" behavior preactivation(write): // "after" behavior postactivation(write):
The issue of non-orthogonality poses a number of interesting issues as the developer should not be able to misuse the provision of dynamic adaptability and violate the semantics of the system. If two (or more) aspects are non-orthogonal, any action that is directed at one might affect the overall group. As a result, the system must be capable of preventing any possible misuse. In the example above, one should not be able to either drop synchronization or change the order of syn-
chronization and scheduling. The order of aspect activation is supported in technologies such as AspectJ, Composition Filters and the AMF through different mechanisms
4.8 Aspects as first-class abstractions We think that the issue of what would constitute the most appropriate abstraction level at which to describe aspects still remains an open problem. Aspect languages provide constructs to express crosscutting concerns and a number of proposals support the implementation of aspects in a modular and natural way. There are proposals of specific languages for the support and implementation of AOP versus extensions to general-purpose languages. Domain-specific languages provide language constructs to address certain concerns. In ESP [6] the functional part is separated from the synchronization code, but it is still in the same class. The D framework [16] first introduced a complete separation between functional and synchronization code. However, aspects in D are not firstclass abstractions, but statements that get inlined to the functional components by the weaver. Perhaps the most notable general-purpose aspect language is AspectJ that provides an extension to the Java language where aspects can be expressed in classes as separate modular units. Although AspectJ aspects are implemented in a similar fashion to classes, aspects are not instantiated. In order to maintain separation of concerns at all levels of the life cycle an aspect should be treated and remain a distinct artifact. Furthermore, reusability of aspects and their advice should also be possible as well as a notion of grouping related aspects together in some hierarchical structure. In an OO language these features are captured through classes, relations between classes (“has-a”), and the inheritance mechanism. It is thus only natural to consider aspects as first-class abstractions (classes) materialized as objects at runtime. This approach would provide the means to parameterize / group and reuse aspectual code through hierarchical structures as in OOP. We would like to be able to refer to and manipulate aspects at runtime as concrete, modular units.
4.9 Aspects as reusable pieces of software Ideally, both components and aspects as well as architectural and design decisions should be reused. The importance of reuse lies on the fact that it can cut down costs, increase productivity and improve the quality of software. It has already been argued in the literature that the general feeling that OOP promotes reuse and expandability by its very nature is rather a misconception as none of these issues is enforced. Rather, a software system must be specifically designed for reuse and expandability [7]. A number of researchers are suggesting that the maximum potential for reuse is over the entire life cycle, where reuse is applied to each phase, and it must begin in the requirements phase. Another important issue is the one of the verification of components and aspects in isolation from each other as well as to test and verify the collaboration of components and aspects. This would constitute an important phase in the design process. In order to achieve a high degree of aspect code reusability, we must investigate the degree to which aspects and components are separate from each other (as well as whether aspects are separate from each other). AspectJ aspects are not generic, as they reference the joinpoints of the class to which new semantics are introduced. Aspects in the AMF are more generic, as they have no visibility over the functional components but rely on local data. In
DJ/DemeterJ reusability is obtained through the structure-shy traversals. That is, the Strategy graph is concerned about the nodes that are explicitly referred to in the Strategies specification (from A to B via C). As long as the class hierarchy and class relations provide some path satisfying that Strategy then one can achieve code reuse. The term reuse here has to do with whether the advice code introduced actually has some positive effect on the over all calculation of the solution one is trying to achieve. DJ/DemeterJ are "adaptive" since they provide strategies that map to a number of OO program solutions. This fact is supported by the structure-shy traversal (specified by the Strategy) that the tools perform.
4.10 Dynamically loadable aspect libraries If we can have reusable aspects as first-class abstractions with flexible paramerization and/or contractual definitions (i.e. with pre-defined interfaces), it would perhaps be possible in the future to create aspect libraries that can be locally deployed or domain specific aspect repositories that can be remotely invoked. The provision of dynamically loadable libraries of aspects can prove advantageous for technologies that support dynamic adaptability.
5. CONCLUSION In our view, aspects should be viewed along the same lines as components: stand alone entities that could be easily adapted and incorporated into different systems without the need of specifically altering the original entity (black box), but rather extending it to meet new requirements. As such, aspects will have a defined interface as well as semantics. Programmers can then reuse aspects in their programs by simply incorporating them into their system and providing the necessary hooks for them to inter-operate with their system. Component integration will thus define the semantics of the final program in terms of the semantic definition of components and their collaboration. To ensure correctness as well as a safe component substitution and component integration one should also perform some sort of checking between aspects and the integrated system. The idea of contracts has been used effectively for OOP, and we believe it can be extended to address this problem by addressing some specific issues found in aspectual systems. The nature of contracts and contract checking has itself an aspectual nature, which can be exploited to provide an extended contract system. Aspects could be used to define the contract checking mechanism that could then be used and extended to address aspectual/component systems for correctness.
REFERENCES 1.
2.
3.
Aksit, M., Wakita, K., Bosch, J., Bergmans, L., and Yonezawa, A., “Abstracting Object Interactions Using Composition Filters”, ed. Guerraoui, R., Nierstrasz, O., and Riveill, M., ObjectBased Distributed Programming, Volume 791 of Lecture Notes in Computer Science, pp. 152-184. SpringerVerlag, 1993. Constantinides, C. A., Bader, A., Elrad, T., Fayad, M., Netinant, P., “Designing an Aspect-Oriented Framework in an Object-Oriented Environment”, ACM Computing Surveys Symposium on Application Frameworks, M.E. Fayad, Editor, Vol. 32, No. 1, March 2000. Constantinides, C. A., Elrad, T., “On the Requirements for Concurrent Software Architectures to Support Advanced Separation of Concerns”, Proceedings of OOPSLA 2000 Workshop on Advanced Separation of Concerns in Object-Oriented Systems. Minneapolis, Minnesota, USA. October 16, 2000.
4.
5.
6.
7. 8.
9.
10.
11.
12.
13.
14. 15.
16.
17. 18.
19. 20.
21.
Constantinides, C. A., Skotiniotis, T., Elrad, T., “Providing Dynamic Adaptability in an Aspect-Oriented Framework”, Proceedings of ECOOP 2001 Workshop on Advanced Separation of Concerns, June 15-17, 2001, Budapest, Hungary. Constantinides, C. A., Elrad, T., Fayad, M., “Extending the object model to provide explicit support for cross-cutting concerns”, International Journal of Software Practice and Experience. (To appear) Dempsey J., and Cahill, V., “Aspects of System Support for Distributed Computing”. In Proceedings of the ECOOP 1997 Workshop on Aspect-Oriented Programming. Jyväskylä, Finland, June 10, 1997. Fayad, M., Cline, M., “Aspects of Software Adaptability”, Communications of the ACM, 1996. Filman, R. E., Friedman, D. P., “Aspect-Oriented Programming is quantification and obliviousness”, Proceedings of OOPSLA 2000 Workshop on Advanced Separation of Concerns in Object-Oriented Systems. Minneapolis, Minnesota, USA. October 16, 2000. Findler, R. B., Felleisen, M., “Contract Soundness for ObjectOriented Languages”, Proceedings of Object-Oriented Programming, Systems, Languages, and Applications (OOPSLA 2001). Findler, R. B., Matthew Flatt, M., “Modular Object-Oriented Programming with Units and Mixins”, Proceedings of the ACM SIGPLAN International Conference on Functional Programming (ICFP '98), 34(1):94-104, 1999. Kiczales G., Hilsdale E., Hugunin J., Kersten M., Palm J., Griswold Lopes, C., Loingtier, J., and Irving, J., “Aspect Oriented Programming”, ed. Aksit, M., and Matsuoka, S., W. G., An Overview of AspectJ, Proceedings of ECOOP 2001. Kiczales, G., Lamping, J., Mendhekar, A., Maeda, C., Lopes, C., Loingtier, J., and Irving, J., “Aspect Oriented Programming”, ed. Aksit, M., and Matsuoka, S., Proceedings of ECOOP '97, pp. 220-242, 1997. Klaeren H., Pulvermüller E., Rashid A. and Speck A., “Aspect Composition applying the Design by Contract Principle”, Proceedings of 2nd International Symposium of Generative and Component-based Software Engineering (GCSE 2000), Springer, LNCS 2177, pp. 57-69. Kramer R., “iContract – The Java Design by Contract Tool”, Proceedings of Tools USA, 1998. Lämmel, R., “Semantics of Method Call Interception”, Proceedings of the Workshop Aspect-Orientierung of GIFachgruppe 2.1.9 Objectorientierte Software-Entwicklung, 2-3 Mai 2001, Universität Paderborn. Lopes, C. V., “D: A Language Framework for Distributed Programming”, Ph.D. Thesis, Graduate School of the College of Computer Science, Northeastern University, Boston, Massachusetts, 1997. Matthijs, F., Joosen, W., Vanhaute, B., Robben, B., and Verbaeten, P., “Aspects Should Not Die”, Proceedings of the ECOOP ’97 Workshop on Aspect-Oriented Programming. Matsuoka S., and Yonezawa, A., “Analysis of Inheritance Anomaly in Object-Oriented Concurrent Programming Languages”, ed. Agha, G., Wegner, P., and Yonezawa, A., Research Directions in Concurrent Object-Oriented Programming, pp. 107-150, The MIT Press, 1993. Meyer, B., “Applying Design by Contract”, IEEE Computer, pp. 40-52, October 1992. Orleans, D., Lieberherr, K., “DJ: Dynamic Adaptive Programming in Java”, Proceedings of Reflection 2001: Meta-level Architectures and Separation of Crosscutting Concerns, Kyoto, Japan, 2001. Pryor, J., and Bastán, N., “A Java Meta-Level Architecture for the Dynamic Handling of Aspects”, Proceedings of PDPTA 2000.
A Proposal For Classifying Tangled Code Stefan Hanenberg and Rainer Unland Institute for Computer Science University of Essen, 45117 Essen, Germany {shanenbe, unlandR}@cs.uni-essen.de
Abstract. A lot of different composition mechanisms claim to permit aspect-oriented software development because they are able to handle the problem of tangled code which was the original target of aspect-oriented programming (AOP). However, it becomes hard to compare those different approaches, because they usually focus on different kinds of tangled code. For comparing different approaches it is necessary to find some communalities between tangled code. Such communalities can be used to classify tangled code and in that way the impact of new aspect-oriented approaches can be determined in respect to what classes of tangled code they are able to handle. A general purpose aspectoriented approach should be able to handle all kinds of tangled code. Currently, there is no common agreement about how to classify tangled code. This paper outlines the need for such a classification and proposes a (preliminary) non-formal classification of tangled code.
1 Introduction In the fundamental paper on aspect-oriented programming (AOP) Kiczales et al argue that "tangled code is extremely difficult to maintain, since small changes to the functionality require mentally untangling and then retangling it" [11] and propose aspect-oriented programming to solve the problem of tangled code. The problem of tangled code means that within software systems code exists, which is one the one hand redundant but on the other hand cannot be encapsulated by separate modules using regular techniques. There are a lot of different approaches available which claim to permit aspect-oriented software development (AOSD) and therefore claim to be appropriate solutions for the problem of tangled code. Most of them mentioned in this context are AspectJ [2] implemented by those people who actuated the term aspect-oriented programming [11], HyperJ [14], which is an offspring of subject-oriented programming (SOP, [10]), DemeterJ [6] whose foundation came from adaptive programming [12] and composition filters [1]. More recent proposals include for example logical meta programming [16] or different mixin-mechanisms like destructive mixins [15] or per-object-mixins [13]. Although there are already some comparisons between different approaches like AspectJ and HyperJ (cf. e.g. [4]) there is currently no common accepted foundation available describing how to compare aspect-oriented mechanisms. This makes it hard to determine if a new proposal really supplies a new solution for untangling code which is not already available in any other approach. Furthermore, it makes it impossible for real software projects to determine what technique to use in a given situation. Moreover, it must not be forgotten that objectoriented programming already provides some techniques for sharing code and hence permits to untangle code in some way. So it is also necessary to determine if a needed mechanism is already available in OOP. It is necessary to describe what kind of situation, i.e. what kind of tangled code exists, hence communalities between tangled code have to be analyzed. Those communalities can be utilized to classify different kinds of tangled code. Then it is possible to determine what techniques are able to handle what kind of tangled code. Because aspect-oriented programming claims to supply appropriate solutions for the problem of tangled code, a general purpose aspect-oriented approach should be able to supply appropriate solutions for all kinds of tangled code. This paper proposes a (preliminary) non-formal classification of tangled code. We do not regard this classification to be complete. Instead it is the result of our observations we did during applying aspect-oriented programming, especially when applying AspectJ. Although the approach of aspect-oriented programming claims to be not limited to object-oriented programming, all of the above mentioned techniques are based on objectoriented concepts. Hence, the here proposed classification will also be based on the object-oriented paradigm. In the next section we will motivate the need for a classification of crosscutting code. Afterwards we introduce a classification of crosscutting code and crosscuts. Afterwards we conclude the paper.
2 Motivation Figure 1 and 2 contain some code examples, which obviously contain some tangled code. In figure 1 the tangled code results from an implementation of the observer pattern [8]. Both classes Point and GuiElement contain redundant methods for attaching and detaching observers. Moreover, the definition of the instance variable observers occurs in both classes. The intension of those definitions is the same and therefore it can be argued, that both classes contain tangled code. public class Point {
public class GuiElement …… {
int x,y; ArrayList observers = new ArrayList();
Color color; ArrayList observers = new ArrayList();
public void setX(int x) { this.x = x; this.informObservers(); }
public void setColor(Color color) { this.color = color; this.informObservers(); }
public void setY(int y) { this.y = y; this.informObservers(); }
. . . . . . . . . .
public void setXY(int x, int y) { this.x = x; this.y = y; this.informObservers(); }
}
public void attachObservers(Observer observer) { observers.add(observer);
public void attachObservers(Observer observer) { observers.add(observer);
}
}
public void detachObservers(Observer observer) { observers.remove(observer);
public void detachObservers(Observer observer) { observers.remove(observer);
}
}
public void informObservers() { for (Iterator it=observers.iterator(); it.hasNext();) ((Observer) it.next()).update(); }
public void informObservers() { for (Iterator it=observers.iterator(); it.hasNext();) ((Observer) it.next()).update(); } }
Figure 1: Tangled Observer Implementation There is already an object-oriented solution for this problem, because if both classes can have the same superclass containing the observer related implementation. So refactoring both classes using extract superclass [7] seems to lead to the desired result. Nevertheless, there might be reasons why it is undesired to use inheritance in that situation. On the one hand in object-oriented programming practices inheritance is often more than just a mechanism for code reuse and expresses a subtype relationship. Such a relationship might be undesired, because it expresses a common root of both classes. On the other hand extracting a superclass in programming languages which support only single inheritance is not that easy. So it seems to be worth thinking about (aspect-oriented) alternatives in such a situation. The statement this.informObservers() occurs three times in different methods in class Point and one time in class GuiElement and therefore seems to be a potential example of tangled code. The intension of those statements stems also from the observer and defines that every time the state of an object changes all observers must be informed. The state of Point instance is describes by the coordinates x and y, the state of GuiElement objects is described by color. For such tangled code there is no object-oriented solution. Is must also be mentioned that this code depends on method informObservers and also in this. This dependency means that the code can only occur in (object-) methods whose class definition also contain method informObservers (assuming a class-based language). The assignments this.x = x and this.y = y exist in method setXY in addition to setX and setY in Point. In some way this kind of tangling seems to be more complex than the ones before. The observers should be informed exactly once whenever a method is called which changes a point's state. For this reason setXY cannot invoke setX or setY, because this would inform the observers twice. In this situation is does not seem to be clear what code is tangled: just by comparing lines of code the answer is that the assignments are tangled. On the other hand they appear more than once because of the property to be observable. It seems to be obviously that this is a different kind of tangling than the this.informObserver statement.1 Another often discussed example of tangled code is a singleton implementation [8] which can be found in figure 2. It is not that easy to identify the tangled code. One the one hand the body of both getInstance methods is (almost) the same. So it could be argued that the method bodies contain the tangled code. On the 1
In fact this kind of code tangling was already exhaustively discussed in the context of AspectJ (cf. [3], [5] and [9]).
other hand the declarations of getInstance only differ in their return types. So it seems to be more appropriate to determine the whole method to be an example of tangled code. Programming languages like Java which allow neither to declare covariant methods nor generic types do not supply any appropriate solution to untangle this code. The definition of instance also seems to be redundant but differs in both classes concerning the type. Moreover, the singleton design pattern is usually implemented using private constructors. So "declaring the constructor private" also seems to be kind of tangled code. public class SingletonA {
public class SingletonB {
static SingletonA instance=null; ..
static SingletonB instance=null; ..
private SingletonA() { .. .. }
private SingletonB() { .. .. }
public static SingletonA getInstance(){ if (instance==null) instance = new SingletonA(); return instance; } .. .. ..
public static SingletonB getInstance(){ if (instance==null) instance = new SingletonB(); return instance; } .. .. ..
}
}
Figure 2: Tangled Singleton Implementation The examples showed that there are a lot of different kinds of tangling. One the one hand there is tangled code which is easy to identify and which might exist on statement level (like this.informObservers). On the other hand there is code which is not that easy to identify, because the object-oriented realization already hides the details responsible for the tangling (like the implementation of method setXY in class Point). Furthermore, there is code somehow depends on the locations it crosscuts (like the type of instance in SingletonA). One of the main cognitions of those examples is, that there is a difference between the tangled code itself and the way how this code crosscuts existing structures. Therefore we distinguish between crosscutting code and the way of crosscutting.
3 Crosscutting code This section classifies the crosscutting code. The classification is based upon the following observations. First, there is code which can be added to almost arbitrary classes or methods because the code does not expect any parameters from the location it is woven to. A typical example is a collection of methods, which do not are strongly coherent to each other, but on the other hand to not expect anything from their object except those methods. Such methods can be added to almost any class (restrictions are given e.g. if the underlying language does not support covariant methods). Second, the crosscutting code not only depends on its environment in the sense, that it expects any parameters, but the code itself has to be adapted when woven to the new environment. For example C++ templates expect class parameters, so the code itself will be transformed to match the needs at hand. Nevertheless, the transformations which are necessary to transform the crosscutting code might be more complex than "just" transform type information. Third, the crosscutting code can transform the environment it is woven to. The most typical example is a delayed exception declaration in java sources, i.e. the exception is part of the crosscutting code. Unit Dependency This characteristic describes, if the code depends on the unit which is affected by the crosscutting or where the crosscutting is located in. We distinguish between unit dependent and unit independent crosscutting code. Unit dependent crosscutting code needs some input from the units it crosscuts. For example the statements this.informObservers() which can be found in both classes of figure 1 are examples for object dependent crosscutting code, because they depend on the variable this and assume the object referred by this to contain a method informObservers(). On the other hand they are method independent, because they do not depend on any method related information. Method related information might be any parameters from the method or any variables local to the method. Although the crosscutting code is object dependent it does not mean, that every occurrence of the code is related to the same object. Obviously, this in GuiElement relates to a different object than this in Point.
Constant vs. Variable Crosscutting Code There is a difference between constant and variable crosscutting code, i.e. the difference is if there are any variabilities within the code or not. Examples of constant crosscutting code can be found in figure 1. The statements this.informObserver() are exactly the same (although this might be related to different objects) , so the crosscutting code is constant. Also the methods for attaching and detaching observers are examples for constant crosscutting code. In contrast to that, the singleton implementation contains variabilities: the return type of method getInstance is a changeable. Likewise the method body of getInstance is variable, because in SingletonA it create a new instance of SingletonA and in SingletonB a new instance of SingletonB. Variable crosscutting code needs a more complex composition technique, because the code changes when applied to a specific context. Transforming Crosscutting Code This characteristic describes, if the crosscutting code changes the declaration of the element it is applied to. For example, the methods for attaching and detaching observers are class transforming crosscutting code because they change the interface of the class those methods are applied to. On the other hand, this.informObservers() is an example for non-class transforming crosscutting code, because is neither transforms the declaration of the methods it is located in nor does it change the interface of any class. Transforming crosscutting code can either increase or decrease the possible usage of the element the code is applied to. For example code which declares several classes to extend a certain class increases the possible usage of those classes. All existing clients of those classes are still able to use them. On the other hand code which declares a "delayed" exception of a method decreases the possible usage, because clients are enforces to catch those exceptions.
4 Crosscutting The crosscutting describes at what positions code crosscuts existing structures. It is a certain strategy applied to existing code to add crosscutting code. While the section above classified "what" crosscuts given code, this section describes "how" it crosscuts. Classifying crosscutting is based upon the following observations. First, the crosscutting might be described constantly or variable. Constant crosscutting means, that the strategy how the crosscutting code is added to existing code is fix and cannot be used in any other context. Second, crosscutting code is added to certain locations. The question arises if the crosscutting really crosscuts such location or if it just affects the location. The difference between both is, that a crosscut location is a common root for several affected locations. It is something like a selector for identifying several affected locations. Third, the relationship between the crosscutting code and the affected location might be static or dynamic. Static means, that this relationship only depends on the location's lifetime. Constant vs. Variable Crosscutting Constant crosscutting means that the way certain code crosscuts a given structure is described completely without any variabilities. In other words, the strategy applying the crosscutting code to the existing one is entirely defined without any hooks which allow the crosscutting to be used in any other context. In contrast to that a variable crosscutting contains variabilities which allow to add the crosscutting code to a new context. Referring to the introducing examples the singleton implementation crosscuts existing structures variable. The implementation can be attached to any class. Therefore the class to which the implementations are applied to are the variable part of the crosscutting. Variable crosscutting is an indication for reusability of the crosscutting code, because it allows to apply the crosscutting code to new contexts without changing crosscutting itself. A constant crosscutting is usually applied if the corresponding code is highly coherent to a certain location and highly specialized for a (usually location dependent) purpose and thus cannot be reused for any other purposes. Examples for constant crosscutting can be found e.g. in the simple telecom simulation which is part of the AspectJ documentation (cf. [2]). Such applied crosscutting code is highly connected to a application specific needs and therefore the crosscutting cannot be used in any other context. Crosscutting Location The crosscutting location describes what entities are crosscut by the crosscutting code. It is necessary to distinguish between crosscutting location and crosscutting affected units. The first one describes the location to which the crosscutting is applied to, the latter one describes those units which are affected by the crosscutting. A crosscutting location is a common root for several affected locations. It is something like a selector for identifying several affected locations. We distinguish between class, method and object located (and affecting) crosscutting. Class located crosscutting describes that kind of crosscutting which is restricted to a certain class. The observer implementation from figure 1 is an example of a class located crosscutting: the statements
this.informObserver() are spread over methods of a certain class which represent the subject. On the other hand the crosscutting responsible for introducing the methods for attaching and detaching observers is not class located: although the methods are part of a certain class they do not crosscut the class (they occur exactly once in each classes). Hence, the crosscut which is responsible for attaching those methods to the class is class affecting, but not class located. Object located crosscutting classifies that kind of crosscutting, that is restricted to certain objects. All statements this.informObservers()are object located, because they crosscut certain objects (which have the same type). The reason why the crosscutting is both class located and object related is that the underlying programming language of the examples is a class-based object-oriented programming language. For such a kind of programming languages every object located crosscutting is also a class located crosscutting (but not the other way around because of static methods and attributes). In prototypical languages which also allow the notion of classes it is possible that an object located crosscutting is not class located at the same time. Method located crosscutting describes that kind of crosscutting that is restricted to certain methods. None of the examples above contains a method located crosscutting. A typical example of method located crosscutting is such code which is inserted into a certain method for debugging purposes like System.out.println(..) after every line of code. Although the statements this.informObservers()from the observer implementations are located in certain methods they are not method located, because the choice if a certain method should contain the code or not is not determined by the method, but by the enclosing object. So the crosscutting for the mentioned statements is method affecting. The above enumerated kinds of crosscutting are related to object-oriented constructs. In that way the classification is already prescribed by the application code, e.g. all statements which are part of a certain method are classified by this method. In that way a classification "method located crosscutting" is according to the enclosing object-oriented construct. On the other hand a crosscutting might group constructs, which are not grouped by the application code. For example the methods for attaching and detaching observers crosscut a collection of classes which are not related in the application code. So the location of that crosscutting is a collection of the classes which is defined by the crosscut itself. The same situation is given for the this.informObservers() statement. The statement does not crosscut a single method, but a collection of methods which are defined by the (object located) crosscut itself. Such kind of crosscutting we call selective, e.g. the methods for attaching and detaching observers are called selective class located crosscutting. Static vs. Dynamic Crosscutting If the connection between crosscutting code and affected or located units depends only the unit's lifetime we call such crosscut static. In any other case the crosscut is dynamic. An example for a static crosscut are the methods for attaching and detaching observers or getInstance from the singleton implementations. They exists as long as the affected class definitions exist. Likewise, it seems as if the statements this.informObservers() do statically crosscut the given structures, because they are always located in the methods which change an object's state. Nevertheless, this statement is an example for dynamic crosscuts. The assignments of x and y in method setXY are tangled, because it was not possible to invoke setX or setY without informing the observers twice. Therefore the object-oriented solution was to implement the assignment operations redundantly. The desired behavior of the observer implementation is to inform the observers exactly once, so informObservers() should be invoked after setX, setY or setXY but never more than once. This is what in [3] is called a jumping aspect. The connection between the crosscutting code and the crosscut location depends on the context the method was invoked. So the underlying crosscutting is dynamic. AspectJ distinguished between static and dynamic crosscutting in a different way (cf. [2]). Static crosscutting describes mainly those kinds of crosscutting, which transform the interface of a class (also known as introduction), respectively "crosscutting concerns that do operate over the static structure of type hierarchies" [2]. Although this terminology seems to be somehow intuitive, it contains some inconsistencies: those crosscutting concerns, that in AspectJ terminology are called dynamic can operate over the static structure. E.g. code, which is executed right before a certain method is invoked is called "dynamic crosscutting". Nevertheless, there is nothing dynamic in it: the weaver uses static type information for connecting the crosscutting code and nothing during runtime unweaves that code. Nevertheless, we agree with the AspectJ terminology that construct like cflow- or if-pointcuts allow to express dynamic crosscutting. Although it does not seem to be obvious, there is a difference between dynamic crosscutting and variable crosscutting. E.g. in AspectJ it is possible to define constant, dynamic crosscuts. Also it is possible to define variable, static crosscuts.
5 Conclusion and Further Work This paper discusses the ability to characterize tangled code and proposed a preliminary classification of tangled code motivated by some introducing examples. It distinguishes between the crosscutting which describes where
and how the crosscutting code affects existing structures and the code itself. Mainly the proposal distinguishes code because of its location dependency, variability and transformational property. The crosscutting is distinguished by its variability, location and its dynamics. We regard the proposed classification to be neither complete nor mature. Instead we think that this proposal is the beginning of some work which is concentrating on different kinds of tangled code which are observable in practice and which unites those appearances using a common classification schema. The proposed preliminary classification of crosscutting and crosscutting code needs much refinement. For example it does not distinguish between different kinds of unit dependencies in crosscutting code. Furthermore, it is necessary to determine what kind of variabilities are possible within the crosscutting. Such an awareness is necessary for building general purpose aspect languages which can provide adequate hooks for building reusable aspects. The categories highly depend on the underlying object-oriented programming language. In static typed, classbased languages every object belongs to exactly one class for the whole lifetime. This means, that object located crosscutting code must be contained in a class definition. So in this case object related crosscutting code is always class located. In (class-based) single dispatching languages a method belongs to exactly one class. This means that every method located crosscutting is also class located. So in the future the impact of the underlying language on the classification must be determined. In future works it is necessary to apply the here proposed classification to different kind of tangled code which occur in practice. Although the classification has been reasoned by the introducing example it must be observed in what situations the classification fails or is too rough to describe the observable occurrences adequately. It should be emphasized that the typical code examples which lead to the proposed classification came from the context of AspectJ. Afterwards the classification has to be applied to different aspect-oriented techniques.
References 1.
Aksit, M., Wakita, K., Bosch, J., Bergmans, L., Yonezawa, A. Abstracting Object-Interactions Using Composition-Filters. In: objectbased distributed processing, R. Guerraoui, O. Nierstrasz and M. Riveill (Eds.), LNCS, Springer-Verlag, (1993), pp. 152-184
2.
AspectJ-Team, The AspectJ Programming Guide, http://aspectj.org/doc/dist/progguide/
3.
Johan Brichau, Wolfgang De Meuter, Kris De Volder. Jumping Aspects, Position paper at the workshop Aspects and Dimensions of Concerns, ECOOP 2000, Sophia Antipolis and Cannes, France, June 2000
4.
Chavez, C.F.G.; Garcia, A.; Lucena, C. "Some Insights on the Use of AspectJ and Hyper/J". Tutorial and Workshop on AspectOriented Programming and Separation of Concerns, Lancaster, UK, August 23-24, 2001
5.
Pascal Costanza. Vanishing Aspects, Workshop on advanced separation of concerns at OOPSLA 2000, Minneapolis, Minnesota, USA, 2000
6.
Demeter/Java Web page, http://www.ccs.neu.edu/research/demeter/releases/
7.
Martin Fowler, Refactoring: Improving the Design of Existing Code, Addison Wesley, 1999
8.
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995
9.
Stefan Hanenberg, Rainer Unland, Using and Reusing Aspects in AspectJ, OOPSLA 2001 Workshop on Advanced Separation of Concerns in Object-Oriented Systems, 2001
10. William Harrison, Harold Ossher, Subject-Oriented Programming (A Critique of Pure Objects), in: Pro-ceedings of the OOPSLA 1993, pp. 411-428 11. Kiczales, G., Lamping, J., Mendhekar, A., Maeda, C., Lopes, C., Loingtier, J., Irwing, J.. Aspect-Oriented Programming. Proceedings of ECOOP '97, LNCS 1241, Springer-Verlag, 1997, 220-242 12. Karl J. Lieberherr, Adaptive Object-Oriented Software: The Demeter Method with Propagation Patterns, PWS Publishing Company, Boston, 1996 13. Gustaf Neumann and Uwe Zdun: Implementing Object-Specific Design Patterns Using Per-Object Mixins, Proceedings of the Second Nordic Workshop on Software Architecture (NOSA'99), Ronneby, Sweden, Aug. 12-13 1999 14. Peri Tarr, Harold Ossher, Hyper/J™ User and Installation Manual, 2001 15. Kris de Volder, Inheritance with Destructive Mixins for Better Separation of Concerns, Workshop on Advanced Separation of Concerns at OOPSLA 2000 16. Kris De Volder, Theo D'Hondt, Aspect-Oriented Logic Meta Programming, Proceedings of Meta-Level Architectures and Reflection, Second International Conference, Reflection'99. LNCS 1616, pp. 250-272, Springer-Verlag, 1999
Analysing the navigational aspect A. M. Reina Dpto. Lenguajes y Sistemas Informáticos Universidad de Sevilla. e-mail:
[email protected]
J. Torres Dpto. Lenguajes y Sistemas Informáticos Universidad de Sevilla e-mail:
[email protected]
Abstract The Internet and web applications have increased their popularity in the last few years. This boom has provoked the use of new approaches for web-based applications. These new methodologies try to address some new concerns which have appeared in this field and weren’t in traditional methodologies. One of these concerns is navigation. At the same time, it has been proved that there are some concerns that aren’t well treated with the traditional abstraction mechanisms ((functions, objects). They scatter by all the code of the program. This paper tries to join both approaches, crossing the gap between the design level proposed in the methodologies and the implementation level, using for it the proposed ideas in the area of the advanced separation of concerns.
Key words Hypermedia, navigation, advanced separation of concerns, aspect-oriented programming.
1. Introduction Separation of concerns is one of the basic disciplines in software engineering. With the proliferation of Internet and multimedia, new design methodologies that apply this principle have arisen. They address new concerns that weren’t treated in traditional applications. One of the terms that appear in this new environment is navigation. Navigation includes the intrinsic notion of movement through an information space [3]. The current position or context is a crucial factor, because many times the next navigation will depend on the previous navigation. If we analyse the tendencies of the last web design methodologies (OOHDM [14], RMM [9], HDM [7], etc), we will deduce that navigation is an important concept and it should be treated separately from the basic functionality of the application. On the other hand, the term aspect has arisen from the field of advanced separation of concerns, as an abstraction to separate concerns that are scattered all over the program code. This paper tries to analyse how these two approaches could be combined, proposing the treatment of navigation like an aspect, in the sense of aspect-oriented programming. We introduce an example to analyse the problems we have when designing navigation, and how the separated definition of navigation could help to solve them. In section 2 we define the navigation concept, as it is understood in the scope of this paper. Section 3 is a review of the state of the art in the field of separation of concerns. Afterwards we introduce the approaches of the last design methodologies to express navigation. Then we introduce and discuss an example to show the problems of navigation, and how the separation of navigation could help to solve it. Finally, we summarise and conclude the paper.
2. Navigation Navigation is a concept widely used in web environments. In its primitive meaning it was bound to the hypertext idea, defining the action of jumping from page to page through a hyperlink. The advance of the technology has made us have a wider vision of the navigation concept, being not only the action of jumping from page to page, but the idea of moving through an information space.
This enlargement of the semantics of the navigation concept invite us not to treat as navigation the fact to push the link More when we browse the results of a query processed by a search machine as google or altavista, since we wouldn’t move from an information space to another one. This problem would be considered as an interface one (we have an information space and we can’t display all the information to the user simultaneously). Although we have a link in the hypertext, this link should be considered just as a way to do scrolling. The context is a very important concept in navigation. Let us suppose we have a web-based application for a museum, and want some information on a concrete painting. If we got the information navigating through the author, and then we push the link Next, we will move to the next painting by the same author. However, if we got the painting through a pictorial movement, the result of navigation will be different. In this case, we should move to another painting related to the same movement. In [15] navigation is defined as the sensation the user has when he navigates through an object space from the application domain. These objects aren’t the conceptual objects, but they are customised according to the user’s profile using the view mechanism.
3. Separation of concerns One of the approaches that has emerged strongly in the last few years is separation of concerns, a concept which has been applied in the field of software engineering practically from its beginnings. However, the current technology has been focused mainly on the programming level. Aspect-oriented programming (AOP) [5] idea is that it is possible to make programs better if you specify separately the different concerns, properties or areas of interest of a system, and the description of their relationships, leaving the weaving or composition tasks to the AOP mechanisms (Figure 1).
Figure 1. Aspect-oriented programming mechanisms Although generally speaking we know it as aspect-oriented programming, there have arisen a few different approaches in different researching groups. The most important are: adaptive methods [13], which can be implemented using the DJ library (http://www.ccs.neu.edu/research/demeter/DJ), multidimensional separation of concerns [16], whose result has been Hyper/J (http://www.research.ibm.com/hyperspace/HyperJ/HyperJ.htm), composition filters [1], and aspectoriented programming [10], whose main tool is AspectJ (http://www.aspectj.org). AspectJ is an aspect-oriented, general-purpose extension to Java. It tries to abstract the concerns that scattered all over the program code. These concepts are known as aspects, and to mix them with the code implementing the basic functionality are used pointcuts. The pointcuts are points where the code that implements the basic functionality can be augmented, either before, or after the join point. This code is wrapped into an aspect.
Adaptive methods encapsulate the behaviour of an operation in a concrete place, avoiding the scattering problem, abstracting over the structure of classes, and avoiding the tangling problem as well. To achieve its objectives, the adaptive methods express the behaviour like a high level description of how to reach to the participants of the calculation (called traversal strategy) and what to do when each participant has got it (known as adaptive visitor). As a result, this group of research has developed the DJ (Demeter/Java) library, which is a Java package that gives us some tools to interpret the traversal strategy and the adaptive visitor. The multidimensional separation of concerns allows us to encapsulate any arbitrary class of concepts simultaneously, and to integrate these concepts. This separation is based on the idea of hyperspaces. A tool called Hyper/J has been made, which doesn’t extend Java, as Aspect does. Hyper/J works with .class files, not with source files.
4. Navigation in methodologies One of the pioneering methodologies in introducing navigation as a different aspect to treat during the design stage of the development of a web application has been HDM [7]. This methodology presented some primitives. Some of them have served as the base to many that came later. OOHDM (Object-Oriented Hypermedia Design Model) may be one of the most consolidated web design methodologies. It considers navigation as a critical step in the design of a hypermedia application [15]. During the design phase a model is constructed. This model is a view of the classes from the conceptual model, so you can construct different navigation models for the same conceptual model. A few primitives are used to define navigation: nodes (they are views of the conceptual classes) links (they are views of the relationships from de conceptual schema) and access structures (they are alternative ways to navigate, as indexes, guided tours and indexed guided tours). Apart from these primitives, which already appeared in the first methodologies that treated navigation, OOHDM defines the navigational context, a new primitive to structure the navigational space. The navigational context is a set of nodes, links, context classes and other navigational contexts that are used to organise the navigation space in consistent sets that can be traversed following a particular order.
5. Navigation and aspects Since navigation is an aspect that already has been treated separately by the new design methodologies for the development of web and multimedia applications, we think the next step is to cross the gap between design and the implementation and to take this separation to the latest stages in the development of a software project. In order to obtain this separation at the programming level, it has arisen the aspect-oriented programming and the multidimensional separation of concerns. It is interesting to do a study to cross the gap between design and implementation using this technology. We introduce the next example to study what advantages we will obtain if we succeed separating clearly the navigation aspect. Let us suppose we have made a web application for a museum, and when we designed the navigation for the paintings by author context, we had decided to use the access structure index. (Figure 2(a)).
Figure 2. Access structures Later, when the application was finished, the customer decided that the access structure we had chosen wasn’t the best one, and we had to change it for an Indexed Guided Tour (Figure 2 (b)).
Guitarra by Pablo Ruiz Picasso
Guitar
Index
©2001 A.M. Reina Quintero
Figure 3. HTML page (code and picture) implementing the Guitar node using an Index access structure
Guitarra by Pablo Ruiz Picasso
Guitar
Index Previous Next
©2001 A. M. Reina Quintero
Figure 4. HTML page (code and picture) implementing the Guitar node using a Guided Tour Indexed access structure. Changing something so conceptually simple as the type of access structure, can be an arduous and tedious work when you modify the application. In Figure 3 we show the implementation of the original Guitar node (with the access structure Index), and in Figure 4 we depict the same node but with the Indexed Guided Tour access structure. We have emphasised the HTML code we have to introduce to implement the new access structure using bold fonts. Although they seem only two lines of HTML code, it should have been noticed that this web page is very simple (we decided to design it so simply to appreciate clearly the problem) and, also, you should notice this isn’t the only page we have to modify. We have to change the other nodes of the context (Guernica and Avignon, in this case). Figure 5 describes the navigational classes using the notation proposed by Hennicker and Koch in [8], while Figure 6 poses the navigation structure model resulting of the two different access structures chosen. The index access structure is depicted in Figure 6 (a) and the guided tour indexed access structure is showed in Figure 6(b).
Figure 5. Navigation space model.
Figure 6. Navigation structure model. In this paper we propose something like we describe in Figure 7, to separate completely the navigational elements. If we define these elements as an aspect, we can use the aspect-oriented mechanisms to specify the new access structure somehow, and weave it with the basic functionality.
Figure 7. Separation of navigational aspect. If we look at how most of the aspect-oriented tools work, we will deduce the following things: 1.
Somehow we should describe the main functionality of the application. We should implement the conceptual model.
2.
On the other hand, we should define navigation separately. Are the current aspect-oriented tools powerful enough to implement it? And, if they are, which of the approaches adjusts better to the definition of this aspect?
3.
We should look for one or many join points, which mean, where are we going to join the navigation aspect with the classes of the conceptual model?
4.
We should have a composition mechanism to make functionality and navigation become one program. How can we mix both concepts?
With the appearance of the Extensible Mark-up Language (XML) [2] we have obtained the separation between presentation and content. Nowadays there are some new technologies coming from the XML world (as XLink [4]) that can help us to obtain this separation of concerns.
6. Conclusions and further work If we pay attention to the current approaches in web design methodologies, we can realise that navigation is a key concept in this type of applications. The most recent methodologies treat it separately, dedicating a whole stage to the navigation design and creating different models, one for conceptual classes and another for navigation classes. This separation should be taken from design to implementation. We could use separation of concern technologies to accomplish it. We propose to make a study to check if the aspect-oriented approaches fit well with the separation of this concern. If they do, which of these approaches fits better? and is there any important lack?. We consider it is interesting to see how useful are the new mark-up languages (XML, XLink) to separate this concern.
7. References 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
Bergmans, L., Aksits, M. Composing Crosscutting Concerns Using Composition Filters. Communications of the ACM. Vol. 44, n. 10, October, 2001. Bray, T., Paoli, J., Sperberg-McQueen, C.M., Maler, E. Extensible Markup Language (XML) 1.0 (Second Edition). W3C Recommendation. [Online: http://www.w3.org/TR/REC-xml]. October, 2000. Cunliffe, D., Taylor, C., Tudhope, D. Query-based Navigation in Semantically Indexed Hypermedia. Proceedings of the Hypertext’97 Conference. 1997 DeRose, S., Maler, E., Orchad, D. XML Linking Languaje (XLink) 1.0. W3C Recommendation. [Online: http://www.w3.org/TR/xlink/] . June, 2001. Elrad, T., Filman, R. E., Bader, A.. Aspect-Oriented Programming. Communications of the ACM. Vol. 44, n. 10, October, 2001. Gamma, E., Helm, R., Johnson, Vlissides, J. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. 1995. Garzotto F., Schwabe D., Paolini P. HDM – A Model Based Approach to Hypermedia Application Design. ACM Transactions on Information Systems, Jan, 1993. Hennicker, R., Koch, N. Systematic Design of Web Applications with UML. In Unified Modeling Language: Systems Analysis, Design and Development Issues. (2001). K. Siau and T.Halpin (Eds.) Idea Group Publishing, 1-20. Isakowitz, T., Stohr, E. A,, Balasubramanian, P.. RMM: A Methodology for Structured Hypermedia Design. Communications of the ACM. Vol. 38, n. 8, August, 1995. Kiczales, G., Hilsdale, E., Hugunin, J., Kersten, M., Palm, J., Griswold, W.G. An Overview of AspectJ. In Proceedings of the European Conference on Object-Oriented Programming, Springer Verlag, 2001. Kiczales, G., Lamping, J., Mendhekar, A., Maeda, C., Lopes, C. V., Loingtier, J.M. and Irwin, J. Finland. Aspect-Oriented Programming, in proceedings of the European Conference on ObjectOriented Programming. Springer-Verlag LNCS 1241, June 1997. Kishi, T., Noda, N. Analyzing Concerns used in Analysis/Design Techniques. Proceedings of the Conference on Object Oriented Programming: System, Languages and Applications (OOSPLA), 2001. Lieberherr, J., Orleans, D., Ovlinger, J. Aspect-Oriented Programming with Adaptive Methods. Communications of the ACM. Vol. 44, n. 10, October, 2001. Schwabe, D., Rossi, G., Barbosa, S. Systematic Hypermedia Design with OOHDM. ACM International Conference on Hypertext’ 96, Washington, USA, 1996. Schwabe, D., Rossi, G. An Object Oriented Approach to Web-Based Applications Design. TAPOS – Theory and Practice of Object Systems, vol. 4, 1998. Tarr, P., Ossher, H., Harrison, W., Sutton, S.M. N degrees of separation: Multi-dimensional separation of concerns. Proceedings of the 21st International Conference on Software Engineering May 1999.
Concerns of Variability in “bottom-up” Product-Lines Andreas Speck, Matthias Clauss, and Bogdan Franczyk Intershop Research Jena D-07740 Jena, Germany [a.speck | m.clauss | b.franczyk]@intershop.com
Abstract. Conventional product-line approaches tend to implement product-lines from scratch rather than support the complete reuse of existing systems. In contrast to these “top-down” approaches the “bottom-up” procedure proposed in this paper allows reuse. The modification and extension with variable elements is realised by aspects woven into existing systems. A set of different concerns provide the different potential specialisations of the variability. Moreover aspects may be used to implement the dependencies between different flexible elements.
1
Introduction
The intention of software reuse is rather old. Already at the NATO science conference on software engineering D. McIlroy stated [12]: “Software engineers should take a look at the hardware industry and establish a software component subindustry. The produced software components should be tailored to specific needs but be reusable in many software systems.” One way to reuse code which comes McIlroy’s vision very close is product-line software engineering. A common procedure is to start with intensive domain engineering in order to capture the requirements, features and variability of a product-line to be developed. The precondition of this conventional approach is that the system to be build has to be build from scratch. If a system is already existing as base for the product-line this systems has to be re-engineered which usually bears a similar effort as developing a new system.
2 2.1
“Bottom-up” Product-line “Bottom-up” Product-line Development Process
In this paper we would like to introduce a concept in order to design the variablity without a complete re-engineering of an existing system. Such an approach allows to consider large systems like e-marketplaces as a potential target for product-line engineering. We would like to call this concept the “bottom-up” approach of productline engineering. In principle the compliance with the existing “top-down” approaches is that in both cases extensive domain engineering is the base for the development or derivation of the product-line system. Domain engineering allows to define the hot spots of the
product-line in contrast to the frozen spots 1 which have to be reused as is. On base of the definition of the required variable elements we start to derive a product-line. The “bottom-up” approach uses existing systems as base of a product-line in contrast to “top-down” product-line development. The product-line is realised by adding the hot spots modelled and designed by the domain engineering to the base system. Like in common approaches the product-line may then be transformed into many different systems by specialisation and customisation of the hot spots. In our approach the hot spots are considered as cross-cutting concerns. 2.2
UML Notation for Feature Modelling
The most common approach to model features and the variability of productlines is applying the FODA model. Despite the wide spread knowledge of the FODA notation among researchers it is not very well-known in the world of software development. System Developers are mostly not familiar with FODA although they are experienced in other notations describing object-oriented models like UML. This led us to the conclusion that it might be much more useful to apply the well-known UML in order to model the features and variability [6].
Order Process
Payment
ShippingCost
Fulfilment
{xor}
CreditCard
PayOnDelivery
Delivery
Download
Fig. 1. UML Feature Model: Order Process of an eCommerce System
Figure 1 depicts the simplified feature model of a order processs that is part of almost every eCommerce system. The overall concept OrderProcess is decomposed into the features Payment, ShippingCost and Fulfilment. Payment is specialised in several payment possibilities: by CreditCard or PayOnDelivery. As you can select only a single method per order these are modeled as exclusive alternatives. In opposition, the fulfilment strategies Delivery and Download can be co-existent, e.g. offering a software per Download and sending a copy on CD via the slower postage delivery. Delivery is also an precondition for PayOnDelivery, modeled with a ‘requires’ composition rule. Also ShippingCost only apply if you use Delivery. Therfore ShippingCost’s are optional since they don’t have to be paid of only Download is used. In contrast to a FODA model in our “bottom-up” approach an UML feature model may be simply derived from models of the existing non-product-line system. Actually 1
The terms hot spot and frozen spot have first been introduced in the domain of frameworks [14].
the UML feature model is an abstract model of the system as it may be used in the analysis phase in order to define the requirements (in fact the feature model represents the requirements for the product-line system). This abstract model has now to be extended by the various alternatives, dependencies and exclusions which define the potential realisations of the product-line system.
3
Variability of Systems
There is no formal pattern how the feature definition could be automatically mapped to the architecture. Like in object-oriented notations (e.g. UML) there is a certain semantical gap which makes it impossible to generate the derivation. Since in our “bottom-up” approach the invariable elements (frozen spots) are already known only the hot spots have to be addressed. This could be done in a traditional way or with aspects. The latter seems to be the natural way to solve the problem. 3.1
Traditional Approaches
In [17] H.A. Schmid demonstrates how hot spots may be designed by applying design patterns which is actually an conventional approach which preserves most of the existing architecture. He determined that e.g. 19 of the 23 design patterns of the GoF design pattern catalogue may be applied to model variability. Most of these patterns are based on the Strategy pattern [8]: An abstract super-class defines an interface which has to be kept by the real sub-classes. The sub-classes override the inherited abstract methods and modify the architecture by this way. This approach assures that the real sub-classes fulfil the requirements given in the super-class where the sub-classes may be variably exchanged. When a sub-class doesn’t fit to the scheme (interface) determined by the super-class the compiler will realise the problem (e.g. the signature of an overriding method doesn’t fit to the abstract method or there is no method given to override an abstract method in the super-class which is called by the architecture). The application of design patterns is very useful and eases the development of variable hot spots. However the disadvantages of this approach are that a modification requires a new class or object to be explicitly integrated by inheritance into the system. It would be much better if the classes to adapt the product-line existed already in the product-line and are simply switched on or off. Moreover there exists no possibility to define in advance negative (or positive) interactions between the features to modify the product-line. This problem could be solved by applying the concept of cross-cutting concerns. 3.2
Implementing Variability as Cross-cutting Concerns
Our intention is to modify the existing base system by adding new items (realising the variability). In general these new elements may be either: – filters that switch on or off specific existing functionality – or predefined functionality which may be arbitrarily added to the system. Both cases may be realised by applying aspects. Figure 2 depicts the implementation of the variability by aspects. The aspects have been woven in the existing base system and serve as filters and connection mechanisms between the classes. They may be woven to classes which are already existing in the base system as well as to classes which are added in order to build a product-line (like
Order Process
ntt PP ay aymmeen
De live ry
requires
optional
Shipping Cost
PayOn De live ry
Fulfilment
Cre ditCard Paym e nt
xor Pa yOn CreditCard Delivery
xor CreditCa rd
depends on
Download
woven in
ADpp elirvoevryal
D Ao pp wrnoload v al
intera cts with
Fig. 2. Aspect Model of Order Process Variability
an additional way fulfilling customers order, e.g. Download if Delivery exists already in the base system). The applicability of aspects is given since aspects may be used to implement design patterns. However the aspects may be simply woven into the existing system in order to implement a variablity. The modification of the code like the traditional implementation of flexible elements propose (c.f. section 3.1) is not required. Moreover aspects allow to integrate several classes or subsystems depending on each other. In the Order Process example Delivery and Shipping Cost are both integrated with the same aspect in the system. In contrast to simple design patterns interactions (requires and xor ) between different hot spots can be modelled and implemented as well. These interactions are indicated by a jagged arrow. When a system is derived from a product-line the interaction have to be taken into account in order to prevent errors. Further aspects may be used to implement the interactions. These aspects assure that the required interaction is performed. A version system like proposed in [15] may support the design and validation of a larger number of interactions. In this case versions express the different possible customisations of the hot spots which are correct. Since there exist different aspect concepts to realise aspects it is one goal of our approach to define aspect systems which support this “bottom-up” product-line approach. Currently we investigate a transformation system operating on the abstract syntax tree of a product line. Quite close alternatives may be the composition filter approach [5], adaptive component connectors [13] or AST manipulation approaches like [18].
4
Related Work
Complementary work may be found in all aspect-oriented and related approaches like ASPECTJ [10] subject-oriented programming [9], adaptive programming [11] or also transformation systems [3] (including the above mentioned adaptive plug & plays [13],
composition filters [1] or XML-based AST manipulations [18]). All these approaches may potentially be applied to realise the “bottom-up” product-line approach. They support the implementation of the “bottom-up” way of inserting variability into existing systems. Additionally generative programming [7] may provide means to generate variable elements into base systems which is yet another realisation for separated concerns. In contrast to existing product-line engineering methods the “bottom-up” approach is oriented on the reuse and extension of existing systems. However there had been approaches to apply aspect-oriented principles to build product-lines. One approach is GenVoca [2] which allows to build a system family as layered architecture. Another approach may be found in [4]. This paper proposes the application of aspects in product-line software development in general. Complementary to the “bottom-up” approach is the field of feature interaction which provides means to ensure that only correct flexible elements exist in a productline and that only valid systems may be derived from this product-line. Several approaches have been discussed at the ECOOP 2001 Feature Interaction in Composed Systems workshop [16]. A potential solution for the modelling and verification of the static dependencies between features (and the aspects realising the features as well) may be the versioning approach introduced in [15].
5
Conclusion
The “bottom-up” product-line approach is invented in order to support the reuse of complete existing systems. These systems are transfered to product-lines by the weaving in of concerns which implement the variability (or a chosen customisation respectively). Therefore the high effort for re-engineering existing systems or even rebuild like in conventional approaches (“top-down” approaches) may be considerably reduced. The aspects realising the variablity serve as filters or connectors between classes and subsystems and the static part of the product-line (frozen spot). Additionally the interactions between the flexible elements may be realised by cross-cutting concerns.
References 1. M. Aksit. Composition and Separation of Concerns in the Object-Oriented Model. ACM Computing Surveys, 28(4), December 1996. 2. D. Batory and B.J. Geraci. Composition Validation and Subjectivity in GenVoca Generators. In IEEE Transactions on Software Engineering, pages 67 – 82, 1997. 3. I. Baxter. Design Maintenance Systems. Communications of the ACM, 35(4):73 – 89, April 1992. 4. J. Bayer. Separation of Concerns in Product Lines Engineering. In K. Mehner, M. Mezini, E. Pulverm¨ uller, and A. Speck, editors, Aspektorientierung - Workshop der GI-Fachgruppe 2.1.9 Objektorientierte Software-Entwicklung. Technischer Bericht der Universitt Paderborn tr-ri-01-223, May 2001. 5. L. Bergmans and M. Aksit. Composing Crosscutting Concerns using Composition Filters. Communications of the ACM, Special Issue on Aspect-Oriented Programming, 44(10):51 – 57, October 2001. 6. M. Clauss. Generic Modeling using UML extensions for variability. In Workshop on Workshop on Domain-specific Visual Languages, OOPSLA 2001, pages 11–18, Tampa, Florida, June 2001. 7. K. Czarnecki and U.W. Eisenecker. Generative Programming - Methods, Tools, and Applications. Addison-Wesley, 2000.
8. E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Abstractions and Reuse of Object-Oriented Software. Addison-Wesley, Reading, 1994. 9. Ossher H. and P. Tarr. Using Subject-Oriented Programming to overcome common Problems in Object-Oriented Software Development/Evolution. In Proceedings of the 1999 International Conference on Software Engineering, pages 687 – 688, May 1999. 10. G. Kiczales, J. Lamping, A. Mendhekar, C. Maeda, C.V. Lopes, J.-M. Loingtier, and J. Irwin. Aspect-Oriented Programming. In LNCS 1241, ECOOP. Springer-Verlag, June 1997. 11. K. J. Lieberherr. Adaptive Object-Oriented Software: The Demeter Method with Propagation Patterns. PWS Publishing Company, 1996. 12. M. D. McIlroy. Mass-produced software components. In P. Maur and B. Randell, editors, Engineering Concepts and Techniques, Proceedings of 1968 North Atlantic Treaty Organisation (NATO) Conference on Software Engineering Garmisch-Partenkirchen, pages 138 – 150. NATO Science Commitee, Jan 1976. 13. M. Mezini and K.J. Lieberherr. Adaptive Plug-and-Play Components for Evolutionary Software Development. In ACM SIGPLAN notices, volume 33, October 1998. 14. W. Pree. Komponenten basierte Softwareentwicklung mit Frameworks. dpunkt, Heidelberg, 1997. 15. E. Pulverm¨ uller, A. Speck, and J.O. Coplien. A Version Model for Aspect Dependency Management. In Proceedings of International Symposium of Generative and Componentbased Software Engineering (GCSE 2001), LNCS 1241, pages 70 – 79. Springer, 2001. 16. E. Pulverm¨ uller, A. Speck, M. D’Hondt, W.D. De Meuter, and J.O. Coplien. Workshop on Feature Interaction in Composed Systems, ECOOP 2001. Budapest, Hungary, June 2001. 17. H.A. Schmid. Systematic Framework Design by Generalization. Communications of the ACM, 40(10):48 – 51, Oktober 1997. 18. S. Schonger, E. Pulverm¨ uller, and S. Sarstedt. Aspect Oriented Programming and Component Weaving: Using XML Representations of Abstract Syntax Trees. In Workshop on Aspect-Oriented Software Development, Bonn, Germany, 2002.
Part II
Aspects and Distributed Systems
Formal Aspects for Distributed Systems Pertti Kellom¨aki,
[email protected] Institute of Software Systems Tampere University of Technology Finland January 28, 2002 Abstract We argue that superposition and the joint action style of specification are well suited for the aspect-oriented formal specification of distributed systems. Superposition steps structure a specification according to behavior instead of implementation level components. Superposition also makes it possible to verify temporal safety properties and refine and compose specifications in a way that preserves these properties.
1
Introduction
Much of the complexity of distributed systems stems from the interplay of different mechanisms for atomicity, fault tolerance, etc. Because of performance considerations many distributed algorithms contain optimizations to reduce the amount of data transferred. Unfortunately these optimizations can make such algorithms hard to understand and verify. Ideally one should be able to specify the mechanisms relatively independently, and to compose them to produce specifications of efficient implementations. Correctness of distributed systems if often expressed in terms of their temporal properties1 . A specification method for distributed systems should thus allow for convenient reasoning about temporal properties, and help in modularizing both specification and verification in a way that aligns with the temporal properties. We identify the following needs. 1. Distributed mechanisms require the cooperation of several objects, so a single syntactic unit of modularity should be able to introduce data and operations into multiple implementation level components. 2. It should be possible to specify independent aspects of collective behavior in parallel branches of specification, and merge the branches to form a composed specification. 3. Because formal verification of temporal behavior is expensive, temporal properties should be preserved both in refinement and composition. 4. For the same reason it is desirable to be able express and verify aspects in an abstract form in order to reuse verification effort. It should thus be possible to design and verify aspects of collective behavior independently of their deployment. Needs 1–3 have been addressed in the long term research project DisCo [1] and the associated specification language [6, 5]. The approach is based on stepwise refinement using superposition and joint actions (abstractions of distributed cooperation). To address the last item in the wish list, we have designed and implemented a formal specification language Ocsid, an experimental 1 Temporal properties in the temporal logic sense, i.e. ordering of events. We do not consider real-time properties here, even though they can also be specified using superposition (see e.g. [10]).
specification list is class node is NEXT : ref node; end; action delete by toDelete, pred : node is when pred.NEXT = ref(toDelete) do pred.NEXT := toDelete.NEXT; toDelete.NEXT := ref(toDelete); end; end; Figure 1: A high level specification of deletion from a distributed list variant of the DisCo language. The language allows us to specify and verify aspects of collective distributed behavior and to compose aspects into specifications in such a way that the aspects are woven together. The language has a formal semantics given in the typed higher order logic of the PVS [11] theorem prover, which is allows for fully mechanized reasoning about Ocsid specifications [9].
2
Joint Actions and Superposition
In the joint action [2, 3] style of specification, distributed systems are specified using atomic guarded parallel assignments involving multiple objects. The formal basis is linear time temporal logic, and behavior is specified in terms of state variables that reside in objects. The structure of objects is dictated by classes. A system described by a joint action specification starts in some initial state satisfying the initial condition of the specification, and proceeds to execute enabled actions one at a time. If more than one action is enabled (i.e. a combination of objects for which the guard evaluates to true exists), one of the actions is nondeterministically selected. Figure 1 shows an example of a joint action specification, a simplified version of an example borrowed from [12]. It describes how objects of class node are arranged in a singly linked ring, and how a node is deleted from the ring. Identifiers toDelete and pred in action delete are formal roles in which objects may participate. The initial configuration of the nodes would be specified by an initial condition which we omit in the interest of brevity. In order to further reduce the number of irrelevant details, we only consider deletion. Insertion of new nodes would be specified similarly. Joint actions in a high level specification may imply synchronizations that are not directly possible in an actual implementation, but are useful at the specification level to express distributed cooperation. Stepwise refinement is used to introduce lower level mechanisms that implement the synchronizations. For example, action delete in Figure 1 cannot be directly implemented in a distributed system, because it needs to assign to the NEXT attribute of two objects. Our strategy is to introduce new variables from which NEXT can be calculated, and consequently omit NEXT and the synchronizations needed for accessing it from the implementation. Superposition is a simple form of stepwise refinement, where the only transformation is to add new structure to a specification. An Ocsid superposition step may introduce new state variables into classes, strengthen the guards of actions, and introduce assignments to the newly introduced state variables. Previously introduced variables cannot be assigned to, which preserves safety properties2 by construction. 2 Safety properties in the temporal logic sense: something bad never happens. This is in contrast to liveness properties: something good eventually happens.
In our example, we superimpose two implementation level mechanisms on the high level specification: an implementation of atomic assignment using a state machine and the exchange of request and reply messages, and coordination implemented by the circulation of a token. Figure 2 depicts a superposition step (a layer in DisCo parlance) that implements action delete atomically. A layer consists of a requires part and a provides part. The requires part describes the classes and actions that need to be present in a specification in order for the step to be applicable, and the provides part describes the new structure to be added to the specification. New structure is superimposed on classes and actions in extensions. The ellipsis “. . . ” in extensions denotes the existing components of the base class or action. Variables of enumeration types can be used for implementing hierarchical state similar to Statecharts [4]. After declaring variable status to be of an enumeration type containing the values valid and invalid, we can declare variable next to be accessible only when the value of status is valid as follows: status : (valid, invalid); [status’valid].next : ref node; The requires part describes a closed world, meaning that in a specification to which the step is applied, delete must be the only action assigning to the state variable NEXT. The closed world assumption along with the initial condition and extensions provided by the layer make it possible to verify temporal properties of the resulting specification. When verifying temporal properties for a layer we assume that actions in the base specification imply the corresponding actions in the requires part of the layer. When the layer is superimposed on a specification, it is sufficient to verify the action implications to establish that the invariants proved for the layer hold in the result. This is similar to what Katz suggests in [7]. The invariants provided by layer messages l are: ∀n ∈ node : n.status = valid ⇒ n.N EXT = n.[status0 valid].next
(1)
∀n ∈ node, r ∈ request : r.existsAs = message ∧ r.[existsAs0 message].f rom = ref (c) ⇒ n.N EXT = r.[existsAs0 message].next
(2)
∀n ∈ node, r ∈ reply : r.existsAs = message ∧ r.[existsAs0 message].to = ref (c) ⇒ n.N EXT = r.[existsAs0 message].next
(3)
Layer messages l is superimposed on specification list as specification messages is superimpose(messages l, list); The second parallel branch of specification describes how a token is used for coordinating deletions. In the interest of brevity, we only outline the layer here. It requires class node and action delete, and provides classes freeToken and reservedToken and actions reserveToken, passFreeToken and passReservedToken. Initially there is a single free token which is passed around with action passFreeToken. When an object wants to initiate deletion, it waits for the free token. After acquiring the token, the object consumes it and sends a reserved token in action reserveToken. The reserved token is then passed around with action passReservedToken. Upon receiving a reserved token, an object may execute delete, consume the reserved token and send a free token. The safety property provided by the layer is that exactly one token exists at any time and that actions reserveToken and delete alternate.
3
Composition
In our approach, classes and actions in a common ancestor specification provide the points where separately specified aspects meet. If a class or an action has been extended in parallel refinements,
layer messages l requires class node is NEXT : ref node; end; action delete by toDelete, pred : node is when true do pred.NEXT := _; – – underscore denotes an arbitrary value toDelete.NEXT := _; end; provides new class request; new class reply; class extension node is . . . status : (valid, invalid); [status’valid].next : ref node; end class extension request is . . . existsAs : (nothing, message); [existsAs’message].from : ref node; [existsAs’message].next : ref node; end class extension reply is . . . existsAs : (nothing, message); [existsAs’message].to : ref node; [existsAs’message].next : ref node; end initially init is ∀ n : node; req : request; rep : reply :: n.status = valid ∧ req.existsAs = nothing ∧ rep.existsAs = nothing; new action requestDelete; new action completeDelete; action extension requestDelete by . . . n : node; r : request is when . . . n.status = valid ∧ r.existsAs = nothing do . . . r.existsAs := message; r.[existsAs’message].from := ref(n); r.[existsAs’message].next := n.[status’valid].next; n.status := invalid; end; action extension delete by . . . req : request; rep : reply is when . . . pred.status = valid ∧ rep.existsAs = nothing ∧ req.existsAs = message ∧ req.[existsAs’message].from = ref(toDelete) do – – ‘pred.NEXT refers to the value assigned to pred.NEXT in the base specification pred.[status’valid].next := ‘pred.NEXT; req.existsAs := nothing; rep.existsAs := message; rep.[existsAs’message].to := ref(toDelete); rep.[existsAs’message].next := ‘toDelete.NEXT; end; action extension completeDelete by . . . n : node; rep : reply is when . . . rep.existsAs = message ∧ rep.[existsAs’message].to = ref(n) do n.status := valid; n.[status’valid].next := rep.[existsAs’message].next rep.existsAs := nothing; end; end; Figure 2: Message exchange as an Ocsid layer
its structure in a composition of the refinements reflects all the extensions. For a class this means that in addition to the state variables in the common ancestor, it contains all the state variables introduced in the refinements. For an action this means that in addition to the structure of the common ancestor it contains all the new roles introduced in the refinements, the guard is a conjunction of the common guard and the new conjuncts, and the body contains the common assignments and the new assignments. We also allow merging of independently introduced entities. In our example we want a single message to play the role of a delete request and a reserved token. This is done by merging the two classes and the actions that send the messages: specification protocol is compose messages, token; class requestAndToken := deleteRequest, reservedToken; action requestDeletePassToken := requestDelete, reserveToken; end; Merging classes deleteRequest and reservedToken into requestAndToken means that the three names all denote the same class, we just happened to use different names for the class in the branches. Merging actions is equivalent to executing the component actions simultaneously. Compared to programming languages, the absence of control flow in joint action specifications simplifies composition considerably. We only need to indicate to which action the new participants, guard conjuncts and assignments are added. Their relative ordering does not matter. In some ways our composition is similar to that of Tarr et al [13]. Composition of parallel refinements can be seen as a restricted special case of composition of hyperslices. The reason for the much more stringent restrictions on composition in our approach is the desire to preserve temporal properties in composition, which we believe to be of crucial importance in the design of correct distributed systems.
4
Abstract Aspects
While the superposition step in Figure 2 can be understood and verified independently, it is still tightly coupled to the specification in Figure 1 because the names of entities in a layer and in a specification need to match. Verification of temporal properties is insensitive to the names of classes, state variables and actions. For example, if we systematically replace NEXT with V in step messages l and in the invariants, the modified invariants trivially hold for the modified superposition step. This observation allows us to express aspects of collective behavior at a more abstract level. For example, instead of of specifying how the specific action delete is implemented, we can design and verify a superposition step that specifies how to implement an action A where two objects of class C atomically modify their instance variables V of type T. This superposition step can then be instantiated for any desired class, action and type. Verification of the abstract step can be reused by establishing that the specification fulfills the assumptions of the superposition step [9].
5
Conclusions
As pointed out by Katz in [8], superposition steps can be used to structure specifications according to features of behavior rather than implementation level components. We advocate the use of superposition for aspect-oriented specification of distributed systems for the following reasons. Superposition is a simple, well-understood mechanism with a sound formal basis. Combined with the joint action style of specification it allows one to specify distributed behavior at a level of abstraction where distributed cooperation is explicitly visible. Temporal properties are an important correctness criteria in the specification of distributed systems. Superposition steps allow one to express cooperation of objects in such a way that
temporal properties can be verified independently. Verification and design effort is reused when a verified superposition step is used in constructing a specification. Joint actions make the cooperation in a distributed system explicit. The application level semantics can be given at a high level of abstraction, and archived superposition steps can be used for refining the specification into a form that can be implemented in a distributed fashion. Each archived step encapsulates a particular temporal property, so the modularity of the specification matches the modularity of desired properties.
References [1] The DisCo project WWW page. At http://disco.cs.tut.fi on the World Wide Web, 2001. [2] R. J. R. Back and R. Kurki-Suonio. Distributed cooperation with action systems. ACM Transactions on Programming Languages and Systems, 10(4):513–554, October 1988. [3] R. J. R. Back and R. Kurki-Suonio. Decentralization of process nets with a centralized control. Distributed Computing, (3):73–87, 1989. [4] David Harel. Statecharts: A visual formalism for complex systems. Science of Computer Programming, 8(3):231–274, June 1987. [5] Hannu-Matti J¨ arvinen. The design of a specification language for reactive systems. PhD thesis, Tampere University of Technology, 1992. [6] Hannu-Matti J¨ arvinen and Reino Kurki-Suonio. DisCo specification language: marriage of actions and objects. In Proceedings of the 11th International Conference on Distributed Computing Systems, pages 142–151. IEEE Computer Society Press, 1991. [7] Shmuel Katz. A superimposition control construct for distributed systems. ACM Transactions on Programming Languages and Systems, 15(2):337–356, April 1993. [8] Shmuel Katz and Joseph Gil. Aspects and superimpositions. Position paper at ECOOP’99 AOP workshop, 1999. [9] Pertti Kellom¨ aki. A structural embedding of Ocsid in PVS. In Richard J. Boulton and Paul B. Jackson, editors, Theorem Proving in Higher Order Logics, TPHOLS2001, number 2152 in Lecture Notes in Computer Science, pages 281–296. Springer Verlag, 2001. [10] Reino Kurki-Suonio and Mika Katara. Logical layers in specifications with distributed objects and real time. Computer Systems Science & Engineering, 14(4):217–226, July 1999. [11] S. Owre, J. M. Rushby, and N. Shankar. PVS: A prototype verification system. In Deepak Kapur, editor, 11th International Conference on Automated Deduction, volume 607 of Lecture Notes in Artificial Intelligence, pages 748–752. Springer Verlag, 1992. [12] S. Park and D. L. Dill. Protocol verification by aggregation of distributed transactions. In Rajeev Alur and Thomas A. Henzinger, editors, Proceedings of the Eighth International Conference on Computer Aided Verification CAV, volume 1102 of Lecture Notes in Computer Science, pages 300–310, New Brunswick, NJ, USA, July/August 1996. Springer Verlag. [13] Peri Tarr, Harold Ossher, William Harrison, and Stanley M. Sutton, Jr. N degrees of separation: Multi-dimensional separation of concerns. In Proceedings of the 1999 International Conference on Software Engineering, pages 107–119. IEEE Computer Society Press / ACM Press, 1999.
Distribution and aspects Hafedh Mili, Hamid Mcheick, and Salah Sadou† Dépt d’Informatique, UQÀM, C. P. 8888, Succ. Centre-Ville, Montréal (P.Q.) H3C 3P8, Canada Laboratoire VALORIA, Université de Bretagne Sud, Vannes, France {Hafedh.Mili@,{mcheick,sadou}@larc.info.}uqam.ca Abstract The separation of concerns, as a conceptual tool, enables us to manage the complexity of the software systems that we develop. Such was the intent behind the OORAM [Reenskaugh et al., 1995]. When the idea is taken further to software packaging, greater reuse and maintainability are achieved. There have been a number of approaches aimed at modularizing software around the natural boundaries of the various concerns, including subject-oriented programming [Harrison & Ossher, 93] aspect-oriented programming [Kiczales et al., 97], and our own view-oriented programming [Mili et al., 99]. The same applications that warrant the kind of separation supported by the above techniques tend also to be distributed where different users may be interested in different aspects of the application at different times. In this paper, we look at distribution in the context of the separation of concerns, and present an approach to distributing objects that embed different aspects.
1
Introduction
In the real world, objects change roles during their lifetime. Generally speaking, we need a mechanism for allowing objects to change behavior during their lifetime, specifically when that change takes place within the same program run. In the context of a distributed application, different sites, and different users within the same site, may see different aspects of the same objects, including different functionalities, different access rights and privileges, different quality of service parameters, and so forth. The transition from analysis to design consists of deriving an implementation of the functionalities specified at analysis time in a way that satisfies design-level constraints and properties and addresses design-level concerns. Addressing these concerns usually means adding code that crosscuts normal modularization boundaries, i.e. typically objects and methods. These are but three of the most common situations requiring us to modularize programs along dimensions other than the traditional function, class, or method, inherent in both procedural and object-oriented programming. There have been a number of approaches to providing language-level support for separation of concerns in the OO research community (subjects [Harrison&Ossher, 93], aspects [Kiczales et al., 1997], views [Mili et al., 99-01],
and others). Each one of these approaches was intended to solve one particular set of problems related to the three mentioned above. It turns out that the same applications that warrant the use of separation of concern techniques also tend to be distributed and offer different sets of functionalities to different user communities. Thus, we have a situation where: 1. Objects acquire and lose behavior dynamically (the dynamic behavior change problem), 2. Objects offer different sets of behaviors to different client programs simultaneously (the multiple interface problem), and 3. (Server) objects and client programs are distributed (the distribution problem). We could treat the different problems, if there are no interactions between the three aspects, or try to find a global solution that accommodates all three requirements in an optimal fashion. In this paper, we propose an approach that handles all three requirements in a unified framework. We assume that readers are familiar with AOP, subject-oriented programming/HyperJ ([Ossher et al., 95], [Tarr et al., 98]). We provide a brief overview of view oriented programming in section 2. Section 3 explores distribution issues in the context of these methods. Section 4 describes the principles underlying our approach. We conclude in section 5.
2
View oriented programming in a nutshell
We view each object of an application as a set of core functionalities that are available, directly or indirectly, to all the users of the object, and a set of interfaces that are specific to particular uses, and which may be added or removed during run-time. The interfaces may correspond to different types of users with similar functional interests or to different users with different functional interests. We set out to provide support for the following: • Enable client programs to access several functional areas or views simultaneously, 1. Support the addition and removal of views (functional slices) during run-time, making objects support different interfaces during run-time, and 2. Have a consistent and unencumbered protocol to address objects that support views. Figure 1 shows an aggregation-based implementation of this idea. The dashed object boundary (rectangle) represents our abstraction of an application object: it consists of the combination of the core instance and the views. In this example, the core object includes two state variables (‘a’ and ‘b’), and supports three operations (f(), g(), and h()). The view objects, which point to the core object, may add state (‘c’ for view 1 and ‘d’ for view 2), behavior (i(...) for view 1, j(...) for view 2, and k(...) for views 1 and 2), and delegate shared data and behavior. In this case, each behavior invocation goes to the components that implement it, i.e. either the core object or the views. The application object is seen as supporting the union of behaviors of the core instance and of the currently attached views. Roughly speaking, our approach consists of putting a wrapper around the core object and its views, which will intercept the various behavior invocations and dispatch them to the appropriate components. A major concern for our approach has been to not overburden developers who wish to take advantage of the view mechanism, with additional language constructs and novel thought processes: support for views has to be seamless. Accordingly, our implementation is based on:
• •
Providing an API for manipulating views during run-time (adding and removing, activating and deactivation) Transforming code that uses views by replacing simple (core object) references by references to the wrapper, when needed.
Application object i() View 1
View 2
-c : int +i() +k()
-d : int +j() +k()
j()
k() CoreObject -a : int -b : int +f() +g() +h()
Figure 1. An object with two views.
The following code excepts illustrate the idea. Assume that we are a merchandising company that manages a fleet of trucks. Different business functions view trucks differently. Operations see them as machine-like resources that need to be scheduled, and for which we need to schedule operators. Accounting view them as amortizable assets whose depreciation may be matched against earnings, reducing taxable income. And then, there is Inventory, which is concerned with the basic properties of a truck, such as the serial number, the make, model year, and the like. The following code excerpts show how a developer might write an application that supports different sets of functionalities at different times. import com.walmart.core.Truck; import com.walmart.finance.*; import com.walmart.operations.*; import com.walmart.maintenance.*; (1)Truck myTruck = new Truck(id); (2)myTruck.attach(“Finance”); (3)myTruck.attach(“Operations”);
f()
(4)float val = myTruck.getResidualValueOn(dt1);
(5) myTruck->releaseOn(); The truck is created by instantiating the core class (Truck, line (1)). Lines (2) and (3) add two functional aspects/concerns to the core object, corresponding to the views “Finance” (amortization, residual value, etc) and operations (scheduling, routing, etc.). Line (4) invokes a behavior that is supposed to be only part of the “Finance” view. Line (5) invokes a behavior defined by two views, and so a combination of the various implementations must be invoked. In order for the above code to exhibit the behavior we just described, this code is transformed by replacing references to the core object by references to its “wrapper”, which takes care of dispatching calls according to the number and state (i.e. active or inactive) of the views attached to the core object. It has been our experience that in business information systems, the roles played by domain objects often correspond to generic business processes, and do not depend on the business domain. Using our model of view programming, the different roles that an application object can play will be represented by views. We propose a kind of a template for functional roles/views that is parameterized by those elements of the interface of the core object that are required by the functional role. This template is called viewpoint. The views are then instantiations of the viewpoint for the core class, like Büchi & Weck’s generic wrappers [Büchi & Weck, 00].
3
Distribution issues
The combination of aspects and distribution is interesting for three reasons: 1) Distribution is, itself, one of those design aspects that crosscut implementation classes, and that clutter the code without bringing in any new user-defined functionality. It would thus seem to be a perfect fit for a technique such as aspect-oriented programming, which appears to be particularly well suited for separating design-level concerns. 2) Depending on the separation of concerns technique, objects that embody several
concerns may be fragmented, which may raise a number of issues for distribution, 3) Considering that different functional areas usually imply different data ownership and use privileges, to what extent can aspect, role, or view boundaries can be used as units for distribution—and thus duplication—in a distributed application context. We look at the three questions in turn.
3.1
Implementing distribution with separation of concerns techniques
The question here is whether distribution logic can be encapsulated in components along the boundaries of the various separation-ofconcerns techniques. There are two sides to this issue. First, we have to figure out where, in an object-oriented program, does distribution makes a difference, i.e. what needs to be changed to turn a non-distributed application into a distributed one. Once we do this, we then have to analyze the various separation-of-concerns techniques to figure out which method’s abstraction boundaries [Mili et al., 01] best match the required changed to accommodate distribution. Turning a regular application into a distributed one is, for the most part, a solved problem. Existing distribution frameworks all use a variant of the proxy pattern, and various compilers will automatically generate most of the code involved in “distributing” objects. There remain a few changes that need to be accommodated: • Lifecycle issues: the “creation” of remote objects is different from that of local objects. • Handling remote exceptions: remote method invocations may raise a number of exceptions that may either be related directly to the remoteness of objects, or that may be re-castings of user-defined exceptions. Both of these changes are to take place in the client program, but they can occur anywhere within a method. Both subject-oriented programming and vieworiented programming allow composition only at the method level. Only AOP supports composition at sub-method levels, with some restrictions. Thus, aspect-oriented programming seems to be the best fit for handling these kinds
of aspects, on demand. As we later see, we used AOP to introduce multi-aspect logic into distribution (CORBA) logic. Client site
Server site
perform(Message m, Target o) { Method meth = o.lookup(m); if ( meth = null) then deleg