Lessons learned building tool support for AspectJ - Semantic Scholar

5 downloads 13705 Views 405KB Size Report
aspect-oriented plugins for Java development environments we observed structure model and ..... support a wide range of Aspect-Oriented Software Development (AOSD) tools. The latest .... Each IDE defines a custom format and conventions for describing a project's resources .... ACM, Denver, Colorado (1999). 8. Kiczales ...
Lessons learned building tool support for AspectJ Mik Kersten University of British Columbia 201-2366 Main Mall, Vancouver, BC V6T 1Z4 Canada [email protected]

Abstract. AspectJ is an aspect-oriented language extension to Java™. A critical part of the AspectJ technology is the development environment support that makes it possible for industry developers to use AspectJ without giving up the tool support they are accustomed to. Providing developers with aspectoriented views of their programs facilitated the understanding of AspectJ’s crosscutting structure, similar to the way object-oriented tools facilitate working with inheritance and encapsulation structure. In the process of implementing aspect-oriented plugins for Java development environments we observed structure model and view limitations that make extending existing platforms challenging. This paper reports on the technical lessons we learned from extending object-oriented development environments with tool support that makes the crosscutting structure of a system explicit.

1. Overview Object-oriented programming (OOP) tool support makes the inheritance and encapsulation structure of a system explicit. Many programmers rely on query facilities for reporting method overriders, tree views of the system’s type hierarchy, or debugger mappings from exception traces to offending source lines. AspectJ [8] is an Aspect-Oriented Programming (AOP) [9] extension to Java [5] that provides the programmer with language support for modularizing crosscutting. This paper reports on our experiences building tool support that makes crosscutting structure explicit. The AspectJ integrated development environment (IDE) plugins have been crucial to the adoption of the AspectJ language for both practical and pedagogical reasons. They allow programmers to use AspectJ without forcing them to give up the other development tools they use. The plugins and support tools make AOP structure explicit, similar to how the current Java IDEs make OOP structure explicit. But we struggled to integrate support for crosscutting without giving misconceptions about the language. We have yet to succeeded at showing the dynamic properties of crosscutting. The tools are still not integrated with advanced IDE features that work for Java code. Subtle but fundamental assumptions in the object-oriented IDEs’ structure models and views made it difficult to implement AOP extensions. This is a discussion of the technical issues that we observed while building facilities for editing, compiling, navigating, documenting, and debugging aspect-oriented

2

Mik Kersten

programs. It is intended for those interested in providing extensions to OOP and making them accessible with development environment support. The next section discusses the tools that we built. The following sections discuss why we built them this way, and what we learned in the process.

2. The first AOP tools To ensure that the AspectJ language and development tools were usable on real-world Java systems, the AspectJ project was structured to incorporate user feedback. Our primary means of gathering user input were mailing lists, a bug database, and close interaction with users at AspectJ conference sessions. The first releases of the command line compiler resulted in numerous requests for build and development environment integration. Users wanted the ability to invoke the AspectJ compiler from within their IDE [7]. However, such support would have been minimal inside an environment that provides rich facilities for navigating and editing object-oriented structure. We set out to provide similar facilities for working with crosscutting structure. The first step we took was to make AOP structure explicit with annotations and links in Emacs and Javadoc-style [4] documentation generated with the ajdoc tool. We met the increasing user demand with plugins for the JBuilder, JDEE, NetBeans, and Eclipse IDEs. For developers not using the supported IDEs we provided a lightweight standalone tool, the AspectJ Browser and an Ant task. Figure 1 summarizes the tool support we released as the language matured and demand grew.

Fig. 1. Timeline and downloads of AspectJ tools (details in Appendix B)

Lessons learned building tool support for AspectJ

3

2.1 AspectJ AOP enables the modular implementation of crosscutting concerns. Crosscutting concerns are inherent in complex systems, and impossible to capture cleanly with OOP. AspectJ is an extension to Java that provides the programmer with language mechanisms that explicitly capture crosscutting structure. The result is similar to the benefits of OOP modularity for object encapsulation and inheritance: easier to maintain code with greater potential for reuse. Consider the failure handling policy aspect in Figure 2. The first three lines of code declare that after a WSIFException is thrown in any public method within the wsif package the exception will be handled by the body of the advice. The aspect defines a pointcut as the set of join points corresponding to every call to a public method. In AspectJ’s pointcuts and advice mechanism, join points are key points in the dynamic execution of the program [10]. These include method and construction execution, class initialization, and field accessors. The FailurePolicyEnforcement aspect uses after advice to define what action should be taken under these points in the execution. Advice execution can also be specified to happen before and around a join point. Aspects as simple as this one have been demonstrated to be powerful enough to capture crosscutting concerns such as first failure data capture policies in applications servers [1]. aspect FailurePolicyEnforcement { pointcut publicInterface(): call(public * org.apache.wsif..*(..)); after() throwing(WSIFException w): publicInterface() { // code to handle w using FailureMonitor... } }

Fig. 2. Failure handling policy aspect

2.2 Crosscutting structure views The most common objection that arose at presentations of the language suggested that AspectJ’s ability to introduce behavior invoked implicitly would compromise program understandability. For example, the code surrounding a method or accessible by browsing references does not indicate what advice might execute before the method does. The tools make this structure clear by indicating which advice will affect that method. For example, the file structure presents a tree of the declarations. Crosscutting links in the file structure view make it possible to navigate from a method to the advice affecting it (Figure 3-A). Since not all users refer to the file structure view, the links are also exposed as inline annotations (Figure 3-B). The crosscutting structure links are also relevant to code documentation. The ajdoc tool makes generated Javadoc-style documentation for AspectJ members, and surface crosscutting structure relationships as hyperlinks (Figure 3-C).

4

Mik Kersten

Fig. 3. Crosscutting structure relationships in the file structure view (A), inline editor annotations (B) and ajdoc-generated documentation (C) AspectJ’s inter-type declarations, an open class mechanism, can affect the type structure of a system. For example, a class may have new members declared on it. This structure is made explicit in the file structure view as well (Figure 4). As with advice elements, this involves showing program elements corresponding to join points below the signature level (e.g. exception handler sites). Unlike Java member declarations, advice and some inter-type declarations (declare error/warning) can not be invoked explicitly. As such these declarations are not named. In the structure views they attempt to identify themselves uniquely by including all relevant properties (such as parameter types) as well as a named pointcut if available (Figure 4).

Fig. 4. AspectJ declarations displayed in the file structure view

AspectJ has rich pointcut and advice mechanisms. When beginners start prototyping aspects their first challenge is to understand the places that the aspect affects. Similar to the back-links, advised join point shadows show up in the structure

Lessons learned building tool support for AspectJ

5

view (Figure 4). The effects of changing a pointcut can be inspected in this view. However, some of the most affective pointcuts are property based (e.g. the pointcut in Figure 1) and crosscut very large portions of the system. For this tree views are less convenient, since scrolling through thousands of nodes makes maintaining context difficult. The aspect visualizer view addresses global crosscutting by showing advice relationships in a zoomed-out SeeSoft source line-based view [3] inspired by the Aspect Browser [6].

Fig. 5. Aspect Visualizer showing the effects of an aspect on a package

2.3 Build support Since we extended Java, the AspectJ language and compiler needed to be compatible with Java. All legal Java programs are legal AspectJ programs, and the bytecodes produced by the compiler ajc can run on any Java 2 and later VM. Aspects can be declared in both “.java” and “.aj” source files. Pointcuts can be declared in classes as well as aspects, and inner aspects can be declared in classes. As a result, crosscutting modularity is as primary and visible to the AspectJ programmer as object-oriented modularity, and the tools’ role is to present a consistent view of both. For supporting builds outside of the IDEs (e.g. running on automated build machines) we provide an Ant task. Build integration allows projects within the IDE to be built with the AspectJ compiler, according to the dependencies and properties specified by the project configuration. In addition to specifying an integral part of a system’s architecture, aspects can also be used to add auxiliary functionality such as monitoring, logging, and

6

Mik Kersten

debugging. These aspects need support for unplugging from the system in order to support development time-specific concerns that are not shipped, as well as multiple system configurations. We provide a build configuration specification file format (“.lst”). Within the IDE configurations can be edited based on project properties and selected for compilation.

Fig. 6. Build configuration support and graphical editor.

3. Observations on modeling and displaying crosscutting structure The purpose of the AspectJ IDE plugins is to make it possible for developers to work with crosscutting structure. Existing OO views did not expose this structure, and needed to be extended. The program structure model underlying the views needed to represent aspects as well as objects. Inheritance and encapsulation have clear representations in static structure views. But the core of the AspectJ structure model is the dynamic join points—key points in the dynamic call graph of the running application. We struggled with ways to model and display an accurate aspectoriented view of the program. In this section, we report on several lessons we learned trying to model and display crosscutting structure. 3.1 Surfacing crosscutting in views made aspect-oriented programs easiter to understand User feedback from tutorials, workshops, and our mailing lists has indicated that the single most effective role that the tools have played is to expose the crosscutting structure relationships of the program. Aspects provide a powerful means of expressing behavior that crosscuts large parts of the system. This structure can not be inferred easily from the code at the affected places. Views like the gutter annotations (Figure 3) address this by making the crosscutting structure explicit. Having the language so closely coupled to tool support is a related concern some raised when introduced to AspectJ. However, we have not heard feedback that this deterred adoption. The AspectJ structure views surface relationships for advice (e.g. pointcuts specifying calls, executions, exception handlers), inter-type declarations (introduced fields & methods), and declares (e.g. declare error/warning).

Lessons learned building tool support for AspectJ

7

3.2 Object-oriented views and navigation did not scale well to showing crosscutting structure Object-oriented views serve well for showing hierarchies and navigating references. Aspects are about non-hierarchical structure. The presence of significant aspectoriented structure in large systems overloads the tree views with relationships and links. The editor gutter annotations (Figure 3-B) suffer from a related problem. The gutter is narrow and only capable of displaying a single icon per source line. If additional annotations are present (e.g. breakpoint indicators) they obscure the advice. In addition, crosscutting relationships needed to be made explicit in the tree views (Figure 3-A). Advice affecting a method could not just appear as a child node of the method, since it is related by crosscutting and not by containment. This resulted in additional indirection nodes (e.g. “advised by”) that significantly add to the complexity of the tree view by introducing an extra level to the tree. To reduce the visual complexity we attempted to make the relationship nodes easily discernible by making their label italicized, so that it was clear that they did not correspond to a structural element. Their icon was an arrow indicating the direction of the relationship. The link nodes were displayed to look like hyperlinks to make it clear that they did not correspond to declarations local to that place in the tree, but instead to links in other declarations. Clicking the links causes the editor to navigate to the selected declaration and select it in the current tree view (i.e. to resolve the link). Aspects are inherently good at expressing global effects on a system. However, object-oriented views tend to focus on more local structure, and do not help present the big picture of the crosscutting. For example, changing a single pointcut can result in every public method of the system being advised (e.g. pointcut in Figure 2). The AspectJ tools need to make the effects of this global structure clear. The Aspect Visualizer (Figure 5) presents crosscutting at a file or package level of granularity. It allows the programmer to see the extent to which aspects affect the system. The AspectJ Browser attempts to show the global effects of crosscutting with a tree view. It presents a tree of named pointcuts, with other pointcuts or advice that use them as children, and finally the affected join points as leaves (Figure 7). It allows the programmer to see all of the crosscutting in the system, and shows the effects of refactoring a pointcut without needing to navigate to other pointcuts or advice. We also had to provide facilities for helping the programmer maintain context when navigating crosscutting. When updating the body of an advice, the behavior of each of the join points it affects can be of interest. IDEs make it easy to lose context by presenting only the structure relevant to the current focus of the editor. To offset this we first introduced navigation history. Our tree links acted as hyperlinks and navigation could be stepped back and forward (most IDEs now support a similar history feature). Navigation history helped, but it did not solve the main problem of needing to see both aspect and affected join point context at the same time. The AspectJ Browser does this by maintaining a structure view focused on the crosscutting while allowing a second structure view to be synchronized with the editor (Figure 7). A prototype browser extension went one step further by allowing multiple places in the code to be exposed in parallel editor panes.

8

Mik Kersten

Fig. 7. AspectJ Browser showing context of advice and affected method simultaneously

3.3 The tools taught both concepts of and misconceptions about the language We had a compelling idea of using Fluid Document technology [2] to selectively expose the lines of advice code that would execute before or after a method (Figure 8). But this gave the incorrect impression that AspectJ used preprocessor semantics and inserted code—advice does not execute in the same scope as the method. As a result we did not release this tool, although the idea could have potential if combined with showing dynamic context. There is a related caveat with the Aspect Visualizer view (Figure 5) which encourages the developer to think in terms of source lines instead of dynamic points in the execution.

Lessons learned building tool support for AspectJ

9

Fig. 8. Fluid inlining of an advice body before a method body

Making it clear that AspectJ is based on a dynamic model has been the key challenge of displaying crosscutting. Thinking in terms of static transformations of source code discourages programmers from learning how to understand and manipulate crosscutting as a principal structure of the system. The preprocessor misconception prevents programmers from attaining an intuitive understanding of AspectJ’s semantics. For example, it is awkward to think of join point parameter binding in terms of method parameters. We worked hard to ensure that the crosscutting views discouraged notions of inserting code and accurately portrayed AspectJ’s semantics. 3.4 We did not figure out how to represent the dynamic properties of crosscutting The current tools give the developer no assistance for determining what dynamic conditions will affect the potential execution of advice at a join point shadow (e.g. by showing the call graph under which the advice would execute). Multiple advice can apply to a single join point. Their execution is specified by ordering rules, or explicitly declared by the programmer. The structure views do not surface the ordering semantics. There was no obvious way to extend the object-oriented views to show this information, and it has remained an open problem. Part of problem stems from the fact that the IDEs’ views show static structure. The nodes populating structure views represent static signatures. But join points are dynamic points in the call graph of a running application. The easiest way to overlay the aspect-oriented structure is by doing what the compiler does, and translating it to the corresponding object-oriented program. We call the projection of the dynamic join point model onto the static structure of the program the join point shadow. Using join point shadows we could surface relationships that map to more than one source location (e.g. both method signatures and call sites are of interest for advice on calls). Another good thing about shadows is that they provide a simple way to surface all of the places that advice might execute. But while much pointcut matching is static, which is why AspectJ is efficient, some pointcut matching has residual runtime tests (e.g. a pointcut can constrain the join points to only those within the control flow of a particular method execution). Unfortunately the programmer is left to infer what

10

Mik Kersten

runtime conditions need to be true for the advice to execute. The crosscutting structure views should be more specific about indicating whether or not advice will execute, and provide context indicating what runtime tests and conditions will affect the execution of the advice (e.g. by showing the call graph for the control flow constraining a pointcut). Exposing the dynamic properties of crosscutting would involve some redesign of the way we surface static structure. 3.5 A crosscutting structure model was key, but over-generalizing it was a mistake From the beginning of the project using agile methods helped the tools evolve gracefully with the changing language implementation and IDE platforms. The tools framework grew out of a single IDE implementation, to one generic enough for 2 Swing-based IDEs, and finally to a GUI-independent framework when we needed to support Eclipse’s SWT. The Abstract Structure Model (ASM) is at the core of the AspectJ tools framework. The ASM represents the crosscutting, inheritance, and referential structure of AspectJ programs. Framework clients expose the structure of the model in task-specific views. The lifecycle of the ASM is longer than that of the compiler’s AST in order to support structure with errors and to provide the framework with multiple live views. The model is kept in memory since the crosscutting structure of the entire system must be presented to the user without invoking a search. Its footprint must be small enough to be kept for programs of up to tens of thousands of classes. Firgure 9 demonstrates how clients can extend the ASM directly (e.g. ajdoc). IDE plugins use the event and abstract user interface facilities of the framework. Java Swing clients (JBuilder, NetBeans, AspectJ Browser) use the Swing UI layer of the framework and extend it with look-and-feel specific to the target platform (icons, actions, and view layout). The Eclipse plugin uses the abstract UI and event layer of the framework.

Fig. 9. AspectJ tools framework and clients

Lessons learned building tool support for AspectJ

11

The ASM started out as a string-based map of correspondences between declarations that represented how advice affected signatures corresponding to method execution join points. To incorporate structural relationships for inter-type declarations and other kinds of join point shadows we built a generic data structure composed of program elements and associations relating them. It was used for constructing containment, inheritance, referential and crosscutting views. It didn’t contain a dominant decomposition (the containment hierarchy in most IDEs) and didn’t require searches to build views (contrast with Eclipse long searches to build an inheritance tree). It also captured additional associations such as the @see links from Javadoc. It was intended to be extensible with additional structural relationships such as UML-specific associations or relationships between program elements and structure declared in external resources (e.g. deployment descriptors in J2EE). At one point we considered making it represent crosscutting in a way generic enough to support a wide range of Aspect-Oriented Software Development (AOSD) tools. The latest ASM implementation is, once again, a string-handle-based mapping between relationships in a containment hierarchy. The more flexible and extensible generic data structure attempted to solve interesting problems, but was not practical for solving the core problem of supporting high-quality IDE integration. The lack of a dominant hierarchy resulted in multiple graphs representing the entire program structure and causing an excessive memory footprint when used with large systems. In addition, to achieve a deep integration with the Eclipse IDE the update of the structure model needed to be eager, and to include elements that existed in source code but were not contained in the last build. The eager update also enables compatibility with very large systems by avoiding the necessity to store the entire model in memory. In order to make the ASM support this incremental update and improve performance we concretized it and returned to using string handles as references to program elements. The relationships are persisted in memory, but as a much leaner map and easier to maintain map between string handles corresponding to program elements.

4. Observations on extending object-oriented IDEs Modern IDEs provide the developer with great support for editing object-oriented programs. We needed to extend the existing functionality in a consistent and elegant way in order to support AspectJ without getting in the way of the Java tooling. We struggled with extensibility limitations that result from AOP breaking the core assumptions made by object-oriented IDEs. In the process we learned about desirable extensibility properties of IDE platforms and developed strategies for providing a clean integration of AOP support. The extension features we considered are summarized in Appendix A.

12

Mik Kersten

4.1 Overriding the file extension goes against the extensibility model is but key to consistency AspectJ is intended to be a seamless integration of AOP & Java. The file extension for AspectJ sources seems like a seemingly small detail, but turns out to have significant implication on the degree to which the integration is seamless. One of the core goals of the AspectJ language is to make crosscutting mechanisms available as a part of the base language. This is in contrast to the reflective and external language (e.g. AspectWerkz) approaches in which crosscutting is declared outside of the main language. AspectJ’s approach benefits the programmer by providing consistent support for both objects and aspects. However, current IDEs only allow for language extensibility outside of the core program text (e.g. in comments, metadata tags, strings, and new file extensions). In any file named “.java” the tools expect a language that conforms to the Java language specification. The easiest way out is to only allow AspectJ code separate resources (e.g. “.aj” files with the current syntax or “.xaj” with XML syntax). But this would have only side-stepped the problem. For example, consider an inter-type declaration made in a separate resource. The tool support could try to make the resulting structure clear, but there will still be a confusing and awkward disconnect between the external code for the inter-type declarations and the pure Java declarations. A reference to an inter-type declaration in a “.java” file would break an open parser. As a result, the AspectJ language and tool support makes crosscutting as a primary part of the system’s architecture and allows aspect declarations in “.java” files. There is an ongoing cost to this approach. The IDE plugins need to employ sophisticated mechanisms for making the AspectJ language behavior match Java behavior transparently. The AspectJ 1.1 tools fall short of providing access to advanced features such as refactoring support. AOP is a profound change to language semantics. Fixing existing technology based on OO to work with AOP is difficult because the data structures are fundamentally different. 4.2 No IDE was inherently extensible beyond OOP This may seem at odds with the fact that we built IDE plugins. But the AspectJ plugins do not extend the OO structure model of the IDEs. They replace it. The AspectJ structure views are not extended Java views, they are imitations of their Java counterparts. When contrasted with the efforts behind Java tooling the limited resources of a research project make this game of catch-up a slippery slope. Take for example the Eclipse IDE, which offers no facilities for extending its Java model with new semantics. The structure model is the foundation of features such as eager parsing, code assist, and refactoring. Both the core Java tool support and other extensions (e.g. Rational XDE) contain explicit bindings to the Java language, and consider language extensions to be programmer errors. Taking the external-language approach is less intrusive to the other Java tooling. But this only delays the problem by pushing the aspect-oriented structure out of the way. The IDEs’ structure models needs to be made extensible to other program structures such as crosscutting. We are now exploring means of extending Eclipse’s model.

Lessons learned building tool support for AspectJ

13

4.3 Access to IDE sources, a plugin component model, and self-hosting on open APIs helped Our first IDE plugin extended the Microsoft Visual J++ 6 IDE. Its extensibility APIs are similar to those currently available in VisualStudio.NET. However, the IDE was closed-source and not self-hosted on the APIs (i.e. the internal implementation was not based on them). It proved unfeasible to extend beyond the limited use cases that the tool builders had in mind. The release of the pure-Java-based JBuilder 3.5 was promising. We released the first IDE plugin on JBuilder’s much broader OpenTool APIs. The breadth and stability of these APIs helped bring AspectJ into the hands of real developers [11]. But they were not designed for incorporating new modularity ideas and language extensions. JBuilder is not open source, and was missing critical extension points. For example, to make the file structure view work we had to walk the Swing component tree, and reversibly overwrite the Java view with ours. Based on the experience of trying to extend limited closed-source APIs we decided to solicit community contribution instead of building plugins for IntelliJ’s IDEA, Symantec’s VisualCafe, and IBM’s VisualAge. The NetBeans release was encouraging since the IDE was open source. However, due to an overly general architecture and not enough focus on extensible Java tooling it was more difficult to build the NetBeans plugin than to build the JBuilder one. Eclipse combined openness, broad APIs, a much deeper self-hosting on those APIs, a more complete plugin component model, and more features for viewing and manipulating OO structure. In addition, Eclipse’s open source compiler provided us with more opportunity for a deep integration. However, the advanced tool features of Eclipse are a double-edged sword for language extensions. They raise the feature bar (e.g. Eclipse users expect eager parsing and refactoring) and are inherently nonextensible. Open sources helped because the IDE documentation invariably lagged the implementation, and did not describe the extensibility use cases that we were interested in. The ability to copy existing code to learn how a core part of the IDE worked proved invaluable for figuring out how to extend it in a way that was not originally planned for. 4.4 Supporting multiple IDEs and enterprise versions was time consuming and benefited from community contribution We have released support for 7 versions of JBuilder, 5 versions of NetBeans, and 4 versions of Eclipse. The porting of plugins to newly released APIs has been straightforward. JBuilder’s have evolved very slowly, NetBeans’ slowly enough, while Eclipse’s evolved more quickly but provided stability by controlling change in APIs marked public. Our main problem has been maintaining a single release that is backwards compatible with older releases. Users want the latest bug fixes even if they are stuck on an older version, and many of our users expected immediate support for new IDE releases. Supporting both the latest and older versions imposed a drag on evolution, was time consuming, and involved marginal solutions such as checking the IDE version at runtime and invoking the appropriate API call reflectively.

14

Mik Kersten

Crosscutting is particularly apparent in large enterprise applications (e.g. those using J2EE). To enable use by enterprise developers we needed to support the enterprise versions of the IDEs (JBuilder Enterprise Edition, Sun ONE Studio built on NetBeans, and IBM Websphere built on Eclipse). In theory, this should not have required extra work since all plugins making correct use of the extensibility model should interoperate with the extended enterprise IDEs. However, testing and updates specific to the enterprise editions were necessary to ensure compatibility. This is in part because enterprise project configurations are different and tend to involve more kinds of resources, and because the enterprise editions can depend on core platform features that are not used by the standard edition. Unlike the early adopters who always downloaded the latest free standard version of their IDE, the enterprise developers were often stuck on a version until their organization decided to upgrade. This was another reason why we needed to maintain backwards compatibility. Enterprise users also saw a disproportionate amount of bugs because we did not use their tools internally. Due to the broad range of tools that we supported, we could not always depend on ourselves to accurately represent our users. To address this we engaged willing users in the process of improving the tool integration. This was most obvious with the enterprise versions, but low download numbers for the NetBeans were indicative of a similar problem. None of us used NetBeans for development, and as such we did not have an intuitive sense for the developer’s workflow in that IDE. Close dialogs with NetBeans users helped us understand the expectations they had of the integration. When the quality evolved above an acceptable bar the plugin saw more use, and users submitted several patches to further improve the support. 4.5 The need to simulate project and IDE state made testing difficult Automated testing of the IDE tools is an ongoing challenge, and we still rely on manual inspection. The main thing that helped with testing the core framework was the introduction of a test harness based on the public framework APIs. The harness is a client that implements all of the framework’s extension points by simulating the presence of an IDE. For example, it mocks up the existence of projects, source files, build parameters and structure views. It has been very helpful for building unit tests on top of, and for turning bug reports into regression test cases. Since it does not require an instance of any IDE to be running, it also provided a clean separation of the testing responsibility between the core tool framework and the IDE plugin. Each IDE defines a custom format and conventions for describing a project’s resources, dependencies, and other properties. A significant portion of IDE support bugs were related to project configurations. Without a common and open project specification format it was difficult to replicate bug reports, and we often relied on asking for detailed, and invariably inaccurate, description of the project setup that triggered a particular bug. The lack of a format the description of a project also made it difficult to create tests of project configurations. In addition, each IDE imposed its own idiosyncratic project constraints and required a separate project configuration implementation. Efforts such as Apache’s Maven and JSR-198 could address this problem.

Lessons learned building tool support for AspectJ

15

4.6 Clean integration was more important than new views and features Our bug report database indicates that the most important part of clean integration is not getting in the way of existing Java tool support. New users curious to try AspectJ are not willing to continue using it if they have to sacrifice their existing Java support. Before we got any of the plugins to a satisfactory quality level we did not see any reports. Where at first we thought this was a good sign subsequent reports proved otherwise. We came to assume that the lack of bug reports indicated lack of use. To further improve integration we set a policy of zero-configuration after install. This was challenging given the amount of user-specified customization exposed by the IDEs. In addition, we had to provide IDE-specific UIs for toggling whether or not AspectJ was enabled for a particular project. Effort spent on improving integration was at the expense of adding features. But it was critical for getting feedback from use on real systems. We started by exposing AspectJ functionality as visibly as possible (e.g. there was an AspectJ menu that provided build commands). As our plugins improved access to AspectJ features was inlined with the corresponding Java functionality. But extending the look-and-feel of the Java functionality was challenging due to a lack of consistency both across and within the IDE. For example, we needed icons that clearly represented the new AspectJ declarations. However, the IDEs didn’t use consistent iconography or coloring schemes. We started by providing our own icon scheme, but have moved to creating icons specific to each IDE. When possible extending existing views worked better than adding new ones. Placing the crosscutting information inline with the file structure view and editor was effective because programmers are familiar with those views. The new structure is placed inline with their editing and navigation, and is passively present. On the other hand, IDE integration of the AspectJ Browser’s global crosscutting view involved a new UI, took valuable screen real estate, and did not receive as much positive feedback from developers. Adding new views forces the programmer to mentally overlap yet another pane in order to understand the structure affecting the current code of interest, and to be constantly aware of where to find a particular facet of the program structure. 4.7 Extending existing debuggers is easier than implementing a new one We released a JPDA-based debugger with a command-line and GUI interface. However, we were not able to get the quality and features of the debugger up to the expectation set by debuggers in existing IDEs. We discontinued the debugger after 1.0. The Java Servlet-support-related improvements to debuggers’ understanding of source line mappings have made it possible for us to enable AspectJ source line mappings by means of bytecode attributes alone. The result is that the core debugger functionality works for AspectJ sources with standard debuggers, with the caveat of exposing the implementation of the language instead of the language semantics (e.g. extra stack frames and generated names for advice). But it allowed us to consider the additional functionality (e.g. hiding extra stack frames or setting breakpoints on join points) as an additional user interface layer over the existing debugger functionality.

16

Mik Kersten

User feedback on debugger support demonstrated the need to preserve both views. The standard Java debugger views turns out to be useful for the cases where seeing exactly what executes is more important than seeing clean AspectJ language abstractions (e.g. in resource-constrained J2ME environments). Extending the debuggers turns out to be easier than extending the IDE’s core structure model. This is in part due to the extra genericity offered by debugging support for other languages (JSR-45). The main difference is that in the debugger it is more natural to transform the executing state into AspectJ abstractions and back again. This is analogous to what the compiler does when it produces the Java bytecodes in the first place. In contrast, crosscutting needs to be represented directly in the IDE’s core structure model to support operations like aspect-oriented refactoring.

5. Summary We have made significant progress in providing tool support that exposes the aspectoriented structure of programs by extending object-oriented IDEs. Some of the lessons we learned should generalize to other attempts at extending object-oriented tools to surface crosscutting structure, particularly when real-world use is relevant to validation. We learned how to expose crosscutting structure by extending the limited objectoriented structure views, and that providing a global perspective on the effects of crosscutting helps. Whereas we succeeded at showing the static mapping of join points to structure views, we did not manage to expose the dynamic properties of crosscutting. In the process we learned that tools have the ability to both teach the language and to encourage misconceptions about it. The most difficult problems we encountered resulted from the lack of extensibility beyond OOP that is an inherent limitation of the tool platforms. Crosscutting structure is incompatible with the program structure models of the object-oriented IDEs. But we are continuing to improve the breadth and integration of the AspectJ tool support, and in the process hope to contribute to making object-oriented tool platforms more extensible.

6. Acknowledgments Gail Murphy and Gregor Kiczales were very helpful in selecting and distilling the lessons learned. The rest AspectJ and AJDT teams made the tool support possible, and currently includes Adrian Colyer, Andrew Clement, Erik Hilsdale, Jim Hugunin, Julie Waterhouse Park and Wes Isberg. There would be no lessons without the AspectJ user community who continues to provide the invaluable feedback that will continue teaching how to build better AOP tools.

Lessons learned building tool support for AspectJ

17

7. References 1. Colyer, A., Clement, A., Bodkin R., Hugunin, J.: Practitioners report: Using AspectJ for component integration in middleware. In: Proceedings of the Conference on Object-Oriented Programming Systems, Languages, and Applications (OOPSLA). ACM, Anaheim, California (2003) 2. Chang, B.W., Mackinlay, J.D., Zellweger, P.T. and Igarashi, T.: A Negotiation Architecture for Fluid Documents. In: Proceedings of the ACM Symposium on User Interface Software and Technology, pp. 123-132 (1998) 3. Eick, S.G., Steffen, J.L., Sumner, E.E.: Seesoft - A Tool For Visualizing Line Oriented Software Statistics. In IEEE Trans. on Software Engineering, Vol. 18, N. 11 (1992) 4. Friendly, L.: Design of Javadoc. In: The Design of Distributed Hyperlinked Programming Documentation (IWHD). Springer-Verlag, Montpellier, France (1995) 5. Gosling, J., Joy, B., and Steele, G.: The Java Language Specification. AddisonWesley, Reading, Maschusetts (1996) 6. Griswold, W.G., Kato, Y. and Yuan, J.J.: Aspect browser: Tool support for managing dispersed aspects. In First Workshop on Multi-Dimensional Separation of Concerns in Object-oriented Systems, OOPSLA (1999) 7. Kersten, M., Murphy, G.: Atlas: A Case Study in Building a Web-Based Learning Environment Using Aspect-Oriented Programming. In: Proceedings of the Conference on Object-Oriented Programming Systems, Languages, and Applications (OOPSLA). ACM, Denver, Colorado (1999) 8. Kiczales, G., et al.: An Overview of AspectJ. In: Proceedings of the European Conference on Object-Oriented Programming (ECOOP). Springer-Verlag, Finland (2001) 9. Kiczales, G., et al.: Aspect-Oriented Programming. In: Proceedings of the European Conference on Object-Oriented Programming (ECOOP). SpringerVerlag, Finland (1997) 10.Masuhara, H. and Kiczales, G.: Modeling Crosscutting in Aspect-Oriented Mechanisms. In: Proceedings of the European Conference on Object-Oriented Programming (ECOOP). Springer-Verlag, Spain (2002) 11.Price, R.: Real-world AOP Tool Simplifies OO Development. Java Report, September Issue (2001)

18

Mik Kersten

Appendix A: plugin extension features The following summarizes the IDE extension features that are relevant to the AspectJ plugins. Features supported available in AspectJ 1.1 are in parentheses. Task Building

Extension Compiler

Editing

Build configuration Library support Ant task Text editor

Browsing

Structured editing Configuration editing Documentation File structure views Global views Search

Debugging Presentation

Extensibility

Execution Runtime views Invocation Graphical notations Dialogs Structure extension

Features Invocation on project files according to the build options Class and aspect inclusion selection, active configuration selection, portable file format Input and output library setting for builds Compiler invocation Keyword highlighting, inline structure annotations, (code assist) Resource creation, (test case creation), (refactoring), (design pattern support) Graphical editing of build configurations Generation of HTML documentation Relationship navigation, filtering of declarations and relationships, (eager parsing) Sourceline and file-based view, crosscutting browser, (UML views) Query support for new declarations and relationships Runtime integration, source line mapping, (language-specific breakpoints) Stack translation, thread tree structure views Mechanism for enabling and disabling Icons and formatting for declarations, relationships Plugin preferences, project preferences, error reporting Public API, (model interchange format)

Lessons learned building tool support for AspectJ

19

Appendix B: tool support releases 1999-2003 The following table summarizes the public releases of AspectJ tool support. Some of the tools released have not seen significant contribution beyond AspectJ 1.0, as is evident from the timeline in Figure 1. The download numbers in Figure 1 are of binary tools containing a compiler distribution (eclipse.org download numbers are not available). Ver. 0.3 0.4 0.5 0.6 0.7

0.8

1.0

1.1

Date May 1999 beta 1 Aug. 1999 beta 1 Jan. 2000 beta 1 Mar. 2000 beta 1 Aug. 2000 beta 5 Sep. 2000 beta 6 Oct. 2000 beta 7 Feb. 2001 beta 12 Mar. 2001 beta 1 Apr. 2001 beta 3 Aug. 2001 alpha 1 Nov. 2001 1.0.0 Feb. 2002 1.0.2 Apr. 2002 1.0.4 Jun. 2002 1.0.5 Dec. 2002 beta 2 Jun 2003 1.1.0 Sep. 2003 1.1.1

Details Java-based compiler generates source code, bytecode via javac Better Java language compatability Emacs/JDE support and ajdoc released Static type system more closely matches Java JBuilder plugin released , compiler and core tools made available under an Open Source License (MPL) Command-line debugger released, “privileged” modifier added Forte plugin & GUI debugger released, advice on field access points Build configuration support added to JBuilder plugin Ant task released, initializer join points, introduction on interfaces, static advice removed GUI debugger added to Forte plugin AspectJ Browser released, public AJDE APIs, “declares” added Context-preserving browser, annotations added to JBuilder plugin, “.aj” extension, compiler generated bytecodes Bytecode line mapping for debuggers, -Xlint option added, Eclipse plugin project started Open source contribution helps port support to NetBeans 3.3.1 Eclipse plugin released. Graphical configuration file editor and AspectJ Browser for JBuilder. NullIDE test suited added. Compiler porteded to JDT, first eclipse.org & sourceforge.net release Bytecode weaving into JARs, aspect libraries, incremental compilation Revised structure model, views, and APIs, improved scalability