Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Distribution and persistence as aspects

Software - Practice and Experience, 2006
...Read more
SOFTWARE—PRACTICE AND EXPERIENCE Softw. Pract. Exper. 2000; 00:1–6 Prepared using speauth.cls [Version: 2002/09/23 v2.2] Distribution and Persistence as Aspects S. C. B. Soares 1, and P. H. M. Borba 2, and E. A. G. C. Laureano 2, ‡§ 1 Pernambuco State University, Computing Systems Department, Madalena, Recife - PE, CEP 50720-001, Brazil. 2 Federal University of Pernambuco, Informatics Center, Cidade Universit´aria, Recife - PE, Caixa Postal 7851, CEP 50732-970, Brazil. 1 Microsoft Corporation, One Microsoft Way - 50/1315. Redmond, WA 98052, USA. SUMMARY This paper reports our experience using AspectJ, a general-purpose aspect-oriented extension to Java, to implement distribution and persistence concerns in a web-based information system. This system was originally implemented in Java and restructured with AspectJ. Our main contribution is to show that AspectJ is useful for implementing several persistence and distribution concerns in the considered application, but also in similar applications. We have also identified interferences between the implemented aspects and a few drawbacks in the language, so we suggest some minor language modifications that could significantly improve similar implementations. Despite those problems, we argue that the AspectJ implementation is superior to the pure Java implementation. Some of the aspects implemented in our experiment are abstract and constitute a simple aspect framework. The other aspects are application specific but we suggest that different implementations might follow the same aspect patterns. The framework and the patterns allow us to propose architecture-specific guidelines that provide practical advice for both restructuring and implementing certain kinds of persistent and distributed applications with AspectJ. Copyright c 2000 John Wiley & Sons, Ltd. key words: Aspect-oriented programming; separation of concerns, framework, persistence, distribution Correspondence to: Escola Polit´ ecnica da Universidade de Pernambuco, Departamento de Sistemas Computacionais, Rua Benfica, No 455, Madalena, CEP 50720-001. Recife - PE - Brazil. E-mail: sergio@dsc.upe.br E-mail: phmb@cin.ufpe.br E-mail: edlaure@microsoft.com § This work was done while the first and third authors were at Informatics Center of the Federal University of Pernambuco. Contract/grant sponsor: CNPq and CAPES. Copyright c 2000 John Wiley & Sons, Ltd.
2 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO INTRODUCTION In this article we give an extended and revised presentation of our work [1] on using AspectJ [2], a general purpose aspect-oriented [3, 4] extension to Java [5], to implement distribution and persistence aspects in a simple but real and non trivial web-based information system, a health complaint system, which was originally implemented in Java. In fact, the aspects implementation we present here had considerable evolved since the system restructuring resulting in improved and more reusable aspects. The distribution aspects implement basic remote access to system services using Java RMI Remote Method Invocation [6]. The persistence aspects implement basic persistence functionality using relational databases, and support the following main concerns: connection and transaction control, storage medium customization, and partial (shallow) object loading. Additionally there is an aspect for synchronizing object states with the corresponding database, when the software uses persistent data management, and/or with the corresponding remote server, when the software is distributed, in order to ensure consistency. During implementation of those aspects, it was necessary to define auxiliary exception handling aspects, which we also present here. We discuss the lessons learned implementing those aspects and justify our design decisions. The main contribution of our restructuring experience is to show that AspectJ is useful for implementing several persistence and distribution concerns in the kind of application considered, but we have also identified a few drawbacks in the language and suggest some minor modifications that could significantly improve implementations similar to the ones discussed here. Moreover, we mention other development difficulties that could be minimized by proper tools and processes for aspect-oriented development. We also argue that the AspectJ implementation of the health complaint system is superior to the pure Java implementation. Some of the aspects implemented in our experiment are abstract and constitute a simple aspect framework. These abstract aspects can be extended for implementing persistence and distribution in other applications that comply with the architecture of the health complaint system, a layer architecture used for developing web-based information systems. The other aspects are application specific and therefore have different implementations for different applications. Nevertheless, we suggest that different implementations might follow a common aspect pattern, having aspects with the same structure. Based on the framework and the pattern, we propose architecture specific guidelines that provide practical advice for both restructuring and implementing certain kinds of persistent and distributed applications with AspectJ. Those guidelines are actually a systematic description of a real world application implemented with AspectJ including a documentation of design rationale in the Health Watcher Aspects Section. ASPECTJ OVERVIEW AspectJ [2] is a general purpose aspect-oriented extension to Java. The aspect-oriented constructs support the separate definition of crosscutting concerns—concerns that affect several units of a system. This separation of concerns allows better modularity, avoiding Copyright c 2000 John Wiley & Sons, Ltd. Softw. Pract. Exper. 2000; 00:1–6 Prepared using speauth.cls
SOFTWARE—PRACTICE AND EXPERIENCE Softw. Pract. Exper. 2000; 00:1–6 Prepared using speauth.cls [Version: 2002/09/23 v2.2] Distribution and Persistence as Aspects S. C. B. Soares1,∗ and P. H. M. Borba2,† and E. A. G. C. Laureano2,‡§ 1 Pernambuco State University, Computing Systems Department, Madalena, Recife - PE, CEP 50720-001, Brazil.2 Federal University of Pernambuco, Informatics Center, Cidade Universitária, Recife - PE, Caixa Postal 7851, CEP 50732-970, Brazil. 1 Microsoft Corporation, One Microsoft Way - 50/1315. Redmond, WA 98052, USA. SUMMARY This paper reports our experience using AspectJ, a general-purpose aspect-oriented extension to Java, to implement distribution and persistence concerns in a web-based information system. This system was originally implemented in Java and restructured with AspectJ. Our main contribution is to show that AspectJ is useful for implementing several persistence and distribution concerns in the considered application, but also in similar applications. We have also identified interferences between the implemented aspects and a few drawbacks in the language, so we suggest some minor language modifications that could significantly improve similar implementations. Despite those problems, we argue that the AspectJ implementation is superior to the pure Java implementation. Some of the aspects implemented in our experiment are abstract and constitute a simple aspect framework. The other aspects are application specific but we suggest that different implementations might follow the same aspect patterns. The framework and the patterns allow us to propose architecture-specific guidelines that provide practical advice for both restructuring and implementing certain kinds of c 2000 John Wiley & persistent and distributed applications with AspectJ. Copyright  Sons, Ltd. key words: distribution Aspect-oriented programming; separation of concerns, framework, persistence, ∗ Correspondence to: Escola Politécnica da Universidade de Pernambuco, Departamento de Sistemas Computacionais, Rua Benfica, No 455, Madalena, CEP 50720-001. Recife - PE - Brazil. ∗ E-mail: sergio@dsc.upe.br † E-mail: phmb@cin.ufpe.br ‡ E-mail: edlaure@microsoft.com § This work was done while the first and third authors were at Informatics Center of the Federal University of Pernambuco. Contract/grant sponsor: CNPq and CAPES. c 2000 John Wiley & Sons, Ltd. Copyright  2 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO INTRODUCTION In this article we give an extended and revised presentation of our work [1] on using AspectJ [2], a general purpose aspect-oriented [3, 4] extension to Java [5], to implement distribution and persistence aspects in a simple but real and non trivial web-based information system, a health complaint system, which was originally implemented in Java. In fact, the aspects implementation we present here had considerable evolved since the system restructuring resulting in improved and more reusable aspects. The distribution aspects implement basic remote access to system services using Java RMI Remote M ethod Invocation [6]. The persistence aspects implement basic persistence functionality using relational databases, and support the following main concerns: connection and transaction control, storage medium customization, and partial (shallow) object loading. Additionally there is an aspect for synchronizing object states with the corresponding database, when the software uses persistent data management, and/or with the corresponding remote server, when the software is distributed, in order to ensure consistency. During implementation of those aspects, it was necessary to define auxiliary exception handling aspects, which we also present here. We discuss the lessons learned implementing those aspects and justify our design decisions. The main contribution of our restructuring experience is to show that AspectJ is useful for implementing several persistence and distribution concerns in the kind of application considered, but we have also identified a few drawbacks in the language and suggest some minor modifications that could significantly improve implementations similar to the ones discussed here. Moreover, we mention other development difficulties that could be minimized by proper tools and processes for aspect-oriented development. We also argue that the AspectJ implementation of the health complaint system is superior to the pure Java implementation. Some of the aspects implemented in our experiment are abstract and constitute a simple aspect framework. These abstract aspects can be extended for implementing persistence and distribution in other applications that comply with the architecture of the health complaint system, a layer architecture used for developing web-based information systems. The other aspects are application specific and therefore have different implementations for different applications. Nevertheless, we suggest that different implementations might follow a common aspect pattern, having aspects with the same structure. Based on the framework and the pattern, we propose architecture specific guidelines that provide practical advice for both restructuring and implementing certain kinds of persistent and distributed applications with AspectJ. Those guidelines are actually a systematic description of a real world application implemented with AspectJ including a documentation of design rationale in the Health Watcher Aspects Section. ASPECTJ OVERVIEW AspectJ [2] is a general purpose aspect-oriented extension to Java. The aspect-oriented constructs support the separate definition of crosscutting concerns—concerns that affect several units of a system. This separation of concerns allows better modularity, avoiding c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS Concerns OOP System requirements Concern identifier AOP (a) Classes Interfaces Aspects (b) W E A V E R 3 Executable system (c) Figure 1. Aspect-Oriented development phases. code tangling and code scattering over several units. Therefore, system maintainability is also increased. Programming with AspectJ uses both objects and aspects to separate concerns. Concerns that are well modeled as objects are separated that way; concerns that crosscut the objects are separated using units called aspects, and those are composed with the objects of a system by a process called weaving. By weaving AspectJ aspects with standard Java code, we obtain a new AspectJ application. Figure 1 illustrates aspect-oriented development phases. The first phase (Figure 1.a) is to identify the system’s concerns necessary to implement the system requirements† . After that, the concerns that can be well implemented as objects, are implemented in this way, using object-oriented programming, and the crosscutting concerns are implemented using aspectoriented programming, in order to increase the system’s modularity (Figure 1.b). Finally, the aspects and the classes are composed, by a process called weaver (Figure 1.c), to obtain the final version of an application with the required functionality. In fact, the phases illustrated by Figure 1 have to be accommodated in the context a software development process. Although requirements, analysis and design activities are crucial for any software development, we are focusing only on experience with AspectJ and not on experience of using AO across the life cycle. Despite not considering such activities, they should be placed in the Concern identifier phase. Considerations on that issue can be found elsewhere [7]. The main construct of the AspectJ [2] language is called aspect. Each aspect defines a functionality that crosscuts others, called crosscutting concerns, in a system. An aspect can declare attributes and methods, and can extend another aspect by defining concrete behavior for some abstract declarations. An aspect can affect the static structure of Java programs, by using AspectJ’s static crosscutting mechanism. This mechanism allows one to introduce new methods and fields † It is possible to derive several concerns from a single system requirement. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 4 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO 1: import java.sql.*; 2: 3: aspect DatabaseDebugging { 4: 5: pointcut queryExecution(String sql): 6: call(* Statement.execute*(String)) && 7: args(sql); 8: 9: before(String sql): queryExecution(sql) { 10: System.out.println(sql); 11: } 12: } Figure 2. AspectJ example. to an existing class, convert checked exceptions into unchecked exceptions, and change the class hierarchy by, for example, making an existing class extend another one. Aspects can also affect the dynamic structure of a program by changing the way a program executes. They can intercept certain points, called join points, of the program execution flow and add behavior before, after, or around the join point. Examples of join points are method calls, method executions, constructor executions, field references (get and set), exception handling, static initializations, and combinations of these using the logical !, && and || operators. An interesting set of join points can match all the execution points of an execution flow, and it is usually used combined to others in order to better identify joint points to be affected Usually, an aspect declares pointcuts that select sets of join points and context values at those join points. The aspect also declares advice in order to specify the piece of code that should be executed when a pointcut is matched during execution. The advice declaration indicates if the code should execute before, after, or around the pointcut. An aspect has access to reflective information of the join points through an attribute (thisJoinPoint). Figure 2 shows a simple but powerful aspect definition‡ . The aspect DatabaseDebugging defines a pointcut (line 5) to identify calls to methods with names starting with execute of the JDBC interface Statement that receives a string parameter (line 6) and expose the parameter (line 7) of the method call. The Statement methods named execute* are responsible to execute SQLs statements into the database. The aspect also defines an advice (line 9) that prints the SQL strings before the execution of the methods identified by the pointcut. Note that this 7 ‡ For simplicity and legibility reasons we omit the public visibility modifier in every piece of code throughout the paper c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 5 lines aspect will affect every point of the system that makes an access to the database using the java.sql.Statement interface. THE HEALTH WATCHER SYSTEM The Health Watcher, the information system used in our experiment, is a real health complaint system developed to improve the quality of the services provided by health care institutions. By allowing the public to register several kinds of health complaints, such as complaints against restaurants and food shops, health care institutions can promptly investigate the complaints and take the required actions. The system has a web-based user interface for registering complaints and performing several other associated operations. In order to achieve modularity and extensibility, a layer architecture and associated design patterns [8, 9, 10] were used in the Java implementation of the system. This layer architecture helps to separate data management, business, communication (distribution), and presentation (user interface) concerns. This structure leads to less tangled code—such as when business code interlaces with distribution code—but does not completely avoid it. For example, the code for starting and terminating transactions, in general, cannot be easily untangled by using this architecture and an object-oriented language. Moreover, in the cases where it can be untangled, one has to pay a high price for that: adapters have to be written just to take care of the transaction functionality. Another example is the code for providing data access on demand, which cannot be untangled too. The layer architecture of the Health Watcher system does not prevent scattering code too. This is the case of the code specifying which classes have to be serializable for allowing the remote communication of its objects. The exception handling code is also scattered throughout the system. The transactions code appears only in the facade class [8], the unique entry point to the system, but it is essentially replicated on all transactional methods of this class. Despite not completely separating concerns, the layer architecture gives some support to adaptability. Figure 3 shows two possible system configurations, where a relational database is used as the persistence mechanism accessed through JDBC. In the one used in our restructuring experience, the system is used through an HTML [11] and Javascript [12] user interface, which interacts with Java servlets [13] running in a web server. In the other configuration, a Java user interface interacts directly with an application server using Java RMI. Instead of RMI, it would be possible to use EJB [14, 15] (Enterprise JavaBeans) or another distribution technology. Similarly, we could also have an object-oriented database as the persistence mechanism. Moreover, for making tests easier and allowing early functional requirements validation, we could not use a persistence mechanism at all, but test and validate the system using nonpersistent data structures. After the system is mostly validated, we could then implement the persistence code. This kind of flexibility was desirable for the Health Watcher system, and justified the use of the layer architecture and some of the design decisions that we discuss later. Although some researches might think counter productive using nonpersistent data collection to test the software before plugging in a persistent collection [16], the use of nonpersistent data collections aims in early identifying requirements change. This increases productivity since the persistence code is only implemented after such validation [7], avoiding rewriting persistence c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 6 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO HTTP Client 1 (HTML + Javascript) RMI JDBC Web server (Servlets or JSP) Persistence mechanism Client N (Java application) Application Server Figure 3. System configurations. code if requirements change. In fact, the nonpersistent data collection should be automatically generated [7, 17], also increasing productivity. Figure 4 presents part of the Health Watcher UML [18] class diagram. For simplification, it only shows the classes involved in the complaint processing services, the others essentially follow the same pattern [10]; we also omit the classes from the communication layer, which allow remote access to system services. Complaints are registered, updated, and queried through a web client implemented using Java servlets. Accesses to the Health Watcher services are made through its facade (HWFacade), which is composed of business collections. The interface IPersistenceMechanism abstracts which persistence mechanism is in use. Classes implementing this interface (PersistenceMechanismRDBMS) should handle database connections and transaction management. In fact, this concrete class can be reused in other developments that use the same kind of database. Persistent data collections (ComplaintDataRDBMS) are used to map persistent data into business basic objects (Complaint), and vice versa. Those collections are used by business collections (ComplaintRecord) through business-data interfaces (ComplaintData). These interfaces allow multiple implementations of the data collections, using different data storage and management mechanisms, including nonpersistent data structures (ComplaintDataArray). To exemplify the tangling problem, the following piece of code shows some lines of the object-oriented version facade class, a business class. In the first line, there is a reference to a remote interface, which is code specific for distribution implementation. The class also has persistence specific code. The IPersistenceMechanism attribute (line 2) is responsible to allow implementing persistence transactions. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS <<UserInterface>> HttpServlet <<UserInterface>> UpdateComplaintServlet 7 <<Facade>> HWFacade <<BusinessCollection>> ComplaintRecord update(Complaint) <<PersistenceMechanismInterface>> IPersistenceMechanism connect() disconnect() beginTransaction() commitTransaction() rollbackTransaction() getCommunicationChannel() releaseCommunicationChannel() <<PersistenceMechanism>> PersistenceMechanismRDBMS <<Business-DataInterface>> ComplaintData insert(Complaint) remove(code) update(Complaint) search(code) : Complaint <<PersistentDataCollection>> ComplaintDataRDBMS <<NonpersistentDataCollection>> ComplaintDataArray <<BusinessBasic>> Complaint getCode() Figure 4. Partial Health Watcher class diagram. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: public class HWFacade implements IRemoteFacade { private IPersistenceMechanism pm; private ComplaintRecord complaintRecord; // ... public void update(Complaint complaint) { try { this.pm.beginTransaction(); this.complaintRecord.update(complaint); this.pm.commitTransaction(); } catch (ObjectNotFoundException e) { this.pm.rollbackTransaction(); throw e; } // other catch blocks for each throwable exceptions } //... } c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 8 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO Object-Oriented Functional requirements Data management Aspect-Oriented Distribution User interface Figure 5. Aspect-oriented Health Watcher restructuring. The transactions are implemented in every facade methods. In this example, the transactions are implemented from line 6 to 13, plus other catch blocks to rollback the transaction if other exceptions are raised. In fact, if we do not consider transaction implementation, this method would be implemented only by line 8. The aspect solution to this tangling is presented in the Health Watcher Aspects Section. HEALTH WATCHER ASPECTS In order to minimize the deficiencies of the pure Java implementation of the system considered in our experiment (see Section “The Health Watcher System”), AspectJ was chosen to restructure the system to implement distribution and persistence concerns. By doing this, we aimed to achieve better separation of concerns and avoid some tangling and scattering that cannot be avoided by simply using the layer architecture. Therefore, we hoped to obtain a more extensible system, supporting, without invasive changes, several different configurations required by the Health Watcher stakeholders. Figure 5 depicts the restructuring we made in the object-oriented Health Watcher system resulting the aspect-oriented Health Watcher. In the object-oriented version, different concerns are tangled with each other and scattered over several places of the system. In the aspectoriented version, the concerns are physically separated and well modularized, not scattered. As previously mentioned, these separated concerns should be woven to result the distributed and persistence version of the system. DISTRIBUTION ASPECTS In this section, we concentrate on the distribution aspects. Later we consider the persistence aspects and the complementary exception handling aspects. Those aspects are presented by discussing the steps we performed towards restructuring the pure Java version of the system and obtaining the AspectJ version. Although those steps are not generally applicable for all c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS Original system A local calls between A and B Distribution aspects B Client-side Recomposition process 9 Server-side Weaver Client-side aspect Distributed system remote calls between A and B Server-side aspect B A Client Server Distribution specific API Figure 6. Distribution code weaving. kinds of applications, we believe they can be used as specific guidelines for implementing distribution and persistence aspects in systems that comply with the architecture presented in Section “The Health Watcher System”. They can, likewise, be used as guidelines for restructuring such systems. Actually, the aspects we present had evolved, since their first version [1], to a more reusable aspects definition. In order to allow reuse we implemented an aspect hierarchy composed of abstract aspects, which are system-independent, and concrete aspects, which are specific to the Health Watcher system. In fact, the abstract aspects comply with the software architecture, like all others guidelines and abstract aspects we defined. Those abstract aspects define an aspect framework that provides aspect reuse, helping programmers to implement those concerns in other systems. The first step of the restructuring process for separating the distribution code was to remove the RMI specific code from the pure Java version of the system. Roughly, in a system that complies with the architecture presented in Section “The Health Watcher System”, the RMI distribution code is tangled in the facade class (server-side) and in the user interface classes (clients-side). Furthermore, the business basic classes also have some RMI code if their objects are arguments and return values of the facade’s methods, which are remotely executed. The RMI code was removed from the mentioned server and client classes and a similar functionality was separately implemented in associated server-side and client-side aspects, as explained by the following sections. Those distribution aspects are weaved (composed) to the c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 10 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO system resulting in the distribution version, as shown in Figure 6. This seems to be a common AspectJ pattern [19], where the aspects glue the functionality of their associated classes to the original system code. In fact, our distribution code consists of distribution aspects and auxiliary classes or interfaces. When this code is woven with the system code, it essentially affects the system facade and the user interface classes; the communication between them becomes remote by distributing the facade instance. Server-side distribution aspect The server-side distribution aspect is responsible for making the facade instance remotely available. It also ensures that the methods of the facade have serializable parameters and return types, since this is required by RMI. Implementing a reusable aspect RMI remote objects implement a so-called remote interface, which is used to access the remote services provided by those objects. Therefore, we can define an abstract aspect that uses this interface to generalize the server side behavior. Additionally, remote objects are required to extend the RMI UnicastRemoteObject class, which defines the behavior of remote objects and makes their references remotely available. This approach, although recommended by RMI specification, would require the server-side aspect to add RemoteException to the throws clause of the facade’s constructor. This would be necessary because the subclass (system facade) constructor calls the superclass (UnicastRemoteObject in this case) constructor, which declares that it might throw RemoteException. Unfortunately, the current version of AspectJ does not support that kind of static crosscutting. It can introduce, for example, methods, fields, and implements declarations, but not exceptions to a throws clause. As we could not make the facade extend UnicastRemoteObject, we obtained a similar effect using an RMI alternative. The exportObject static method, declared in UnicastRemoteObject, was used to export the facade instance and make it remotely available. This method is called by the facade main method, which essentially starts up the remote Health Watcher server. The abstract aspect defines an abstract pointcut to identify the execution of the facade main method. It also defines abstract methods to initialize the remote instance, to get the instance and the server names. abstract aspect ServerSide { abstract pointcut facadeMainExecution(); abstract Remote initFacadeInstance(); abstract String getSystemName(); abstract String getServerName(); Those abstract methods and pointcut are implemented by system specific aspects. The abstract aspect also defines and around advice that uses the abstract methods to export the facade instance and make it remotely available. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 11 void around(): facadeMainExecution() { try { Remote facade = initFacadeInstance(); String systemName = getSystemName(); UnicastRemoteObject.exportObject(facade); java.rmi.Naming.rebind("/"+ systemName, facade); } catch (RemoteException rmiEx) { ... } } catch (MalformedURLException rmiEx) { ... } } } In fact, this advice replaces the entire original main method, and therefore, the original behavior if despised. However, usually, the main method of a facade class might not even exist or it may only has tests over the system. It is very unusual a main method to be executed while the system is being executed. Defining a concrete aspect As previously mentioned, RMI remote objects must implement a remote interface. Hence, the concrete server-side aspect has to modify the facade class (HWFacade) to implement a corresponding remote interface (IRemoteFacade), which extends the RMI remote interface (java.rmi.Remote). Since the IRemoteFacade interface is only needed to implement distribution, its relationship with the system facade was implemented by the distribution aspect. This is done by using AspectJ’s declare parents construct: aspect HWServerSide extends ServerSide { declare parents: HWFacade implements IRemoteFacade; The IRemoteFacade interface, which is distribution specific code, was part of the pure Java version of the system, so we did not have to implement it again. In the AspectJ version of the system, this interface is specific and auxiliary to the distribution aspects, so it was grouped with the other auxiliary types. Besides extending RMI’s Remote interface, this interface contains the signatures of the facade public methods, however, adding the java.rmi.RemoteException in their throws clauses. This exception is used by RMI in order to indicate several kinds of configuration problems and remote communication failures. The concrete aspect must implement the abstract members of the abstract aspect in order to specialize it to a specific system. The methods Remote initFacadeInstance() { return HWFacade.getInstance(); } String getSystemName() { return "HealthWatcherSystem"; } String getServerName() { return /* server IP or DNS address */ } and the pointcut pointcut facadeMainExecution(): execution(static void HWFacade.main(..)); c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 12 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO As previously mentioned, facade class might not have a main method, and when this happens, we should add an empty one in order to enable the super aspect. This can be done through the use of AspectJ inter-type declarations, which adds a main method into the HWFacade class. Serializing types As demanded by RMI, the concrete server-side aspect should also make serializable all parameters and return types of the facade methods. Exceptions are for parameter and return values that correspond to remote objects themselves. In order to be serializable, a class has to implement the Java Serializable interface, which indicates that default object serialization should be available for its objects. So the aspect simply uses the declare parents construct for each parameter and return type that should be serializable: declare parents: healthGuide.HealthUnit || ... || complaint.Complaint implements java.io.Serializable; } This might indeed be repetitive and tedious, suggesting that either AspectJ should have more powerful metaprogramming constructs [7, 20] or code analysis and generation tools [7, 17] would be helpful for better supporting this development step. Those tools would be even more useful for the pure Java implementation, where we have to write basically the same code, but in a tangled and scattered way. Client-side distribution aspect A simple implementation of the client-side aspect would make the client (user interface) classes refer to the remote facade instance. They all have a HWFacade field that should yield the remote instance when accessed. At first, it seems that this could be easily achieved with AspectJ by intercepting the accesses to those fields. However, due to RMI conventions, the type of the remote reference is actually IRemoteFacade. So the remote reference is not assignable to the HWFacade fields and, consequently, those cannot yield that reference when accessed. This problem could be avoided if the client classes had IRemoteFacade fields, but those classes would then depend on RMI code, decreasing system modularity. If the remote reference had HWFacade type, another possibility would be to intercept calls to the facade methods, making sure that the calls are directed to the remote facade instance. This could be achieved by first defining a pointcut (line 1) to identify calls to the non-static HWFacade methods (lines 2 and 3), as long as they originate from the user interface classes (line 3), which in our case are Java servlets: 1: 2: 3: pointcut facadeCalls(HWFacade local): target(local) && call(* *(..)) && !call(static * *(..)) && this(HttpServlet); In this code, the pointcut parameter local indicates that we want to expose some value in the execution context of the associated join points. We use the target designator to bind c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 13 the local pointcut parameter to the target of the method calls, and the this designator to indicate that the currently executing object has type HttpServlet. Besides identifying the join points of the facade method calls, we would define an around advice (line 4) to affect those join points by substituting the reference to the local facade instance (the target of the call) with the reference to the remote facade instance: Object around(HWFacade local) throws /*...*/: facadeCalls(local) { return proceed(remoteHW); } This advice affects the facade calls, exposing the reference to the target of each call (line 4). It uses a reference to the remote instance (remoteHW, declared and initialized by the aspect) to proceed with the execution flow (line 5), but changing the execution context. This is done by changing the exposed reference to the target of the call: instead of the reference stored in local it becomes the one stored in remoteHW. This advice, however, would only be valid if the type of remoteHW were HWFacade, the type of the advice parameter, instead of IRemoteFacade. Redirecting method calls As the discussed solutions do not work with the current version of AspectJ, we had to write an advice for each facade method, essentially doing the same thing as the previous around advice, but in a specific way for each single facade method. For example, the advice for the update(Complaint) method is the following: int around(Complaint c) throws /*...*/: facadeCalls() && call(void update(Complaint)) && args(c) { return remoteHW.update(c); } It redirects the update calls to the facade remote instance. However, this is not done by changing the value of the target of the call, as in the general around advice shown before. Here the around advice does not proceed with the execution of the original call, but executes a new call to the same method, with the same argument, but with a different target. Since we do not change the value of any variable, we avoid the typing problems, with HWFacade and IRemoteFacade, discussed before. The facadeCalls pointcut used in this advice would be essentially the same as the one we have shown before, but does not need to expose a reference to the target of the call. The advices for the other facade methods are quite similar to this one. In fact, this solution works well but we loose generality and have to write much more tedious code. It is also not so good with respect to software maintenance: for every new facade method, we should write an associated advice, besides including a new method signature in the remote interface. Defining an abstract aspect In order to solve this problem and allow reuse, we define an abstract aspect that uses Java reflection and AspectJ features to redirect facade methods calls. The aspect defines an abstract c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 14 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO pointcut to identify facade calls, and abstract methods to retrieve the name bound to the remote instance and the name of the server where the remote instance is available. abstract aspect ClientSide { private Remote facade; abstract String getSystemName(); abstract String getServerName(); abstract pointcut facadeLocalCalls(); These abstract methods are not specific to the Health Watcher system, making the aspect more general. The aspect also defines the lookup service to retrieve the remote instance, assigning it to the facade field. private synchronized Remote getRemoteFacade() { if (facade == null) { String systemName = getSystemName(); String serverName = getServerName(); try { facade = java.rmi.Naming.lookup("//" + serverName + "/" + systemName); } catch (Exception ex) { throw new SoftException(ex); } } return facade; } Note that the method wraps any exception raised by the lookup method execution into a SoftException. This is our approach to any exception raised by a concern implemented in the aspects, since the exception handling aspects will be responsible to handle them. The aspect also defines an around advice that uses the AspectJ API to access the arguments and name of the method being called, and then to call the corresponding method of the remote instance. Object around(): facadeLocalCalls() { Object[] args = thisJoinPoint.getArgs(); Signature signature = thisJoinPoint.getSignature(); String methodName = signature.getName(); return MethodExecution.invoke(getRemoteFacade(), methodName, args); } } The auxiliary class MethodExecution defines the static method invoke to call method of objects using the Java reflection API. This approach simplifies and generalizes facade method redirection. Despite simplifying the number of lines of code and generalizing the method redirection, the use of reflection decrease code readability and avoids static type checking, c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 15 which may favor adding errors into the program. On the other hand, this abstract aspect is supposed to be reused, and therefore, should not be implemented by the programmer. The programmer has only to implement the concrete aspect, which is system-specific, inheriting the redirection behavior. Defining a concrete aspect The next step is to define a concrete aspect that should implement the ClientSide abstract methods and define the abstract pointcut to identify facade methods call, as in the following pointcut. pointcut facadeLocalCalls(): this(HttpServlet) && call(* IRemoteFacade+.*(..)) && !call(static * IRemoteFacade+.*(..)); This solution is quite superior to the corresponding pure object-oriented implementation. In fact, without using AspectJ and this approach, we would have productivity and maintenance problems. For instance, a common pattern for separating the distribution code in a pure Java implementation is to use factories and a pair of adapters [8, 9] between the facade and the user interface classes. However, in this way, we need to write much more code and a change in the facade class would require changing two classes besides the facade and the remote interface. Besides that, this alternative pure Java implementation cannot separate the distribution code at all, not satisfying the Health Watcher’s adaptability and extensibility requirements. Feature request Some problems we hade during system restructuring could be avoided if we could add an exception in a method throws clause. Therefore, we submitted a feature request to the AspectJ team, which they expect to consider for a following version of AspectJ. We suggested the support of a new constructor that adds an exception to a method throws clause. For example, it could be used as in the following declaration, where the wildcard * is used to match any return type and any method name, and the wildcard .. matches any parameter list: declare throws: (* IRemoteFacade.*(..)) throws RemoteException; This declaration would add the RMI specific exception, RemoteException, to the throws clause of all methods of the IRemoteFacade interface, assuming that this interface simply contains the signature of the public methods of the facade; it would not extend Remote and its methods would not throw RemoteException, this should be implemented by the aspect. In this way the client classes could have IRemoteFacade fields, since the RMI details would be introduced to the interface by the distribution aspects. The general solution shown at the beginning of this section could then be used; we should only replace HWFacade for IRemoteFacade in the facadeCalls pointcut definition. The proposed feature would be useful to solve similar problems mentioned elsewhere [21], reinforcing the need for its support. It would allow static exception checking, as opposed to c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 16 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO the use of AspectJ’s so-called softened exceptions, which are unchecked and therefore can be thrown anywhere, without further declarations. However, this feature must be used with care. It has to be used together with aspects that handle the newly added exceptions, otherwise a well-typed Java program, when woven with the aspect code, might yield a non well-typed program that does not handle some thrown exceptions. In fact, this feature does not have good compositionality properties. Synchronizing states When implementing the client-side aspect we had also to deal with the synchronization of object states. This was necessary because RMI supports only a copy parameter passing mechanism for non-remote arguments. So, when a facade method returns an object to the client, it actually returns a copy of the server-side object. Therefore, modifications to the client copy are not reflected in the server-side object. The client-side aspect should take care of this distribution concern, and make sure that the modifications to the client copies are reflected on the server. This could be done by intercepting the user interface (client) methods and synchronizing the states of the serverside copies changed by those methods. The synchronization could be performed through calls to update methods declared by the system facade. Later we concluded that this concern and its associated behavior are necessary for implementing persistence as well. Therefore, we actually implemented it only once, and the details are presented in Section “Data State Synchronization control”. This shows that the distribution and persistence concerns are not completely independent. It also shows that careful design activities are also important for aspect-oriented programming. Only in this way we can detect in advance intersections, dependences and conflicts among different aspects. Consequently, we can avoid serious development problems and better plan the reuse and parallel development of different aspects. Distributuion aspects class diagram Figure 7 presents a class diagram of the distribution aspects and the Health Watcher classes the aspects affect or use, as described in this section. The <<Aspect>> stereotype and the fill color blue identify the aspects. PERSISTENCE ASPECTS This section presents the steps that we followed in order to restructure the persistence code of the Health Watcher system and obtain the corresponding persistence aspects. The first step in this direction was to remove the persistence code from the pure Java version of the system. In a system that complies with the architecture presented in Section “The Health Watcher System”, the persistence code is mostly concentrated in the data collection and persistence mechanism classes, but also appears in the facade and in the business collection classes. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS <<Aspect>> ClientSide 17 <<Aspect>> ServerSide Remote (from java.rmi) <<Aspect>> HWClientSide <<Aspect>> HWServerSide IRemoteFacade update(Complaint) <<UserInterface>> HttpServlet (from javax.servlet.http) RemoteException (from java.rmi) <<BusinessBasic>> Complaint getCode() Figure 7. Distribution aspects class diagram The persistence code was removed from the pure Java system and a similar functionality was implemented as aspects. Figure 8 illustrates that and also shows that we have aspects for making the system work with nonpersistent data structures. As discussed in Section “The Health Watcher System”, this is useful for making testing easier and allowing early functional requirements validation, usually before the persistence code is written. When the persistence aspects are woven with the system code, we generate a persistent version of the system. The persistence source code includes the IPersistenceMechanism interface and implementations for this interface. The IBusinessData interfaces (see Section “The Health Watcher System”) is responsible to make transparent to the business collection classes what data management medium they are using, and was not factored out from the core source code. The persistence aspects affect the facade and business collection classes. The persistence code includes aspects and auxiliary classes and interfaces to address the following major concerns: connection and transaction control, partial (shallow) object loading and object caching for improving performance, and synchronization of object states with the corresponding database entities, for ensuring consistency. We now discuss most of them and briefly explain an auxiliary aspect for supporting data collection customization (one can choose between nonpersistent and persistent). Persistence mechanism control The persistence mechanism control aspects are responsible for implementing basic persistence functionality for all operations accessing the data storage mechanism. They create an instance of a persistence mechanism class (an implementation of IPersistenceMechanism provided by the persistence source code) and deal with database initialization, connection handling, and resources releasing, services provided through the created instance. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 18 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO System Executable Nonpersistent Data Source Code Aspects use Nonpersistent Version Classes Weaver crosscut ---------------------------------------- --------------------------------------- ------------------------------------------- Memory System Source Code Persistent Version crosscut Weaver Persistent Data Source Code Aspects use ---------------------------------------- --------------------------------------- ------------------------------------------- Database Classes Figure 8. Data management code weaving. For reuse purposes, this concern was implemented using an aspect hierarchy composed of an abstract aspect and a concrete aspect. The second is specific to the Health Watcher system, whereas the first can be used for implementing other systems that comply with the same architecture of the Health Watcher. Implementing a reusable aspect The abstract persistence mechanism control aspect is reusable. It defines two advice that depend on abstract pointcuts, which are made concrete by different concrete aspects, depending on the systems in which it is reused. This aspect (AbstractPersistenceControl) defines an abstract pointcut (initSystem) to identify the execution of the system initialization process; this is where an instance of a persistence mechanism class should be created and initialized. abstract aspect PersistenceControl { abstract pointcut initSystem(); abstract IPersistenceMechanism pmInit(); The aspect also declares an abstract method that should be used to initialize the persistence mechanism instance. Both the method and the pointcut are defined abstractly because their concrete definitions depend on specific classes of the system being implemented. Two advices were declared to initialize and release resources; their implementations use the abstract pointcut previously defined: c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 19 before(): initSystem() { getPm().connect(); } after() throwing: initSystem() { getPm().disconnect(); } The before advice states that, before system initialization, a persistence mechanism instance is created and connected to the database system. If any problem happens during initialization, the after throwing advice is executed; the resources allocated by the persistence mechanism are then released. The persistence mechanism disconnect method is only called after an abnormal execution, since when the system is shutdown, the persistence mechanisms connections are released. To achieve a more explicit behavior, the aspect might override the finalize method to assure resources releasing before the object be garbage collected. The getPm method creates, if necessary, and returns a valid IPersistenceMechanism instance. synchronized IPersistenceMechanism getPm() { if (pm == null) { pm = pmInit(); } return pm; } Those advices call methods that might raise exceptions, but it would not be interesting to handle them in the advice code, which will usually be executed before or after some facade code, during system initialization time. Therefore those exceptions were declared as soft, not checked, by the declare soft static crosscutting AspectJ construct. In Section “Exception Handling Aspects” we show how soft exceptions are handled. Note that this aspect uses a single instance of the persistence mechanism for the whole application, but it is simple to adapt this aspect to work with a pool of persistence mechanisms, instead of just one, when required. For example, this would be necessary in a distributed database environment. Implementing a concrete aspect The abstract pointcut and method declared in the previous aspect were concretely defined for the Health Watcher system in the following aspect. aspect HWPersistenceControl extends PersistenceControl { pointcut initSystem(): call(HWFacade.new(..)); IPersistenceMechanism pmInit() { return PersistenceMechanismRDMS.getInstance(); } The pointcut definition states that the initialization point of the Health Watcher system is the creation of the facade (HWFacade) instance. This aspect also implements the c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 20 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO persistence mechanism initialization method, pmInit. This method obtains an instance of the concrete implementation of the persistence mechanism for relational databases, PersistenceMechanismRBMS, and then connects it to the database system, using the connect method. As in the previous abstract aspect, we have to indicate that the persistence mechanism exception is soft when raised during the execution of the getInstance method: pointcut obtainPmInstance(): call(* PersistenceMechanismRDMS.getInstance(..)); declare soft: PersistenceMechanismException: obtainPmInstance(); The obtainPmInstance is just an auxiliary pointcut. The abstract aspect depends only on the persistence mechanism interface IPersistenceMechanism, benefiting software evolution, whereas the concrete aspect depends on a concrete persistence mechanism. Only the concrete aspect needs to be modified to support a different data storage mechanism such as object-oriented databases or another implementation for relational databases. The system can then be easily customized by simply replacing the concrete aspects and going through the weaving process. By using factories, a similar kind of customization could also be achieved in the pure Java implementation of the system. This would require more code to be written. On the other hand, it would allow customization without recompiling the system code, at least for a pre-existing set of customization alternatives. This is not currently supported by AspectJ, but is expected to be. Moreover, with the pure Java version it would be expensive to separate the code for ordering the creation and use of the persistence mechanism. This would have to be tangled to the facade code. Since the tangled code would depend only on the IPersistenceMechanism interface, the main direct disadvantage in this case would be with respect to the legibility of the facade, instead of its reusability or extensibility. Those would be indirectly affected only. Persistence control aspects class diagram Figure 9 presents a class diagram of the persistence control aspects and the Health Watcher classes and interfaces the aspects affect or use, as described. Transaction control When dealing with data stored in a persistence mechanism it is essential to work with transactions in order to guarantee the ACID properties [22]: atomicity of operations, data consistency, isolation when performing operations, and data durability even if the system fails. In the Health Watcher system, the transaction control code was mostly invoked from the facade class. Therefore, we removed this code and implemented the transaction control concern using two aspects to improve reusability, similarly to what was done in the implementation of the previous concern. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS <<Aspect>> PersistenceControl getPm() : IPersistenceMechanism 21 IPersistenceMechanism <<Aspect>> HWPersistenceControl connect() disconnect() beginTransaction() commitTransaction() rollbackTransaction() getCommunicationChannel() releaseCommunicationChannel() <<Facade>> HWFacade <<PersistenceMechanism>> PersistenceMechanismRDMS Figure 9. Persistence control aspects class diagram Implementing a reusable aspect The simplest version of the abstract transaction control aspect defines an abstract pointcut that should identify the transactional methods of the system; that is, the methods whose execution should be bound by a transaction: abstract aspect TransactionControl { abstract pointcut transactionalMethods(); abstract IPersistenceMechanism getPm(); It also declares an abstract method to obtain a valid persistence mechanism instance; it is necessary for invoking the transaction services supported by the persistence mechanism. The abstract transaction control aspect also implements three advice to begin, commit, and rollback transactions. The first one is a before advice that starts a transaction just before the execution of any transactional method: before(): transactionalMethods() { getPm().beginTransaction(); } As in the previous aspect definition, we should declare that the exceptions raised by the methods called inside the advice are soft; we omit the code here. We also have an after returning advice that commits the transaction when the method executions returns successfully: after() returning: transactionalMethods() { getPm().commitTransaction(); } c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 22 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO At last, an after throwing advice rolls the transaction back to the original state, maintaining the database in a consistent state, if any problem happens during the execution of any transactional method: after() throwing: transactionalMethods() { getPm().rollbackTransaction(); } Notice that any exception that is thrown and not handled by a transactional method aborts the transaction. We had the same behavior in the pure Java version of the Health Watcher system. This decision was perfectly adequate for both versions of the system and we believe that it would be adequate for other systems too. Nevertheless, this shows that the programmer that writes the persistence aspects should be aware of the behavior of the affected code. Likewise, the programmer who wishes to reuse our transaction aspects should be aware of the effect of throwing, and not handling, an exception. In fact, there might be a strong dependency between the aspect code and the Java code [21]. In the transactions case, we do not think that this brings major problems in practice. In general, more powerful AspectJ tools would be necessary to provide multiple views, and associated operations, for the strongly related AspectJ and Java units of code. Current tools, such as AJDT for Eclipse [23] and others [24], only show the dependency between the Java code and the aspects that affect it. Implementing a concrete aspect The concrete transaction control aspect (HWTransactionControl) inherits from the previous abstract aspect and provides concrete definitions for the abstract pointcut and method. When defining the concrete pointcut, we do not directly list the signatures of all transactional methods. This would affect aspect legibility and make the aspect code too much directly dependent on modifications on the method signatures. Therefore, we defined an interface containing the signatures of the transactional methods. This interface, ITransactionalMethods, is used by the pointcut to identify the transactional methods of the system. The pointcut matches the execution of all methods defined by the interface: aspect HWTransactionControl extends TransactionControl { declare parents: HWFacade implements ITransactionalMethods; pointcut transactionalMethods(): execution(* ITransactionalMethods.*(..)); The aspect also uses the declare parents construct to make the facade class, which contains all transactional methods of the Health Watcher system, implementing the ITransactionalMethods interface. This is necessary for associating the methods that will be executed with the signatures in the interface. The definition of the concrete method refers to the concrete persistence control aspect, which provides access to an instance of the persistence mechanism: IPersistenceMechanism getPm() { HWPersistenceControl pc = HWPersistenceControl.aspectOf(); return pc.getPm(); } c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 23 This method yields a valid instance of the persistence mechanism. This is done by obtaining the instance that is available in the HWPersistenceControl aspect, through its getPm method. We use the aspectOf method to obtain an instance of the aspect. This makes the concrete transaction aspect dependent on the concrete persistence control aspect, but the abstract aspects are independent of each other and can be reused and support different system customization alternatives. In fact, despite being syntactically independent, there is a semantic dependency between these abstract aspects, since persistent software usually also needs transaction control, and, probably, vice versa. The independency we claim relies in the fact that one does not provide nor uses services from the other. With this approach, the aspect is not directly dependent on the transactional methods signatures, but the auxiliary ITransactionalMethods interface is completely dependent on them. In fact, the interface should contain a subset of the signatures of the methods defined by the facade class. Once again this suggests that either AspectJ should have more powerful metaprogramming constructs [7, 20] or code analysis and generation tools [7, 17] would be helpful for better supporting this development step. Those tools would semiautomatically extract information from the facade every time the facade code changes, minimizing maintenance problems. The Health Watcher system with the transaction aspects is significantly better than the pure Java system. In the original system code, the transactional methods explicitly call methods for transaction control. They also have code for handling the associated exceptions. For each method, there are at least 6 lines of tangled code to call the transaction lifecycle methods and handle the exceptions. Factoring all these repeated lines of code in a single unit avoids tedious work and increases productivity. It also makes the code much easier to evolve, especially if modifications in the transaction control policies are required. In this way, the developers can be more focused on the more interesting aspects of transaction implementation and on the main functionality implementation. Implementing alternative policies The aspects illustrated in this section offer a uniform transaction control policy, which was useful for most situations in the Health Watcher system but might not be adequate for more complex or performance demanding systems. The same performance limitations are reported by a similar, although independently developed, AspectJ implementation of transactions in the context of the OPTIMA framework for controlling concurrency and failures with transactions [21]. However, slight variations of our implementation can offer several alternative policies and solve those limitations. For example, we could have different transaction implementations for read only and update operations (read transaction and write transaction, respectively). We could also have more than one class with transactional methods. In order to support different transaction implementations, it is useful to define an appropriate interface hierarchy to indicate the different kinds of transactional methods. The hierarchy shown in Figure 10 establishes that all transaction control interfaces should extend ITransactionalMethods. Interfaces specifying read only methods should extend ReadOnlyTransactionalMethods, and interfaces specifying update methods should extend UpdateTransactionalMethods. The class that implements the transactional c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 24 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO ITransactional Methods ReadOnly TransactionalMethods UpdateTransactional Methods UserDefinedRead OnlyMethods UserDefined UpdateMethods Figure 10. Transactional methods hierarchy. methods should then implement the specific interfaces, instead of simply implementing ITransactionalMethods, as done before. In addition to a different interface hierarchy, we should have variations of the abstract and concrete aspects. Instead of having a single pointcut, transactionalMethods, we should have two pointcuts, one for read operations (readOnlyTransMethods) and the other for write operations (updateTransMethods). Those pointcuts must match the execution of the methods of the associated interfaces. The abstract aspect should now have two sets of transactions advice, one set for each pointcut. Each set has a before, an after returning, and an after throwing advice, similar to the ones illustrated before. In this way, we can specify different behavior for the different kinds of transactional methods. Roughly generalizing, the transaction control aspects should contain a pointcut and a set of three transactions advice for each kind of transactional method existing in the system. In an extreme situation, we could maybe imagine each transactional method having a different type of transaction implementation. In this case, the AspectJ version would only have a small advantage over the pure Java version: by removing the tangled code, the facade becomes simpler. On the other hand, considering that we do not have advanced AspectJ tools as discussed in the beginning of the section, there is a disadvantage too: as we separated related code, changes to a code unit might usually affect the other. However, these extreme situations do not seem to be usual. In fact, it seems that our AspectJ implementation of transactions can usually have significant advantages over pure Java implementations. That is certainly the case of systems such as the Health Watcher. Another straightforward variation of the transaction control aspects supports multiple classes with transactional methods. In this case, one interface should be defined for each one of the classes. Those interfaces should extend the transactional methods interface ITransactionalMethods. For instance, suppose that the Health Watcher system contains c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 25 ITransactionalMethods ITransactionalCitizen <<Facade>> HWFacade CitizenFacade ITransactionalAdmin AdminFacade Figure 11. Example of multiple transactional components. transactional methods in two classes: CitizenFacade, defining the main system services, and AdminFacade, containing system administration and configuration services. Therefore, we should define two interfaces: ITransactionalCitizen and ITransactionalAdmin. Figure 11 shows the UML class diagram for this hierarchy. Besides having the extra interfaces, we should extend the concrete HWTransactionControl aspect to reflect this new structure: declare parents: AdminFacade implements ITransactionalAdmin; declare parents: CitizenFacade implements ITransactionalCitizen; The concrete transactionalMethods pointcut should also be modified to consider the executions of the methods declared in the new transactional interfaces. Transaction control aspects class diagram Figure 12 presents a class diagram of the transaction control aspects and the Health Watcher classes and interfaces the aspects affect or use. Data collection customization As explained before, the Health Watcher system should also work using nonpersistent data. In order to support this, two aspects were coded in such a way that we can build both application versions: nonpersistent and persistent. Each version is the result of weaving pure Java code with additional AspectJ code, as shown in Figure 8. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 26 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO <<Aspect>> TransactionControl getPm() : IPersistenceMechanism IPersistenceMechanism <<Aspect>> HWTransactionControl connect() disconnect() beginTransaction() commitTransaction() rollbackTransaction() getCommunicationChannel() releaseCommunicationChannel() ITransactional Methods <<PersistenceMechanism>> PersistenceMechanismRDMS update(Complaint) Figure 12. Transaction control aspects class diagram Implement a system-independent reusable aspect Again, we define an abstract aspect to increase aspect reuse. The aspect DataCollectionCustomization defines a pointcut to identify business collections creation abstract aspect DataCollectionCustomization { pointcut recordsCreation(): call(SystemRecord+.new(..)) && !within(DataCollectionCustomization+); by using an auxiliary class SystemRecord that should be made superclass of the business collections classes by the system-specific aspect. The aspect defines an around advice to return a business collection using the configured data collection, which is chosen by a concrete aspect. SystemRecord around(): recordsCreation() { Signature signature = thisJoinPoint.getSignature() return getSystemRecord(signature.getDeclaringType()); } protected abstract SystemRecord getSystemRecord(Class type); } The abstract method getSystemRecord should return the required business collection object based in the information of what class (business bollection) is being created in the affected join point. Note that this aspects uses information from the execution context through the variable thisJoinPoint [25]. This aspect simplifies the programmer work in the sense that the system-specific aspect that will implement the getSystemRecord method has only to define methods to retrieve the system-specific data collections for the required medium. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 27 Implement an abstract system-specific aspect Unlike the other abstract aspects, this one is system-specific in the sense that it must be defined for each system and therefore cannot be reused. The aspect HWDataCollectionCustomization identifies the system business collection classes and make them subclasses of SystemRecord: abstract aspect HWDataCollectionCustomization extends DataCollectionCustomization { declare parents: ComplaintRecord || ... extends SystemRecord; The aspect implements the getSystemRecord method by creating the corresponding business collection based on its Class information. protected SystemRecord getSystemRecord(Class type) { SystemRecord response = null; if (type.equals(ComplaintRecord.class)) { response = new ComplaintRecord(getComplaintData()); } else if (type.equals(... } return response; } protected abstract ComplaintData getComplaintData(); ... } Note that the getSystemRecord method uses an abstract method getComplaintData that is responsible to create the data collection to be used by the business collection. We omit the code for the others business collections, but it is similar to the ComplaintRecord code. It is important to mention the need to change the getSystemRecord method every time a business collection is added or removed from the system. This abstract, but system-specific, aspect is necessary in order to allow other aspects to inherit from it in order to define the medium the software should use. The following concrete aspects definition depicts this. The use of reflection, when the Class type is used by the getSystemRecord method, has some negative issues. For example, unlike the previous abstract aspect, this aspect is not part of the aspect framework. Therefore, the aspect has to be implemented by a programmer since it is system-specific. By using reflection, its code is more difficult to understand and reason about. On the other hand, this aspect implements only part of the reflection code, actually a simple part. The other part of the reflection is implemented in the previous abstract aspect, which is part of the framework. Implement concrete aspects For the persistent version, we have an aspect responsible for creating persistent data collections to the system, implementing the abstract methods responsible for retrieving the data collections. In fact, we should implement two aspects: PersistentDataCollection and c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 28 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO <<Aspect>> DataCollectionCustomization SystemRecord SystemRecord() <<Aspect>> HWDataCollectionCustomization <<BusinessCollection>> ComplaintRecord <<Aspect>> NonPersistentDataCollections <<Aspect>> PersistentDataCollections ComplaintData <<NonpersistentDataCollection>> ComplaintDataArray insert(Complaint) remove(code) update(Complaint) search(code) : Complaint <<PersistentDataCollection>> ComplaintDataRDBMS Figure 13. Data collection customization aspects class diagram NonpersistentDataCollection, respectively for retrieving persistent and nonpersistent data collections. This is possible because both persistent and nonpersistent data collections implement the same interface. Similar aspects can also be defined to associate different kinds of nonpersistent data collections. The aspect that associates the data collections using nonpersitent implementation is quite similar to the persistent aspect. Therefore, in order to switch between persistent and nonpersistent versions of the system we should only switch between the PersistentDataCollection and NonpersistentDataCollection aspects when weaving. As discussed in Section “Persistence mechanism control”, this kind of customization can also be supported by the pure Java implementation, with several advantages and some disadvantages. Data collection customization aspects class diagram Figure 13 presents a class diagram of the data collection customization aspects and the Health Watcher classes and interfaces the aspects affect or use. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 29 Data access on demand (partial object loading) Objects might have a complex structure, being composed of several other dependent objects. In those cases, object storage and retrieval in data storage mechanisms need special care to avoid performance degradation. An adequate approach to access this kind of object is to parameterize the data loading level. For each kind of object usage, an adequate loading level should be defined. For example, a service that lists complaints may only need to access the complaints description and code, whereas a service that generates a complex report may need the complaints description, code, associated disease type and related health unit data. This kind of data access on demand is an interesting feature when accessing large persistent object graphs, so it was implemented in the Health Watcher system. A common solution to associate the object access strategies with the different kinds of object usages is to provide the access methods with an extra parameter, say an integer, to indicate the desired loading level. So, for example, the search(int) method for accessing disease types by their integer code should have an extra parameter to indicate how much disease type information should be accessed. There are two problems with this approach. The first is that the extra parameter has nothing to do with the conceptual service being implemented, so we loose in legibility. The second problem is that this approach requires whoever accesses the objects to indicate this parameter value, generating an indirect dependence with specific persistent data collections, where the extra access methods are implemented. In order to avoid those problems detected in the pure Java version of the Health Watcher, we defined an aspect to deal with data access on demand. This aspect calls access methods with the extra parameter, but those are not visible to the system services. Those services, for example, call the search(int) method for accessing disease types. The aspect intercepts those calls and then calls the access methods with an extra argument indicating the required data loading level. In this way, we preserve the implementation of data access calls without needing an extra parameter, or any other kind of workaround in the user interface and business layers. Identifying kinds of object usages The data access on demand aspect first declares the pointcuts that identify where a specific kind of object usage appears. In order to illustrate that, we can use an interface (PartialLoadingServlet) to identify the servlets that generate web pages listing partial information about several objects of a class. aspect ParametrizedDataLoading { private interface PartialLoadingServlet {} declare parents: ServletSearchHealthUnit implements PartialLoadingServlet; For example, a servlet could generate a page with partial information about the various health units registered in the system by just showing the code and the name of the health unit, omitting, for example, the specialties of each health unit. In this case, the search method of the HealthUnit data collection should adopt a particular kind of object usage, namely partial object loading, which avoids retrieving complex attributes of objects, like relationships to other objects. Therefore, we must define a pointcut matching the execution of those methods: c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 30 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO pointcut partialLoadingServlets(): this(PartialLoadingServlets+) && execution(* do*(..)); We should list more servlets in the declare parents clause to identify all servlets that should generate a page with partial information. Applying the adequate loading level After specifying that the subtypes of PartialLoadingServlets adopt a specific kind of object usage, we must, for instance, specify that this kind of usage should be applied when searching HealthUnit objects in the associated data collection (HealthUnitDataRDBMS): pointcut healthUnitSearchCall(HealthUnitDataRDBMS huData, int code) : cflow(partialLoadingServlets()) && target(huData) && call(HealthUnit search(int)) && args(code); The target and the argument of the search method are exposed by the pointcut because those values are necessary for redirecting the matched method calls. The cflow construct is used to match only method calls that are in the execution flow of the join points matched by the partialLoadingServlets pointcut. Therefore, we intercept only search method calls that originate from the execution of the methods of PartialLoadingServlet and its subtypes. Similar pointcuts should be declared for other access methods called in the same context. In fact, the previous pointcut does not match any execution of those facade methods if the servlets and the facade are executing in different machines, i.e., the software are distributed. A solution for that is discussed in Section “Distribution aspects for partial loading”. Besides the pointcuts, we must have advice that intercept calls to the access methods and apply the appropriate data loading level. For accesses to health units, we have the following: HealthUnit around(HealthUnitDataRDBMS huData, int code) throws ...: searchCall(huData, code) { return huData.searchByLevel(code, HealthUnit.PARTIAL_ACCESS); } We basically replace the search method call for a searchByLevel call, using the same target and argument. The specified partial loading level corresponds to the level adopted by partialLoadingServlets. Using this solution, the persistent data collections should provide methods such as searchByLevel, with extra parameters to indicate the loading level. Alternatively, they could provide methods with different names. It is important to clarify that in our approach, the searchByLevel method is implemented in the data collection. This should not be seen as an invasive chance, since data collections are actually auxiliary aspects classes. For example the Health Watcher data collections are located in packages like aspects.dataManagement.dataCollections.rdbms. In fact, our approach contributes to code modularization, by implementing data collection methods directly in the data collections. Data collection and aspects should not be oblivious from each other, since both are in the ”aspect side”. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 31 <<UserInterface>> HttpServlet (from javax.servlet.http) <<UserInterface>> ServletSearchHealthUnit HealthUnitData insert(HealthUnit) remove(code) update(HealthUnit) search(code) : HealthUnit <<Aspect>> ParametrizedDataLoading <<BusinessBasic>> HealthUnit <<PersistentDataCollection>> HealthUnitDataRDBMS searchByLevel(code, level) : HealthUnit Figure 14. Data access on demand aspects class diagram This solution modularizes a persistence concern and solves some problems of the pure Java implementation. However, it presents some problems with respect to extensibility and legibility, problems of the original version as well. For example, when modifying the ServletSearchHealthUnit code, the programmer must be aware of the advice that intercept that code, otherwise it might try to have access to non-loaded health unit information. It might even be necessary to change the aspect because of changes in the servlet. This shows a strong dependence between the aspects and the Java code, requiring more powerful AspectJ tools as discussed in Section “Transaction control”, or more sophisticated pointcut definitions. For the transaction aspects, those tools could be helpful. For the aspect presented in this section, they would be very important. Our solution to data access on demand also requires more code to be written than in the pure Java version. Fortunately, the extra code follows the same pattern of the pointcuts and advice shown in this section. Code generation tools could easily generate the corresponding code templates. An alternative might be the use of generic aspects, similarly to generic classes in Java. Data access on demand aspects class diagram Figure 14 presents a class diagram of the data access on demand aspect and the Health Watcher classes and interfaces the aspects affect or use. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 32 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO DATA STATE SYNCHRONIZATION CONTROL The business and presentation layers deal with persistent objects, which contain data that reflect the data stored in the database. Those layers invoke several methods on those objects, changing attribute values in the objects only. Therefore, in order to guarantee object persistence, extra method calls are necessary to synchronize the object data with the database data, reflecting the attribute changes into the database. Similar synchronization calls are also necessary for distribution purposes, as discussed at the end of Section “Client-side distribution aspect”. Therefore, this concern is seen as a separate aspect, since it should be used in conjunction in both persistent and distributed versions. For separating concerns, those layers should not know whether an object is persistent (its state reflects stored data) or not (its state corresponds to nonpersistent data). Therefore, we removed the synchronization calls and implemented a similar functionality in the data state synchronization control aspect. When this aspect is woven with the pure Java code, it introduces the synchronization method calls in the business and presentation code, satisfying both persistence and distribution requirements. Identifying classes whose objects must be updated The UpdateStateControl aspect defines a tag interface (SynchronizableObject) to identify classes whose objects must be updated after being changed. aspect UpdateStateControl percflow(UpdateStateControl.servletService()) { private interface SynchronizableObject { void synchronizeObject(int updateSource); } The aspect uses a percflow designator to create an instance of the aspect for each execution flow specified by the pointcut servletService: pointcut servletService() : this(HttpServlet) && (execution(void doPost(..)) || execution(void doGet(..))); This avoids undesirable interferences between concurrent executions of Java servlets requests creating an aspect instance per servlet request, instead of sharing a single aspect instance among all requests. We used the declare parents construct to make the class Complaint subtype of SynchronizableObject. declare parents: Complaint implements SynchronizableObject; Identifying object updates The next step is to identify when objects of the previously identified classes are updated in the presentation layer (user interface). Those updates should be identified so that the updated c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 33 objects are temporarily stored, in a nonpersistent data structure, and later synchronized with the business layer. We used property-based crosscutting to simplify the specification of the updates in the presentation layer: pointcut remoteUpdate(SynchronizableObject o): this(HttpServlet) && target(o) && call(* set*(..)); This pointcut matches calls to the set methods of persistent objects, the target of the calls, but it considers only the calls executed by a servlet, the source (this) of the calls. This works well for the Health Watcher system because its user interface is implemented with Java servlets and its classes follow a name convention, actually the Java name convention: methods that change attribute values have names starting with set. The aspect also identifies updates in the business layer. In the Health Watcher architecture, those updates appear in the business collection classes. As we also follow a convention for those classes’ names (they all end with Record), we can have a general property-based pointcut definition for detecting persistent object updates in the business layer: pointcut localUpdate(SynchronizableObject o): this(*Record) && target(o) && call(* set*(..)); The name conventions simplify the pointcut definitions, but they are not essential. In fact, more complex pointcuts can be defined when naming conventions are not followed. In general, though, it could be tedious and error prone to list the signatures of the methods that correspond to persistent object updates. Therefore, if no conventions were followed, it would be quite useful to have a code analysis and generation tool that helps the user to identify those methods and generate part of the aspect code. Capturing updated objects The aspect identifies the updates and temporarily stores the modified persistent objects in a nonpersistent data structure. This is specified by the following code, which declares an advice and an aspect variable to hold a reference to the data structure: private Set remoteDirtyObjects = new HashSet(); after(SynchronizableObject o) returning: remoteUpdate(o) { remoteDirtyObjects.add(o); } The code for intercepting the updates in the business collection classes is quite similar to this one, so we omit it here. Synchronizing states During the execution of a system service, the previous advice captures and stores the updated objects. When the service execution terminates, the aspect can finally introduce the synchronization calls to reflect the updates in the database. This is specified by the following c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 34 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO pointcut and advice, which runs after the execution of the servlet services (doPost and doGet methods), when there are updated objects that have to be synchronized: pointcut remoteExecution(): if(UpdateStateControl.aspectOf().hasDirtyObjects()) && servletService(); after() returning: remoteExecution() { Iterator it = remoteDirtyObjects.iterator(); while (it.hasNext()) { SynchronizableObject o = (SynchronizableObject) it.next(); try { o.synchronizeObject(UpdateStateControl.REMOTE_UPDATE); } finally { it.remove(); } } } The advice basically iterates over the data structure holding the updated objects, synchronizing those objects. We should also define a similar pointcut and advice for synchronizing the objects changed by executing the methods of the business collection classes. Updating objects Finally, we should implement the synchronizeObject method that is responsible to update objects. This method is introduced into the class using the inter-type declaration mechanism: public void Complaint.synchronizeObject(int updateSource) { try { if (updateSource == REMOTE_UPDATE) { HWFacade facade = HWFacade.getInstance(); facade.update(this); } else { ComplaintRecord record = new ComplaintRecord(null); record.update(this); } } catch (Exception ex) { throw new SoftException(ex); } } Note once more our exception wrapping approach. The exception handling aspects are responsible to handle them. The record instantiation is actually intercepted by the DataCollectionCustomization aspect that initializes the record with the respective data collection to the used storage medium (see Section “Data Collection Customization”). For simplicity, we omitted the declarations for others classes whose objects should be updated if changed. They are, in fact, quite similar to the just illustrated. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 35 Comparing with the pure Java version, this solution is easier to modify since the synchronization concern is completely separated. It is also more concise than the corresponding Java implementation, where the synchronization calls are replicated in several parts of the system. Nevertheless, it also requires some tedious code to be written, so it would be helpful to have a code analysis and generation tool that would help the programmer in implementing this aspect for different systems complying with the same architecture of the Health Watcher system. Our solution for state synchronization also seems to be less error prone than the Java implementation, where the programmers might usually forget to write some synchronization calls. On the other hand, in the pure Java version the programmer might write the synchronization calls he wants, wherever he wants, benefiting from special optimizations. Some of those optimizations could also be achieved with AspectJ, by implementing different strategies for storing the updated objects and later synchronizing them. In general, though, we expect the AspectJ version to be less efficient than the Java version. In the Health Watcher system, this efficiency loss was insignificant. In more complex systems, dealing with several complex objects, we suspect it might not be worth to separate the synchronization concern using the implementation we proposed. Fortunately, the consequences of not separating this concern are not so drastic. In particular, that would not prevent alternative customizations for the system since the synchronization calls are not middleware dependent. Generalizing the distribution aspects As previously shown, the various implementations of the synchronizeObject method call facade methods, which indicates that the synchronization originates from updates in the user interface classes. In a distributed version of the system, those calls to the facade methods should be remote. In fact, the distribution aspects should intercept those calls. Unfortunately, as presented in Section “Client-side distribution aspect”, the client-side distribution aspect is based on the facadeCalls pointcut, which intercepts only facade method calls originating from Java servlets (see the this(HttpServlet) constraint in the pointcut). The synchronizeObject calls originate from persistent objects. In order to solve this problem, we had to generalize the definition of the facadeCalls pointcut in such a way that it includes new joint points corresponding to the execution of the facade methods called by the synchronizeObject method. pointcut facadeLocalCalls(): (this(HttpServlet) || within(UpdateStateControlPerCflow)) && call(* IRemoteFacade+.*(..)) && !call(static * IRemoteFacade+.*(..)); This shows the importance of defining general pointcuts that consider the interception of both the pure Java code and the other aspects code. Moreover, this reinforces the fact that the distribution and persistence concerns are not completely independent. They are semantically dependent. Therefore, careful design activities should have been performed before implementation, avoiding rework, although that was minimal in the reported case. A difficult in that direction is the lack of a proper notion of aspect interface, which would be useful for supporting parallel development. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 36 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO <<UserInterface>> HttpServlet <<BusinessCollection>> ComplaintRecord update(Complaint) (from javax.servlet.http) ComplaintData <<Aspect>> UpdateStateControl <<BusinessBasic>> Complaint getCode() insert(Complaint) remove(code) update(Complaint) search(code) : Complaint <<PersistentDataCollection>> ComplaintDataRDBMS Figure 15. Update state control aspects class diagram In our previous implementation [1], the persistence aspects depended on the distribution aspects that implement the data synchronization between the server and the clients. However, this concern was factored out, since it crosscuts both distribution and persistence. This allows us to use the distribution aspects together with the state synchronization aspect but without the persistence aspects when they are not necessary, and vice-versa. Data state synchronization aspects class diagram Figure 15 presents a class diagram of the data state synchronization control aspect including the Health Watcher classes and interfaces the aspect affects or uses. EXCEPTION HANDLING ASPECTS As some of the advice presented so far might raise exceptions that are not handled by the advice themselves, we had to implement auxiliary exception handling aspects. In the Health Watcher system, they basically handle AspectJ’s unchecked soft exception, since this is the type of the exceptions raised by the distribution and persistence advice. However, those aspects constitute an exception handling framework that could be used to handle other types of exceptions as well. Although exception handling is a natural crosscutting concern, usually implemented in a scattered form, in our experiment we concentrated on separating distribution and persistence concerns, and simply used the exception handling aspects to handle advice exceptions. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 37 Handling exceptions We first implemented a general aspect that defines an abstract pointcut for identifying the join points where the (softened) exceptions must be handled: abstract aspect ExceptionHandling { abstract pointcut exceptionJoinPoints(); Object around(): exceptionJoinPoints() { Object o = null; try { o = proceed(); } catch (SoftException ex) { this.exceptionHandling(ex); } } protected abstract void exceptionHandling(SoftException ex); } The aspect also defines an around advice that catches SoftException objects in the specified join points. This advice specifies that the exception should be handled by the exceptionHandling method, which is also declared as abstract by the aspect. Handling exceptions with servlets As the user interface classes of the Health Watcher system are Java servlets, we extended the general exception handling aspect with behavior useful for handling exceptions with servlets. The servlets are basically used to properly notify the user that something went wrong, and maybe suggest some specific actions she should take. In order to do that, the aspect code must have access to PrintWriter objects, which are used by servlets to write responses back to the service requester. The following aspect does that by defining a pointcut that identifies the join points where a PrintWriter object is obtained through the response object: abstract aspect ServletsExceptionHandling extends ExceptionHandling percflow(ServletsExceptionHandling.clientService()) { pointcut printWriterCreation(): target(HttpServletResponse) && call(PrintWriter getWriter()); It also declares an after returning advice, which actually get and store the PrintWriter object returned by the getWriter method call: private PrintWriter printWriter; after() returning (PrintWriter out): printWriterCreation() { printWriter = out; } This aspect uses a percflow aspect association to create an instance of the aspect for each entrance to the control flow of the join points defined the clientService pointcut (execution c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 38 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO <<Aspect>> ExceptionHandling (from org.aspectj.lang) <<Aspect>> ServletsExceptionHandling <<UserInterface>> HttpServlet SoftException (from javax.servlet.http) <<Aspect>> HWExceptionHandling Figure 16. Exception handling aspects class diagram of the do* servlets methods). This is necessary because one PrintWriter object is created for each request received by a servlet. So when handling exceptions we should make sure that we use the right PrintWriter to notify the user. This aspect also provides the concrete definition of the exceptionHandling method. It basically accesses the exceptions wrapped as soft exceptions and properly notifies the user through the PrintWriter object. In order to be reusable, the previous aspect is abstract and does not provide a concrete pointcut to identify the join points where the exceptions must be caught. Specific aspects should do this. In the Health Watcher system, we defined such a specific aspect (HWExceptionHandling) for identifying default exception handling join points: the service methods of the servlets, meaning that the default handling behavior is to notify the user. If other aspects need to define specific exception handling behavior, they must define a specialization of the aspect ExceptionHandling, providing the handling behavior and the join points to catch the exceptions. Exception handling aspects class diagram Figure 16 presents a class diagram of the exception handling aspects and the Health Watcher classes and interfaces the aspects affect or use. INTERFERENCES BETWEEN ASPECTS When performing the experiment we identified interferences between some aspects. Since the distribution aspects change the computing model by distributing the processing in different machines, they interfered with other aspects. The identified interferences were: c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 39 • Persistence aspects might call facade methods that should be redirected to the remote facade instance, when generating the distributed version. • Information about the execution context in the client-side is not available in the server side. For example, the cflow designator cannot identify join points in the server-side that was originated from the GUI control flow, because this flow information is not transmitted from the client-side to the server-side. We believe that the interferences of the distribution aspects are natural, since they modify the programming model when distributing part of the processing. Therefore, the distribution aspect must be aware of these interferences providing solution to them. The PersistentDistributedUpdateStateControl aspect declares a compile-time warning that identifies calls to the facade class. The programmer should investigate these calls and, if necessary, write the proper pointcut and advice to redirect them to the facade’s remote instance, similarly to what the ClientSideDistribution does. At the moment, this aspect affects theUpdateStateControl aspect, which calls facade methods. In Section “Data state synchronization control” the distribution aspect is generalized to affect the UpdateStateControl aspect. Distribution aspects for partial loading The ParametrizedDataLoading aspect uses information about the servlets execution flow in order to determine if a search method call should retrieve an object with complete or partial information. However, the current implementation of the AspectJ cflow designator cannot track the execution flow if the flow executes in distinct machines. Therefore, by distributing the servlets execution to another machine, or another JVM (Java virtual machine), the cflow designators in the aspects do not track the execution flow from the distributed servlets, not reaching the join points defined by the ParametrizedDataLoading aspect. Figure 17 depicts the problem mentioned above. Consider the PartialLoading aspect that uses information about the servlet execution flow in order to affect a facade’s method. When a specific servlet X calls a facade method (a) the aspect should affect its execution (b) changing its behavior. However, if the servlet and facade objects are distributed in different machines, the cflow designator used by the aspect does not match the servlet execution, since it does not occur in the same machine the aspect is running. Our solution adds a new method in the facade class in order to identify calls from servlet X to method m and redirects the original servlet call to the new method (c). Now, the aspect should use the cflow information from the added method (d) in order to affect m’s execution (e). This shows that the current implementation of the AspectJ cflow designator should be modified in order to support remote execution at least using RMI, since AspectJ is an extension of Java and RMI is the Java solution for distribution. There are proposals for implementing such kind of construction elsewhere [26]. As AspectJ does not provide such support, we develop a solution. We define new aspects that must be woven to the system if every time the ParametrizedDataLoading aspect and the distribution aspects are woven. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 40 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO Without the aspect With the aspect Machine A Machine A Servlet X Servlet X Machine B (a) class Facade { m() {...} } (b) aspect PartialLoading { ... } Machine B (c) class Facade { mFlag() {m()} m() {...} } (d) (e) aspect PartialLoading { ... } Figure 17. Interference problem and solution. Our solution has actually two additional aspects that affect the server and the client side. The aspects are responsible to add some explicit information in the server-side, in order to identify that an execution was made from a specific servlet and should be handled differently, as depicted by Figure 17. The FacadeDistributedParametrizedDataLoading aspect adds new methods to the facade class and to the remote interface to replace the servlets cflow information. aspect FacadeDistributedParametrizedDataLoading { abstract IteratorHW IRemoteFacade.flagGetHealthUnitList() throws ObjectNotFoundException, RemoteException; IteratorHW HWFacade.flagGetHealthUnitList() throws ObjectNotFoundException, RemoteException { return this.getHealthUnitList(); ... } Note that the added method has the same name of one of the facade methods but with a prefix (flag). Whenever this method is called, the data collection search method should execute a partial loading. In fact, this aspect should have more methods for dealing with additional use of the cflow designator. The next declaration defines a pointcut to identify calls to the added method. The cflow designator is used by another pointcut to identify calls to the data collection search method exposing the data collection and the argument of the method call. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 41 pointcut healthUnitFetchDataFacadeIntroducedMethod(): this(HWFacade) && execution(IteratorHW flagGetHealthUnitList()); pointcut flatLevelOfAccess(HealthUnitDataRDBMS huData, int code): target(huData) && cflow(healthUnitFetchDataFacadeIntroducedMethod()) && args(code) && call(HealthUnit search(int)); At last the aspect defines an around advice that redirects calls from the data collection search method to its searchByLevel method, just like the PartialLoadingServlets advice. The method redirection is performed based on the cflow of the flagged method since there is no explicit information available about the servlets execution flow. HealthUnit around(HealthUnitDataRDBMS huData, int code) throws ObjectNotFoundException : flatLevelOfAccess(huData, code) { return huData.searchByLevel(code, HealthUnit.SHALLOW_ACCESS); } } Similar code should be added into this aspect in order to identify new execution flows originated from servlets. Now in order to flag partial loading we have to redirect the calls from the servlets affected by the PartialLoadingServlets to the added flag methods. This is our solution to identify what method in the server-side was called by servlets that request partial loaded objects. The ClientDistributedParametrizedDataLoading aspect identifies calls to the servlets methods that can manipulate partial loaded objects. aspect ClientDistributedParametrizedDataLoading { pointcut getHealthUnitListCall(): this(ServletSearchHealthUnit) && target(IRemoteFacade+) && call(IteratorHW getHealthUnitList()); Note that the method identified by this pointcut is the one that has a corresponding flagged one in the facade. The next step is to define an around advice to redirect the servlet call from the original method definition to the flag method added by the previous aspect in order to allow the server side partial loading aspect to identify this call as a partial loading candidate. IteratorHW around() throws ObjectNotFoundException: getHealthUnitListCall() { try { IRemoteFacade healthWatcher = (IRemoteFacade) HWServerSide.aspectOf().getRemoteFacade(); return healthWatcher.flagGetHealthUnitList(); } catch(RemoteException ex) { throw new SoftException(ex); } } } c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 42 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO <<Aspect>> ClientDistributedParametrizedDataLoading <<Aspect>> FacadeDistributedParametrizedDataLoading IRemote Facade <<UserInterface>> ServletSearchHealthUnit <<Facade>> HWFacade <<PersistentDataCollection>> HealthUnitDataRDBMS searchByLevel(code, level) : HealthUnit Figure 18. Interferences between aspects The advice retrieves the remote instance from the HWServerSide aspect through the getRemoteFacade method. Once more we wrap the concern-specific exception into a SoftException to be handled by specific exception handling aspects. Theses interferences show that an aspect that implements a crosscutting concern should be aware if others crosscutting concerns can interfere with each other. Figure 18 shows a class diagram that presents two aspects that should be woven to the system when generating a persistence and distribution version of it. The diagram also presents the Health Watcher classes and the affected aspects. Restructuring experience summary Our experience on restructuring an object-oriented software to an aspect-oriented one, helped to validate the use of AspectJ for implementing several persistence and distribution concerns in the kind of application considered here. Moreover, we notice that the implementation of those concerns brings significant advantages in comparison with the corresponding pure Java implementation. However, we have identified a few drawbacks in the AspectJ language and suggested some minor modifications that could significantly improve implementations similar to the one discussed here. In addition, another drawback relies on the fact that the definition of a pointcut identifies (by using methods signatures, class names, etc.) specific points of a given system, the aspects become specific for that system, or for systems adopting the same naming conventions, decreasing reuse possibilities. Table I summarizes the implemented aspects given an overview of the aspects, and of what concerns the aspect deals with. The table also shows which aspects might be reused in other developments. Auxiliary types used by the aspects of our experiment are presented in Table II, also including the concern related to each type, which type can be reused, and if the type is a class or an interface. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 43 Table I. Aspects summary. Aspect name Related concern Is reusable? ServerSide HWServerSide ClientSide HWClientSide PersistenceControl HWPersistenceControl TransactionControl HWTransactionControl DataCollectionCustomization HWDataCollectionCustomization PersistentDataCollection NonPersistentDataCollection ParametrizedDataLoading UpdateStateControl ExceptionHandling ServletsExceptionHandling HWExceptionHandling FacadeDistributedParametrizedDataLoading ClientDistributedParametrizedDataLoading distribution distribution distribution distribution persistent data management persistent data management persistent data management persistent data management data management data management persistent data management nonpersistent data management persistent data management distribution and persistence exception handling exception handling exception handling distribution and persistence distribution and persistence yes no yes no yes no yes no yes no no no no no yes yes no no no Table II. Auxiliary types summary. Auxiliary type name Related concern IPersistenceMechanism PersistenceMechanismRDMS ITransactionalMethods SystemRecord Persistent data collections Nonpersistent data collections IRemoteFacade persistent data management persistent data management persistent data management data management persistent data management nonpersistent data management distribution Is reusable? Observation yes yes no no no no no interface class interface abstract class classes classes interface RELATED WORK This section presents works related to aspect-oriented programming, in particular, these works are related to the implementation of persistence or distribution concerns. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 44 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO Persistence as an Aspect Another work [16] that discusses how to implement persistence with aspects defines reusable aspects developed into a framework. Similarly to our work, this one has similar conclusions such as persistence can be modularized using aspect-oriented programming, some aspects can be reused, and systems cannot be developed unaware of the need for data storage. This means that programmers can only be partially oblivious to the persistence nature of the data. In fact, our work considers data management as an aspect, and considers persistence as one kind of data management. We use such approach to support the progressive approach [7, 27, 28], where persistence and distribution are not initially considered in the implementation activities, but are gradually introduced, preserving the system’s functional requirements. This progressive approach helps to decrease the impact caused by requirements changes during development, since a great part of the changes might occur before the final (persistent and distributed) version of the system. The work shows that data storage and update — the insertion of an object when it is created and its update when it is changed — can be modularized and the system can be unaware of these features (obliviousness). On the other hand, the system should be aware of data retrieval and deletion, since systems have to explicitly obtain or delete persistent objects from an external source, which forbids programmers to be completely oblivious of persistence. Therefore, in their solution the system has to use a specific interface (PersistenceData) to retrieve an object and a specific class (PersistentRoot) to delete it. This solution is quite similar to ours, however, we use a business-data interface that provides methods to insert, update, retrieve, and delete the objects. By using an interface, data management services, except transactions, can be implemented as Java collections, files, relational databases, or object-oriented databases. This adaptability is one of our goals, and is not supported by the related work that proposes solutions specific to relational databases and briefly discusses on how the framework could be adapted to suit other database technology, like object-oriented databases. An interesting feature provided by this work is a SQL translation aspect that translates an object-oriented model to a relational database (object-to-relational mapping) schema. It uses reflection (Java and AspectJ APIs) and generates SQL statements to access the database, whereas our approach hard-codes the SQL statements in the implementation of the data management aspects. In fact, our approach also uses reflection, however, with a different goal. We use reflection in the distribution aspects to generalize the redirection of local facade methods calls to the remote instance, avoiding the definition of an advice for each facade method. Our use of reflection can be avoided in future implementations of AspectJ, as explained in the Section Client-side distribution aspect. Concurrency and Transactions A related work is another AspectJ implementation of transactions, which was independently developed in the context of the OPTIMA framework for controlling concurrency and failures with transactions [21]. This implementation does not consider distribution and persistence c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 45 concerns as we do here, but deals mostly with transactions for implementing concurrency concerns. Nevertheless, there are similarities with our approach, so we discuss it in detail here. The authors of the OPTIMA approach first analyze the adequacy of AspectJ for completely abstracting transaction concerns in such a way that transactional behavior can be introduced in an automatic and transparent way to existing non-transactional systems. They conclude that AspectJ is not suitable for this purpose. We have not tried to analyze that in our experiment since we believe that the main aim of AspectJ, and aspect-oriented programming in general, is to modularize crosscutting concerns, not to make them completely transparent. For some situations, this transparency could be achieved by proper tools that would generate AspectJ code, but not by the language itself. The kind of transparency sought by the authors should not be confused with obliviousness, which is supported by AspectJ and allows a system programmer to not worry about inserting hooks in the code so that it is later affected by the aspects. This does not mean that the system programmer should not be aware of the aspects that intercept the system code. Likewise, the aspect programmer should be aware of the code that his aspect intercepts. In this sense, there might be strong dependencies between AspectJ modules, reducing some of the benefits of modularity. In spite of that, there are still important benefits that can be achieved. Moreover, we believe that this problem could be minimized by more powerful AspectJ tools providing multiple views, and associated operations, of the system modules. Appropriate notions of aspect interfaces should also be developed. AspectJ’s ability to separate transactional interfaces (begin, abort, commit), defining aspects to invoke the transactional methods whenever necessary, has also been analyzed by the same authors. Their implementation is similar to what we present, at the beginning of Section “Transaction control”, but they do not explore the variations that we present at the end of the same section. Those variations can actually avoid the performance problems they mentioned. They also faced the same problem we had with the impossibility of adding an exception to a method throws clause. However, our transaction control approach avoids this problem, which actually appears here when dealing with the distribution concerns (see Section “Server-side distribution aspect”). When separating the transactional interfaces, they also complain about the strong dependencies mentioned before, suggesting that AspectJ might not be useful for this task either. In the transactions case, we argue that the dependencies do not bring major problems in practice. This is the case because changes in the transaction aspects are minimal and usually do not affect the pure Java code, whereas changes in the Java code have only a very small impact on the aspects, assuming that it has been established that any exception that is thrown and not handled by a transactional method aborts the transaction. In fact, powerful AspectJ tools for dealing with dependencies would be needed much more for the data access on demand aspects (see Section “Data access on demand”) than for the transaction aspects. It seems that our AspectJ implementation of transactions can usually have significant advantages over pure Java implementations (see Section “Transaction control”). That is certainly the case for systems such as the Health Watcher. Finally, the OPTIMA experience tries to separate transaction mechanisms, supporting different customizations for transaction and concurrency control. They conclude that AspectJ is useful for that. Although we have not implemented much transaction customization, we had c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 46 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO the same positive experience using aspects to customize data management and distribution services. EJB Another related work is The Enterprise JavaBeans (EJB) architecture [14, 15]. EJB supports the development of distributed systems providing services such as transactions, database connectivity, and multi-user safety, which is also supported by our method, however, EJB implements those aspects in a transparent way. The EJB transparency makes easy to write systems in the sense that developers does not have to understand low-level transaction and state management details, multi-threading, connection pooling, or other complex APIs. On the other hand, developers cannot write their owns algorithms looking for performance improving, which happens in our approach, where the developers have to write their own code for implement transactions, database connectivity, distribution, and multi-user safety, dealing with different APIs. When using EJB to implement persistence and distribution, usually in a non-progressive way, another problem is the deployment time, which might be very high. To fix errors — including functional and persistence errors — a lot of time might be wasted by compiling the code and them deploying the system into the application server. When performing the experiment, we did not aim in providing implementation transparency, but in improving software modularity. This modularity allows the use of a progressive implementation approach, previously mentioned, where functional errors are early fixed and will not be mixed with persistence and distribution errors. Despite these differences between EJB and our approach, one possible implementation of our aspects can use the EJB architecture. Therefore, we would have aspects to implement persistence and distribution using the EJB architecture. This would lead to better modularity, by using AOP, and it would also achieve implementation transparency, provided by EJB. Our approach would also allow using EJB in a progressive approach. Actually, another way to achieve transparency with AspectJ, keeping the others benefits of AOP, is using code generation tools that would generate aspects, similar to EJB that generates classes. Others related works JBoss [29] is an Java aspect-oriented framework that provides a set of aspects to implement several concerns, such as transactions and distribution. Another related work in the same line of JBoss is JAC [30], a framework for building aspect-oriented distributed applications in Java. Both works have a great differential to ours by allowing dynamic weaving, which means aspects can be weaving and unweaving at runtime. Our approach is tailored to AspectJ language, whose current’s version does not allow dynamic weaving. Despite our approach being tailored to the RMI and JDBC APIs, our idea is to provide separation of concerns in general, modularizing persistence, exception handling, transactions, distribution, and so on. Therefore, those related works might be seen as complementary works, and other studies might be performed to investigate the use of JBoss and JAC with our approach, similar to what should be done with EJB. In addition, with our approach we also have a fine-grained c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 47 control over the aspects implementation, avoiding the overhead that might exist in general solutions that are hard to optimize. The implementation of distribution and persistence concerns in pure object-oriented systems was explored elsewhere, leading to specific design patterns [9, 10]. Those patterns support the progressive implementation of distribution and persistence code in an object-oriented system. Despite having similar goals, this approach does not achieve the same level of separation of concerns; for instance, the distribution and persistence exception handling are tangled with user interface and business code. There is also scattered code over several units, such as in the serialization mechanism implementation, and the identification of what objects should be made persistent, by using class inheritance. In fact, this was our motivation to study AOP and AspectJ in order to improve the modularity of those concerns. The need for higher adaptability and configurability of middleware is discussed elsewhere [31, 32]. This work discusses the problem of middleware architectures that vary from general features in order to support several domains, to optimizations supporting a particular domain with specialized runtime requirements. The work describes a case study where AOP is used to improve modularization of the CORBA [33] middleware, by factoring out aspects that were identified in CORBA. The identified aspects were implemented in AspectJ to increase the middleware configurability, since the aspects can be chosen at compile-time. This work is another example where AOP and AspectJ are effectively used to modularized crosscutting concerns. However, this work differs from ours because it modularizes concerns of a specific middleware (CORBA), making it customizable, whereas our approach modularizes concerns of a system. Their approach is complementary to ours. We could use their improved version of CORBA to implement another of the distribution aspects. In fact, our approach allows changing the middleware implementation where their approach does not aim in doing that. An experience to evaluate the suitability of AspectJ for modularizing crosscutting concerns in a middleware product line is related in another work [34]. The motivation was to use AOP to target multiple runtime environments with a single code base. Examples of addressed concerns are tracing and logging, event reporting, error handling, and performance monitoring. The work also discusses the impact of AOP on architectural quality. They derived conclusions about AspectJ similar to our experiment, one of the issues is pointcut fragility, which is the pointcut dependence on the system code. This demands refactoring [35] tools to consider this dependence in order to avoid refactorings breaking the aspect code. It is also considered the need for improvements of the AspectJ compiler, mainly error messages, which could give more support for the programmers. The main conclusion is that AspectJ can be used to modularize many important crosscutting problems, however, they did not report any interference problems as we did, probably because of the different nature of our crosscutting concerns (data management and communication) in contrast to their concerns (tracing and logging, event reporting, error handling, and performance monitoring). Regarding distribution and aspects, another work [36] proposes a tool for supporting aspectoriented distributed programming. They have the same goal of implementing distribution without changing the core system code. However, this work uses a specific language to state what objects are located in a host, modifying Java bytecode using Java reflection. In contrast, our approach uses a general-purpose language and does not worry in specify where objects c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 48 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO are located, but uses an API to implement remote methods call from the user interface to the system facade [8]. The need for Quality of Service (QoS) aspects in distributed programs are discussed elsewhere [37]. This work addresses QoS issues, such as, transmission errors, dynamic bandwidth fluctuation, overload situations, partial failures, etc. They define an IDL extension to allow QoS constructions and exemplify its use with CORBA. We agree that some of these issues should be considered when implementing distribution aspects. However, the approach in our experiment was to restructure an OO system to an AOP version and to investigate some issues of such restructuring. For example, how one aspect affects and is affected by others, what are the challengers in AOP, what kind of modification should be made to the AspectJ language to allow a better separation and composition of concerns, when a progressive approach is better than a non-progressive one§ , and so on. As a future work, we should care about QoS aspects to improve our framework allowing QoS management. Techniques such as implicit context [38] and CaesarJ [39] might be considered as alternatives for solving the remote facade issue, where local calls in the monolithic version of the software should be redirected to a remote instance to provide distribution behavior. CONCLUSION We discussed our experience on restructuring a simple, but real and non-trivial, web-based information system with AspectJ. In the new version of the system, the implementation of the distribution and persistence concerns are completely separated from each other and from the business and user interface concerns. Among other benefits, this might make easier changing the distribution middleware or the persistence mechanism without affecting the implementation of the other concerns. In fact, experimental studies or case studies should be carried out to evaluate the effective effort difference in maintaining an object-oriented versus an aspectoriented version of the software. The main contribution of our experience is to validate the use of AspectJ for implementing several persistence and distribution concerns in the kind of application considered here. Moreover, we notice that the implementation of those concerns brings significant advantages in comparison with the corresponding pure Java implementation. The only exception is the data access on demand concern; its implementation also has some disadvantages that could only be minimized with more powerful AspectJ tools supporting aspect interfaces and multiple views of the system modules, which would help programmers deal with strong dependencies between the aspects and the pure Java code. In fact, the need for this kind of tool was reported elsewhere [40]. In our experiment, we considered only basic remote communication concerns, not implementing distribution issues such as caching, fault tolerance, and automatic object deployment for load balancing. However, we believe that those issues could be implemented essentially using the presented approach, revealing no further conclusions about the use of § The analysis about the benefits and drawbacks of using a progressive approach will be reported in a PhD thesis and in papers to be written. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 49 AspectJ. Again, experimental studies or case studies should be performed to demonstrate the effectiveness of our approach when applied to other software. In spite of our successful experience with AspectJ, we have identified a few drawbacks in the language and suggested some minor modifications that could significantly improve implementations similar to the one discussed here. Furthermore, we noticed that AspectJ’s powerful constructs must be used with caution, since they might have undesirable and unintended side effects. Moreover, as the definition of a pointcut identifies (by using methods signatures, class names, etc.) specific points of a given system, the aspects become specific for that system, or for systems adopting the same naming conventions, decreasing reuse possibilities. This suggests that we should either support aspect parameterization [41, 42] or have the support of code generation tools [7, 17] when developing with AspectJ. The need for those tools has actually been noticed on several occasions during our experience. AspectJ’s development environment is also quite immature and needs considerable improvements in compilation time and bytecode size. It is also true that they have been continuously improved. Other discussions on AspectJ benefits and drawbacks from other point of views, like language design and implementation, can be found elsewhere [43, 44]. The distribution and persistence concerns considered here can be implemented separately. However, we noticed that the exception handling and state synchronization aspects are actually necessary for both distribution and persistence aspects. Moreover, the distribution and persistence aspects can be used separately, but if they are used together then some distribution advice must intercept the execution of some persistence advice. In addition, we showed that the distribution aspects affect the persistence aspects by breaking how some of then work. Therefore, additional aspects were implemented to solve those problems when using persistence in a distributed environment. This shows that the persistence and distribution aspects are not completely independent. Therefore, careful design activities are also important for aspect-oriented programming. This is the only way we can detect in advance intersections, dependencies and conflicts among different aspects. Consequently, we can avoid serious development problems and better plan the reuse and parallel development of different aspects. This need for design activities does not seem to have been considered in [21], leading to some of the problems discussed there. It has been noticed before that distribution issues should not be handled only at implementation or deployment time [45]. Some of the aspects implemented in our experiment are abstract and constitute a simple aspect framework. They can be extended for implementing persistence and distribution in other applications that comply with the architecture of the health complaint system, a layer architecture used for developing web-based information systems. Although specific, this architecture has been used for developing many Java systems: a system for managing client information and mobile telephone services configuration; a system for performing online exams, helping students to evaluate their knowledge before the real exams; a complex point of sale system, and many others. The other aspects are application specific and therefore have different implementations for different applications. Nevertheless, we suggest that different implementations might follow a common aspect pattern, having aspects with the same structure. Elsewhere [46], we document such an aspect pattern to implement distribution aspects in an object-oriented application. The c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 50 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO pattern structures can be encoded in code generation tools [17] and automatically generated for different applications, increasing productivity. Based on the framework and the patterns, we can derive architecture specific guidelines that provide practical advice for both restructuring and implementing certain kinds of persistent and distributed applications with AspectJ. However, much more experience with those guidelines is needed before they could be used by a tool for partially automating the refactoring of pure Java systems similar to the one considered here. This tool could do a lot of work mainly because the program structure and the guidelines are tailored to a specific architecture. ACKNOWLEDGEMENTS We would like to thanks CAPES and CNPq, brazilian research agencies, which partially support this work, the members of the Software Productivity Group (SPG), for their help during the discussions on this research, and the anonymous reviewers for they careful and important comments for improving the quality of this work. REFERENCES 1. Sérgio Soares, Eduardo Laureano, and Paulo Borba. Implementing Distribution and Persistence Aspects with AspectJ. In Proceedings of the 17th ACM conference on Object-oriented programming, systems, languages, and applications, OOPSLA’02, pages 174–190. ACM Press, November 2002. Also appeared in ACM SIGPLAN Notices 37(11). 2. Gregor Kiczales, Erik Hilsdale, Jim Hugunin, Mik Kersten, Jeffrey Palm, and William G. Griswold. Getting Started with AspectJ. Communications of the ACM, 44(10):59–65, October 2001. 3. Tzilla Elrad, Robert Filman, and Atef Bader. Aspect–Oriented Programming. Communications of the ACM, 44(10):29–32, October 2001. 4. Gregor Kiczales, John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc, and John Irwin. Aspect-Oriented Programming. In European Conference on Object-Oriented Programming, ECOOP’97, LNCS 1241, pages 220–242, Finland, June 1997. Springer-Verlag. 5. James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java Language Specification. Addison-Wesley, second edition, 2000. 6. Sun Microsystems. Java Remote Method Invocation (RMI). At http://java.sun.com/products/jdk/1.2/ docs/guide/rmi, 2001. 7. Sérgio Soares. An Aspect-Oriented Implementation Method. PhD thesis, Informatics Center, Federal University of Pernambuco — CIn-UFPE — Brazil, October 2004. Available at http://www.cin.ufpe.br/spg/GenteAreaThesis. 8. Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994. 9. Vander Alves and Paulo Borba. Distributed Adapters Pattern: A Design Pattern for Object-Oriented Distributed Applications. In First Latin American Conference on Pattern Languages of Programming — SugarLoafPLoP, Rio de Janeiro, Brazil, October 2001. Published in UERJ Magazine: Special Issue on Software Patterns. 10. Tiago Massoni, Vander Alves, Sérgio Soares, and Paulo Borba. PDC: Persistent Data Collections pattern. In First Latin American Conference on Pattern Languages of Programming — SugarLoafPLoP., pages 311–326, Rio de Janeiro, Brazil, October 2001. Published in University of São Paulo Magazine — ICMC, 2002. 11. Ian S. Graham. The HTML Sourcebook. Wiley Computer Publishing, second edition, 1996. 12. David Flanagan. JavaScript The Definitive Guide. O’Reilly & Associates, Inc., second edition, 1997. 13. Jason Hunter and Willian Crawford. Java Servlet Programming. O’Reilly & Associates, Inc., first edition, 1998. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 DISTRIBUTION AND PERSISTENCE AS ASPECTS 51 14. Richard Monson-Haefel. Enterprise JavaBeans. Oreilly, second edition, 2000. 15. Sun Microsystems. The Enterprise JavaBeans Specification Version 2.1, August 2002. At http://java.sun.com/products/ejb. 16. Awais Rashid and Ruzanna Chitchyan. Persistence as an aspect. In Proceedings of the 2nd International Conference on Aspect-Oriented Software Development (AOSD’03), pages 120–129. ACM Press, March 2003. 17. Marcelo d’Amorim, Clóvis Nogueira, Gustavo Santos, Adeline Souza, and Paulo Borba. Integrating Code Generation and Refactoring. In Workshop on Generative Programming, ECOOP’02, Málaga, Spain, June 2002. 18. Grady Booch, Ivar Jacobson, and James Rumbaugh. Unified Modeling Language — User’s Guide. Addison-Wesley, 1999. 19. Gail C. Murphy, Robert J. Walker, Elisa L.A. Baniassad, Martin P. Robillard, Albert Lai, and Milk A. Kersten. Does aspect–oriented programming work? Communications of the ACM, 44(10):75–77, October 2001. 20. Fernando Castor, Kellen Oliveira, Adeline Souza, Gustavo Santos, and Paulo Borba. JaTS: A Java transformation system. In XV Brazilian Symposium on Software Engineering, pages 374–379, Rio de Janeiro, Brazil, October 2001. 21. Jörg Kienzle and Rachid Guerraoui. AOP: Does it Make Sense? The Case of Concurrency and Failures. In European Conference on Object-Oriented programming, ECOOP’02, LNCS 2374, pages 37–61, Málaga, Spain, June 2002. Springer–Verlag. 22. Ramez Elmasri and Shamkant Navathe. Fundamentals of Database Systems. Addison–Wesley, second edition, 1994. 23. Object Technology International Inc. Eclipse Platform Technical Overview. White Paper. At http://www.eclipse.org/, 2001. 24. AspectJ development tools subproject. At http://www.eclipse.org/ajdt, 2005. 25. AspectJ Team. The AspectJ Programming Guide. At http://eclipse.org/aspectj, 2003. 26. Michiaki Tatsubori Muga Nishizawa, Shigeru Chiba. Remote pointcut: a language construct for distributed aop. In Proceedings of the 3rd International Conference on Aspect-Oriented Software Development, AOSD 2004, pages 7–15, March 2004. 27. Sérgio Soares and Paulo Borba. PIP: Progressive Implementation Pattern. In Michael Gnatz, Frank Marschall, Gerhard Popp, Andreas Rausch, Maura Rodenberg-Ruiz, and Wolfgang Schwerin, editors, Proceedings of the 1st Workshop on Software Development Patterns (SDPP’02), Technical Report TUMI0213, Munich University of Technology, Munich 12/2003, November 2002. 28. Paulo Borba, Saulo Araújo, Hednilson Bezerra, Marconi Lima, and Sérgio Soares. Progressive Implementation of Distributed Java Applications. In Engineering Distributed Objects Workshop, ACM International Conference on Software Engineering, pages 40–47, Los Angeles, EUA, 17th–18th May 1999. 29. Jboss aspect oriented programming webpage. Avalible at http://www.jboss.org/products/aop, 2005. 30. Renaud Pawlak, Lionel Seinturier, Laurence Duchien, Gérard Florin, Fabrice Legond-Aubry, and Laurent Martelli. JAC: an aspect-based distributed dynamic framework. Software — Practice and Experience, 34:1119–1148, 2004. 31. Charles Zhang and Hans-Arno Jacobsen. Resolving feature convolution in middleware systems. In OOPSLA ’04: Proceedings of the 19th annual ACM SIGPLAN Conference on Object-oriented programming, systems, languages, and applications, pages 188–205, New York, NY, USA, 2004. ACM Press. 32. Charles Zhang and Hans-Arno. Jacobsen. Quantifying aspects in middleware platforms. In Proceedings of the 2nd International Conference on Aspect-Oriented Software Development (AOSD’03), pages 130–139. ACM Press, March 2003. 33. Robert Orfali and Dan Harkey. Client/Server Programming with Java and CORBA. Wiley, 1998. 34. Ron Bodkin, Adrian Colyer, and Jim Hugunin. Applying aop for middleware platform independence. In Practitioner Report of the 2nd International Conference on Aspect-Oriented Software Development (AOSD’03), March 2003. 35. Martin Fowler et al. Refactoring: Improving the Design of Existing Code. Addison-Wesley, 1999. 36. Michiaki Tatsubori. Separation of Distribution Concerns in Distributed Java Programming. In OOPSLA’01, Doctoral Symposium, Tampa FL, 2001. 37. C. Becker and K. Geihs. Quality of service - aspects of distributed programs. In International Workshop on Aspect Oriented Programming (ICSE 1998), February 1998. 38. Robert Walker and Gail Murphy. Implicit context: easing software evolution and reuse. In SIGSOFT ’00/FSE-8: Proceedings of the 8th ACM SIGSOFT international symposium on Foundations of software c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6 52 S. C. B. SOARES AND P. H. M. BORBA AND E. A. G. C. LAUREANO engineering, pages 69–78. ACM Press, 2000. 39. Mira Mezini and Klaus Ostermann. Variability management with feature-oriented programming and aspects. In SIGSOFT ’04/FSE-12: Proceedings of the 12th ACM SIGSOFT twelfth international symposium on Foundations of software engineering, pages 127–136. ACM Press, 2004. 40. Robert Filman and Daniel P. Friedman. Aspect–Oriented Programming is Quantification and Obliviousness. In Workshop on Advanced Separation of Concerns, OOPSLA’00, 2000. 41. Neil Loughran and Awais Rashid. Framed aspects: Supporting variability and configurability for aop. In Proceeding of the 8th International Conference on Software Reuse: Methods, Techniques and Tools, ICSR 2004, pages 127–140. IEEE CS Press, July 2004. 42. Stefan Hanenberg and Rainer Unland. Parametric introductions. In Proceedings of the 2nd International Conference on Aspect-Oriented Software Development (AOSD’03), pages 80–89. ACM Press, March 2003. 43. Elisa L. A. Baniassad, Gail C. Murphy, Christa Schwanninger, and Michael Kircher. Managing crosscutting concerns during software evolution tasks: an inquisitive study. In AOSD ’02: Proceedings of the 1st international conference on Aspect-oriented software development, pages 120–126. ACM Press, 2002. 44. Yvonne Coady and Gregor Kiczales. Back to the future: a retroactive study of aspect evolution in operating system code. In AOSD ’03: Proceedings of the 2nd international conference on Aspect-oriented software development, pages 50–59. ACM Press, 2003. 45. Jim Waldo, Samuel C. Kendall, Ann Wollrath, and Geoff Wyant. A Note on Distributed Computing. Technical Report TR-94-29, Sun Microsystems Laboratories, Inc., November 1994. 46. Sérgio Soares and Paulo Borba. PaDA: A Pattern for Distribution Aspects. In Second Latin American Conference on Pattern Languages of Programming — SugarLoafPLoP 2002., pages 87–99, Itaipava, Rio de Janeiro, Brazil, August 2002. Published in University of São Paulo Magazine — ICMC. c 2000 John Wiley & Sons, Ltd. Copyright  Prepared using speauth.cls Softw. Pract. Exper. 2000; 00:1–6