diff options
Diffstat (limited to 'docs/progguide/gettingstarted.xml')
-rw-r--r-- | docs/progguide/gettingstarted.xml | 1310 |
1 files changed, 1310 insertions, 0 deletions
diff --git a/docs/progguide/gettingstarted.xml b/docs/progguide/gettingstarted.xml new file mode 100644 index 000000000..6429d017f --- /dev/null +++ b/docs/progguide/gettingstarted.xml @@ -0,0 +1,1310 @@ +<chapter id="starting" xreflabel="Getting Started with AspectJ"> + + <title>Getting Started with AspectJ</title> + + <sect1 id="starting-intro"> + <title>Introduction</title> + + <para> + Many software developers are attracted to the idea of aspect-oriented + programming (AOP) but unsure about how to begin using the + technology. They recognize the concept of crosscutting concerns, and + know that they have had problems with the implementation of such + concerns in the past. But there are many questions about how to adopt + AOP into the development process. Common questions include: + + <itemizedlist spacing="compact"> + <listitem> + <para>Can I use aspects in my existing code?</para> + </listitem> + + <listitem> + <para> + What kinds of benefits can I expect to get from using aspects? + </para> + </listitem> + + <listitem> + <para>How do I find aspects in my programs?</para> + </listitem> + + <listitem> + <para>How steep is the learning curve for AOP?</para> + </listitem> + + <listitem> + <para>What are the risks of using this new technology?</para> + </listitem> + + </itemizedlist> + </para> + + <para> + This chapter addresses these questions in the context of AspectJ: a + general-purpose aspect-oriented extension to Java. A series of + abridged examples illustrate the kinds of aspects programmers may + want to implement using AspectJ and the benefits associated with + doing so. Readers who would like to understand the examples in more + detail, or who want to learn how to program examples like these, can + find more complete examples and supporting material linked from the + AspectJ web site ( <ulink url="https://eclipse.org/aspectj" /> ). + </para> + + <para> + A significant risk in adopting any new technology is going too far + too fast. Concern about this risk causes many organizations to be + conservative about adopting new technology. To address this issue, + the examples in this chapter are grouped into three broad categories, + with aspects that are easier to adopt into existing development + projects coming earlier in this chapter. The next section, <xref + linkend="starting-aspectj"/>, we present the core of AspectJ's + features, and in <xref linkend="starting-development"/>, we present + aspects that facilitate tasks such as debugging, testing and + performance tuning of applications. And, in the section following, + <xref linkend="starting-production"/>, we present aspects that + implement crosscutting functionality common in Java applications. We + will defer discussing a third category of aspects, reusable aspects, + until <xref linkend="language"/>. + </para> + + <para> + These categories are informal, and this ordering is not the only way + to adopt AspectJ. Some developers may want to use a production aspect + right away. But our experience with current AspectJ users suggests + that this is one ordering that allows developers to get experience + with (and benefit from) AOP technology quickly, while also minimizing + risk. + </para> + </sect1> + + <sect1 id="starting-aspectj" xreflabel="Introduction to AspectJ"> + <title>Introduction to AspectJ</title> + + <para> + This section presents a brief introduction to the features of AspectJ + used later in this chapter. These features are at the core of the + language, but this is by no means a complete overview of AspectJ. + </para> + + <para> + The features are presented using a simple figure editor system. A + <classname>Figure</classname> consists of a number of + <classname>FigureElements</classname>, which can be either + <classname>Point</classname>s or <classname>Line</classname>s. The + <classname>Figure</classname> class provides factory services. There + is also a <classname>Display</classname>. Most example programs later + in this chapter are based on this system as well. + </para> + + <para> + <mediaobject> + <imageobject> + <imagedata fileref="figureUML.gif"/> + </imageobject> + <caption> + <para> + UML for the <literal>FigureEditor</literal> example + </para> + </caption> + </mediaobject> + </para> + + <para> + The motivation for AspectJ (and likewise for aspect-oriented + programming) is the realization that there are issues or concerns + that are not well captured by traditional programming + methodologies. Consider the problem of enforcing a security policy in + some application. By its nature, security cuts across many of the + natural units of modularity of the application. Moreover, the + security policy must be uniformly applied to any additions as the + application evolves. And the security policy that is being applied + might itself evolve. Capturing concerns like a security policy in a + disciplined way is difficult and error-prone in a traditional + programming language. + </para> + + <para> + Concerns like security cut across the natural units of + modularity. For object-oriented programming languages, the natural + unit of modularity is the class. But in object-oriented programming + languages, crosscutting concerns are not easily turned into classes + precisely because they cut across classes, and so these aren't + reusable, they can't be refined or inherited, they are spread through + out the program in an undisciplined way, in short, they are difficult + to work with. + </para> + + <para> + Aspect-oriented programming is a way of modularizing crosscutting + concerns much like object-oriented programming is a way of + modularizing common concerns. AspectJ is an implementation of + aspect-oriented programming for Java. + </para> + + <para> + AspectJ adds to Java just one new concept, a join point -- and that's + really just a name for an existing Java concept. It adds to Java + only a few new constructs: pointcuts, advice, inter-type declarations + and aspects. Pointcuts and advice dynamically affect program flow, + inter-type declarations statically affects a program's class + hierarchy, and aspects encapsulate these new constructs. + </para> + + <para> + A <emphasis>join point</emphasis> is a well-defined point in the + program flow. A <emphasis>pointcut</emphasis> picks out certain join + points and values at those points. A piece of + <emphasis>advice</emphasis> is code that is executed when a join + point is reached. These are the dynamic parts of AspectJ. + </para> + + <para> + AspectJ also has different kinds of <emphasis>inter-type + declarations</emphasis> that allow the programmer to modify a + program's static structure, namely, the members of its classes and + the relationship between classes. + </para> + + <para> + AspectJ's <emphasis>aspect</emphasis> are the unit of modularity for + crosscutting concerns. They behave somewhat like Java classes, but + may also include pointcuts, advice and inter-type declarations. + </para> + + <para> + In the sections immediately following, we are first going to look at + join points and how they compose into pointcuts. Then we will look at + advice, the code which is run when a pointcut is reached. We will see + how to combine pointcuts and advice into aspects, AspectJ's reusable, + inheritable unit of modularity. Lastly, we will look at how to use + inter-type declarations to deal with crosscutting concerns of a + program's class structure. + </para> + +<!-- ============================== --> + + <sect2 id="the-dynamic-join-point-model" xreflabel="the-dynamic-join-point-model"> + <title>The Dynamic Join Point Model</title> + + <para> + A critical element in the design of any aspect-oriented language is + the join point model. The join point model provides the common + frame of reference that makes it possible to define the dynamic + structure of crosscutting concerns. This chapter describes + AspectJ's dynamic join points, in which join points are certain + well-defined points in the execution of the program. + </para> + + <para> + AspectJ provides for many kinds of join points, but this chapter + discusses only one of them: method call join points. A method call + join point encompasses the actions of an object receiving a method + call. It includes all the actions that comprise a method call, + starting after all arguments are evaluated up to and including + return (either normally or by throwing an exception). + </para> + + <para> + Each method call at runtime is a different join point, even if it + comes from the same call expression in the program. Many other + join points may run while a method call join point is executing -- + all the join points that happen while executing the method body, + and in those methods called from the body. We say that these join + points execute in the <emphasis>dynamic context</emphasis> of the + original call join point. + </para> + </sect2> + +<!-- ============================== --> + + <sect2 id="pointcuts-starting" xreflabel="pointcuts-starting"> + <title>Pointcuts</title> + + <para> + In AspectJ, <emphasis>pointcuts</emphasis> pick out certain join + points in the program flow. For example, the pointcut + </para> + +<programlisting format="linespecific"> +call(void Point.setX(int)) +</programlisting> + + <para> + picks out each join point that is a call to a method that has the + signature <literal>void Point.setX(int)</literal> - that is, + <classname>Point</classname>'s void <function>setX</function> + method with a single <literal>int</literal> parameter. + </para> + + <para> + A pointcut can be built out of other pointcuts with and, or, and + not (spelled <literal>&&</literal>, <literal>||</literal>, + and <literal>!</literal>). For example: + </para> + +<programlisting format="linespecific"> +call(void Point.setX(int)) || +call(void Point.setY(int)) +</programlisting> + + <para> + picks out each join point that is either a call to + <function>setX</function> or a call to <function>setY</function>. + </para> + + <para> + Pointcuts can identify join points from many different types - + in other words, they can crosscut types. For example, + </para> + +<programlisting format="linespecific"> +call(void FigureElement.setXY(int,int)) || +call(void Point.setX(int)) || +call(void Point.setY(int)) || +call(void Line.setP1(Point)) || +call(void Line.setP2(Point)); +</programlisting> + + <para> + picks out each join point that is a call to one of five methods + (the first of which is an interface method, by the way). + </para> + + <para> + In our example system, this pointcut captures all the join points + when a <classname>FigureElement</classname> moves. While this is a + useful way to specify this crosscutting concern, it is a bit of a + mouthful. So AspectJ allows programmers to define their own named + pointcuts with the <literal>pointcut</literal> form. So the + following declares a new, named pointcut: + </para> + +<programlisting format="linespecific"> +pointcut move(): + call(void FigureElement.setXY(int,int)) || + call(void Point.setX(int)) || + call(void Point.setY(int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point)); +</programlisting> + + <para> + and whenever this definition is visible, the programmer can simply + use <literal>move()</literal> to capture this complicated + pointcut. + </para> + + <para> + The previous pointcuts are all based on explicit enumeration of a + set of method signatures. We sometimes call this + <emphasis>name-based</emphasis> crosscutting. AspectJ also + provides mechanisms that enable specifying a pointcut in terms of + properties of methods other than their exact name. We call this + <emphasis>property-based</emphasis> crosscutting. The simplest of + these involve using wildcards in certain fields of the method + signature. For example, the pointcut + </para> + +<programlisting format="linespecific"> +call(void Figure.make*(..)) +</programlisting> + + <para> + picks out each join point that's a call to a void method defined + on <classname>Figure</classname> whose the name begins with + "<literal>make</literal>" regardless of the method's parameters. + In our system, this picks out calls to the factory methods + <function>makePoint</function> and <function>makeLine</function>. + The pointcut + </para> + +<programlisting format="linespecific"> +call(public * Figure.* (..)) +</programlisting> + + <para> + picks out each call to <classname>Figure</classname>'s public + methods. + </para> + + <para> + But wildcards aren't the only properties AspectJ supports. + Another pointcut, <function>cflow</function>, identifies join + points based on whether they occur in the dynamic context of + other join points. So + </para> + +<programlisting format="linespecific"> +cflow(move()) +</programlisting> + + <para> + picks out each join point that occurs in the dynamic context of + the join points picked out by <literal>move()</literal>, our named + pointcut defined above. So this picks out each join points that + occurrs between when a move method is called and when it returns + (either normally or by throwing an exception). + </para> + + </sect2> + +<!-- ============================== --> + + <sect2 id="advice-starting" xreflabel="advice-starting"> + <title>Advice</title> + + <para> + So pointcuts pick out join points. But they don't + <emphasis>do</emphasis> anything apart from picking out join + points. To actually implement crosscutting behavior, we use + advice. Advice brings together a pointcut (to pick out join + points) and a body of code (to run at each of those join points). + </para> + + <para> + AspectJ has several different kinds of advice. <emphasis>Before + advice</emphasis> runs as a join point is reached, before the + program proceeds with the join point. For example, before advice + on a method call join point runs before the actual method starts + running, just after the arguments to the method call are evaluated. + </para> + +<programlisting><![CDATA[ +before(): move() { + System.out.println("about to move"); +} +]]></programlisting> + + <para> + <emphasis>After advice</emphasis> on a particular join point runs + after the program proceeds with that join point. For example, + after advice on a method call join point runs after the method body + has run, just before before control is returned to the caller. + Because Java programs can leave a join point 'normally' or by + throwing an exception, there are three kinds of after advice: + <literal>after returning</literal>, <literal>after + throwing</literal>, and plain <literal>after</literal> (which runs + after returning <emphasis>or</emphasis> throwing, like Java's + <literal>finally</literal>). + </para> + +<programlisting><![CDATA[ +after() returning: move() { + System.out.println("just successfully moved"); +} +]]></programlisting> + + <para> + <emphasis>Around advice</emphasis> on a join point runs as the join + point is reached, and has explicit control over whether the program + proceeds with the join point. Around advice is not discussed in + this section. + </para> + + <sect3> + <title>Exposing Context in Pointcuts</title> + + <para> + Pointcuts not only pick out join points, they can also expose + part of the execution context at their join points. Values + exposed by a pointcut can be used in the body of advice + declarations. + </para> + + <para> + An advice declaration has a parameter list (like a method) that + gives names to all the pieces of context that it uses. For + example, the after advice + </para> + +<programlisting><![CDATA[ +after(FigureElement fe, int x, int y) returning: + ...SomePointcut... { + ...SomeBody... +} +]]></programlisting> + + <para> + uses three pieces of exposed context, a + <literal>FigureElement</literal> named fe, and two + <literal>int</literal>s named x and y. + </para> + + <para> + The body of the advice uses the names just like method + parameters, so + </para> + +<programlisting><![CDATA[ +after(FigureElement fe, int x, int y) returning: + ...SomePointcut... { + System.out.println(fe + " moved to (" + x + ", " + y + ")"); +} +]]></programlisting> + + <para> + The advice's pointcut publishes the values for the advice's + arguments. The three primitive pointcuts + <literal>this</literal>, <literal>target</literal> and + <literal>args</literal> are used to publish these values. So now + we can write the complete piece of advice: + </para> + +<programlisting><![CDATA[ +after(FigureElement fe, int x, int y) returning: + call(void FigureElement.setXY(int, int)) + && target(fe) + && args(x, y) { + System.out.println(fe + " moved to (" + x + ", " + y + ")"); +} +]]></programlisting> + + <para> + The pointcut exposes three values from calls to + <function>setXY</function>: the target + <classname>FigureElement</classname> -- which it publishes as + <literal>fe</literal>, so it becomes the first argument to the + after advice -- and the two int arguments -- which it publishes + as <literal>x</literal> and <literal>y</literal>, so they become + the second and third argument to the after advice. + </para> + + <para> + So the advice prints the figure element + that was moved and its new <literal>x</literal> and + <literal>y</literal> coordinates after each + <classname>setXY</classname> method call. + </para> + + <para> + A named pointcut may have parameters like a piece of advice. + When the named pointcut is used (by advice, or in another named + pointcut), it publishes its context by name just like the + <literal>this</literal>, <literal>target</literal> and + <literal>args</literal> pointcut. So another way to write the + above advice is + </para> + +<programlisting><![CDATA[ +pointcut setXY(FigureElement fe, int x, int y): + call(void FigureElement.setXY(int, int)) + && target(fe) + && args(x, y); + +after(FigureElement fe, int x, int y) returning: setXY(fe, x, y) { + System.out.println(fe + " moved to (" + x + ", " + y + ")."); +} +]]></programlisting> + + </sect3> + </sect2> + +<!-- ============================== --> + + <sect2 id="inter-type-declarations" xreflabel="inter-type-declarations"> + <title>Inter-type declarations</title> + + <para> + Inter-type declarations in AspectJ are declarations that cut across + classes and their hierarchies. They may declare members that cut + across multiple classes, or change the inheritance relationship + between classes. Unlike advice, which operates primarily + dynamically, introduction operates statically, at compile-time. + </para> + + <para> + Consider the problem of expressing a capability shared by some + existing classes that are already part of a class hierarchy, + i.e. they already extend a class. In Java, one creates an + interface that captures this new capability, and then adds to + <emphasis>each affected class</emphasis> a method that implements + this interface. + </para> + + <para> + AspectJ can express the concern in one place, by using inter-type + declarations. The aspect declares the methods and fields that are + necessary to implement the new capability, and associates the + methods and fields to the existing classes. + </para> + + <para> + Suppose we want to have <classname>Screen</classname> objects + observe changes to <classname>Point</classname> objects, where + <classname>Point</classname> is an existing class. We can implement + this by writing an aspect declaring that the class Point + <classname>Point</classname> has an instance field, + <varname>observers</varname>, that keeps track of the + <classname>Screen</classname> objects that are observing + <classname>Point</classname>s. + </para> + +<programlisting><![CDATA[ +aspect PointObserving { + private Vector Point.observers = new Vector(); + ... +} +]]></programlisting> + + <para> + The <literal>observers</literal> field is private, so only + <classname>PointObserving</classname> can see it. So observers are + added or removed with the static methods + <function>addObserver</function> and + <function>removeObserver</function> on the aspect. + </para> + +<programlisting><![CDATA[ +aspect PointObserving { + private Vector Point.observers = new Vector(); + + public static void addObserver(Point p, Screen s) { + p.observers.add(s); + } + public static void removeObserver(Point p, Screen s) { + p.observers.remove(s); + } + ... +} +]]></programlisting> + + <para> + Along with this, we can define a pointcut + <function>changes</function> that defines what we want to observe, + and the after advice defines what we want to do when we observe a + change. + </para> + +<programlisting><![CDATA[ +aspect PointObserving { + private Vector Point.observers = new Vector(); + + public static void addObserver(Point p, Screen s) { + p.observers.add(s); + } + public static void removeObserver(Point p, Screen s) { + p.observers.remove(s); + } + + pointcut changes(Point p): target(p) && call(void Point.set*(int)); + + after(Point p): changes(p) { + Iterator iter = p.observers.iterator(); + while ( iter.hasNext() ) { + updateObserver(p, (Screen)iter.next()); + } + } + + static void updateObserver(Point p, Screen s) { + s.display(p); + } +} +]]></programlisting> + + <para> + Note that neither <classname>Screen</classname>'s nor + <classname>Point</classname>'s code has to be modified, and that + all the changes needed to support this new capability are local to + this aspect. + </para> + + </sect2> + +<!-- ============================== --> + + <sect2 id="aspects" xreflabel="aspects"> + <title>Aspects</title> + + <para> + Aspects wrap up pointcuts, advice, and inter-type declarations in a + a modular unit of crosscutting implementation. It is defined very + much like a class, and can have methods, fields, and initializers + in addition to the crosscutting members. Because only aspects may + include these crosscutting members, the declaration of these + effects is localized. + </para> + + <para> + Like classes, aspects may be instantiated, but AspectJ controls how + that instantiation happens -- so you can't use Java's + <literal>new</literal> form to build new aspect instances. By + default, each aspect is a singleton, so one aspect instance is + created. This means that advice may use non-static fields of the + aspect, if it needs to keep state around: + </para> + +<programlisting><![CDATA[ +aspect Logging { + OutputStream logStream = System.err; + + before(): move() { + logStream.println("about to move"); + } +} +]]></programlisting> + + <para> + Aspects may also have more complicated rules for instantiation, but + these will be described in a later chapter. + </para> + + </sect2> + </sect1> + +<!-- ============================== --> + + <sect1 id="starting-development" xreflabel="Development Aspects"> + <title>Development Aspects</title> + + <para> + The next two sections present the use of aspects in increasingly + sophisticated ways. Development aspects are easily removed from + production builds. Production aspects are intended to be used in + both development and in production, but tend to affect only a few + classes. + </para> + + <para> + This section presents examples of aspects that can be used during + development of Java applications. These aspects facilitate debugging, + testing and performance tuning work. The aspects define behavior that + ranges from simple tracing, to profiling, to testing of internal + consistency within the application. Using AspectJ makes it possible + to cleanly modularize this kind of functionality, thereby making it + possible to easily enable and disable the functionality when desired. + </para> + + <sect2 id="tracing" xreflabel="tracing"> + <title>Tracing</title> + + <para> + This first example shows how to increase the visibility of the + internal workings of a program. It is a simple tracing aspect that + prints a message at specified method calls. In our figure editor + example, one such aspect might simply trace whenever points are + drawn. + </para> + +<programlisting><![CDATA[ +aspect SimpleTracing { + pointcut tracedCall(): + call(void FigureElement.draw(GraphicsContext)); + + before(): tracedCall() { + System.out.println("Entering: " + thisJoinPoint); + } +} +]]></programlisting> + + <para> + This code makes use of the <literal>thisJoinPoint</literal> special + variable. Within all advice bodies this variable is bound to an + object that describes the current join point. The effect of this + code is to print a line like the following every time a figure + element receives a <function>draw</function> method call: + </para> + +<programlisting><![CDATA[ +Entering: call(void FigureElement.draw(GraphicsContext)) +]]></programlisting> + + <para> + To understand the benefit of coding this with AspectJ consider + changing the set of method calls that are traced. With AspectJ, + this just requires editing the definition of the + <function>tracedCalls</function> pointcut and recompiling. The + individual methods that are traced do not need to be edited. + </para> + + <para> + When debugging, programmers often invest considerable effort in + figuring out a good set of trace points to use when looking for a + particular kind of problem. When debugging is complete or appears + to be complete it is frustrating to have to lose that investment by + deleting trace statements from the code. The alternative of just + commenting them out makes the code look bad, and can cause trace + statements for one kind of debugging to get confused with trace + statements for another kind of debugging. + </para> + + <para> + With AspectJ it is easy to both preserve the work of designing a + good set of trace points and disable the tracing when it isn t + being used. This is done by writing an aspect specifically for that + tracing mode, and removing that aspect from the compilation when it + is not needed. + </para> + + <para> + This ability to concisely implement and reuse debugging + configurations that have proven useful in the past is a direct + result of AspectJ modularizing a crosscutting design element the + set of methods that are appropriate to trace when looking for a + given kind of information. + </para> + </sect2> + + <sect2 id="profiling-and-logging" xreflabel="profiling-and-logging"> + <title>Profiling and Logging</title> + + <para> + Our second example shows you how to do some very specific + profiling. Although many sophisticated profiling tools are + available, and these can gather a variety of information and + display the results in useful ways, you may sometimes want to + profile or log some very specific behavior. In these cases, it is + often possible to write a simple aspect similar to the ones above + to do the job. + </para> + + <para> + For example, the following aspect counts the number of calls to the + <function>rotate</function> method on a <classname>Line</classname> + and the number of calls to the <function>set*</function> methods of + a <classname>Point</classname> that happen within the control flow + of those calls to <function>rotate</function>: + </para> + +<programlisting><![CDATA[ +aspect SetsInRotateCounting { + int rotateCount = 0; + int setCount = 0; + + before(): call(void Line.rotate(double)) { + rotateCount++; + } + + before(): call(void Point.set*(int)) + && cflow(call(void Line.rotate(double))) { + setCount++; + } +} +]]></programlisting> + + <para> + In effect, this aspect allows the programmer to ask very specific + questions like + + <blockquote> + How many times is the <function>rotate</function> + method defined on <classname>Line</classname> objects called? + </blockquote> + + and + + <blockquote> + How many times are methods defined on + <classname>Point</classname> objects whose name begins with + "<function>set</function>" called in fulfilling those rotate + calls? + </blockquote> + + questions it may be difficult to express using standard + profiling or logging tools. + </para> + + </sect2> + +<!-- ============================== --> + + <sect2 id="pre-and-post-conditions" xreflabel="pre-and-post-conditions"> + <title>Pre- and Post-Conditions</title> + + <para> + Many programmers use the "Design by Contract" style popularized by + Bertand Meyer in <citetitle>Object-Oriented Software Construction, + 2/e</citetitle>. In this style of programming, explicit + pre-conditions test that callers of a method call it properly and + explicit post-conditions test that methods properly do the work + they are supposed to. + </para> + + <para> + AspectJ makes it possible to implement pre- and post-condition + testing in modular form. For example, this code + </para> + + +<programlisting><![CDATA[ +aspect PointBoundsChecking { + + pointcut setX(int x): + (call(void FigureElement.setXY(int, int)) && args(x, *)) + || (call(void Point.setX(int)) && args(x)); + + pointcut setY(int y): + (call(void FigureElement.setXY(int, int)) && args(*, y)) + || (call(void Point.setY(int)) && args(y)); + + before(int x): setX(x) { + if ( x < MIN_X || x > MAX_X ) + throw new IllegalArgumentException("x is out of bounds."); + } + + before(int y): setY(y) { + if ( y < MIN_Y || y > MAX_Y ) + throw new IllegalArgumentException("y is out of bounds."); + } +} +]]></programlisting> + + <para> + implements the bounds checking aspect of pre-condition testing for + operations that move points. Notice that the + <function>setX</function> pointcut refers to all the operations + that can set a Point's <literal>x</literal> coordinate; this + includes the <function>setX</function> method, as well as half of + the <function>setXY</function> method. In this sense the + <function>setX</function> pointcut can be seen as involving very + fine-grained crosscutting - it names the the + <function>setX</function> method and half of the + <function>setXY</function> method. + </para> + + <para> + Even though pre- and post-condition testing aspects can often be + used only during testing, in some cases developers may wish to + include them in the production build as well. Again, because + AspectJ makes it possible to modularize these crosscutting concerns + cleanly, it gives developers good control over this decision. + </para> + + </sect2> + +<!-- ============================== --> + + <sect2 id="contract-enforcement" xreflabel="contract-enforcement"> + <title>Contract Enforcement</title> + + <para> + The property-based crosscutting mechanisms can be very useful in + defining more sophisticated contract enforcement. One very powerful + use of these mechanisms is to identify method calls that, in a + correct program, should not exist. For example, the following + aspect enforces the constraint that only the well-known factory + methods can add an element to the registry of figure + elements. Enforcing this constraint ensures that no figure element + is added to the registry more than once. + </para> + +<programlisting><![CDATA[ +aspect RegistrationProtection { + + pointcut register(): call(void Registry.register(FigureElement)); + + pointcut canRegister(): withincode(static * FigureElement.make*(..)); + + before(): register() && !canRegister() { + throw new IllegalAccessException("Illegal call " + thisJoinPoint); + } +} +]]></programlisting> + + <para> + This aspect uses the withincode primitive pointcut to denote all + join points that occur within the body of the factory methods on + <classname>FigureElement</classname> (the methods with names that + begin with "<literal>make</literal>"). This is a property-based + pointcut because it identifies join points based not on their + signature, but rather on the property that they occur specifically + within the code of another method. The before advice declaration + effectively says signal an error for any calls to register that are + not within the factory methods. + </para> + + <para> + This advice throws a runtime exception at certain join points, but + AspectJ can do better. Using the <literal>declare error</literal> + form, we can have the <emphasis>compiler</emphasis> signal the + error. + </para> + +<programlisting><![CDATA[ +aspect RegistrationProtection { + + pointcut register(): call(void Registry.register(FigureElement)); + pointcut canRegister(): withincode(static * FigureElement.make*(..)); + + declare error: register() && !canRegister(): "Illegal call" +} +]]></programlisting> + + <para> + When using this aspect, it is impossible for the compiler to + compile programs with these illegal calls. This early detection is + not always possible. In this case, since we depend only on static + information (the <literal>withincode</literal> pointcut picks out + join points totally based on their code, and the + <literal>call</literal> pointcut here picks out join points + statically). Other enforcement, such as the precondition + enforcement, above, does require dynamic information such as the + runtime value of parameters. + </para> + </sect2> + +<!-- ============================== --> + + <sect2 id="configuration-management" xreflabel="configuration-management"> + <title>Configuration Management</title> + + <para> + Configuration management for aspects can be handled using a variety + of make-file like techniques. To work with optional aspects, the + programmer can simply define their make files to either include the + aspect in the call to the AspectJ compiler or not, as desired. + </para> + + <para> + Developers who want to be certain that no aspects are included in + the production build can do so by configuring their make files so + that they use a traditional Java compiler for production builds. To + make it easy to write such make files, the AspectJ compiler has a + command-line interface that is consistent with ordinary Java + compilers. + </para> + </sect2> + </sect1> + +<!-- ============================== --> + + <sect1 id="starting-production" xreflabel="Production Aspects"> + <title>Production Aspects</title> + + <para> + This section presents examples of aspects that are inherently + intended to be included in the production builds of an application. + Production aspects tend to add functionality to an application + rather than merely adding more visibility of the internals of a + program. Again, we begin with name-based aspects and follow with + property-based aspects. Name-based production aspects tend to + affect only a small number of methods. For this reason, they are a + good next step for projects adopting AspectJ. But even though they + tend to be small and simple, they can often have a significant + effect in terms of making the program easier to understand and + maintain. + </para> + + <sect2 id="change-monitoring" xreflabel="change-monitoring"> + <title>Change Monitoring</title> + + <para> + The first example production aspect shows how one might implement + some simple functionality where it is problematic to try and do it + explicitly. It supports the code that refreshes the display. The + role of the aspect is to maintain a dirty bit indicating whether or + not an object has moved since the last time the display was + refreshed. + </para> + + <para> + Implementing this functionality as an aspect is straightforward. + The <function>testAndClear</function> method is called by the + display code to find out whether a figure element has moved + recently. This method returns the current state of the dirty flag + and resets it to false. The pointcut <function>move</function> + captures all the method calls that can move a figure element. The + after advice on <function>move</function> sets the dirty flag + whenever an object moves. + </para> + +<programlisting><![CDATA[ +aspect MoveTracking { + private static boolean dirty = false; + + public static boolean testAndClear() { + boolean result = dirty; + dirty = false; + return result; + } + + pointcut move(): + call(void FigureElement.setXY(int, int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point)) || + call(void Point.setX(int)) || + call(void Point.setY(int)); + + after() returning: move() { + dirty = true; + } +} +]]></programlisting> + + <para> + Even this simple example serves to illustrate some of the important + benefits of using AspectJ in production code. Consider implementing + this functionality with ordinary Java: there would likely be a + helper class that contained the <literal>dirty</literal> flag, the + <function>testAndClear</function> method, as well as a + <function>setFlag</function> method. Each of the methods that could + move a figure element would include a call to the + <function>setFlag</function> method. Those calls, or rather the + concept that those calls should happen at each move operation, are + the crosscutting concern in this case. + </para> + + <para> + The AspectJ implementation has several advantages over the standard + implementation: + </para> + + <para> + <emphasis>The structure of the crosscutting concern is captured + explicitly.</emphasis> The moves pointcut clearly states all the + methods involved, so the programmer reading the code sees not just + individual calls to <literal>setFlag</literal>, but instead sees + the real structure of the code. The IDE support included with + AspectJ automatically reminds the programmer that this aspect + advises each of the methods involved. The IDE support also + provides commands to jump to the advice from the method and + vice-versa. + </para> + + <para> + <emphasis>Evolution is easier.</emphasis> If, for example, the + aspect needs to be revised to record not just that some figure + element moved, but rather to record exactly which figure elements + moved, the change would be entirely local to the aspect. The + pointcut would be updated to expose the object being moved, and the + advice would be updated to record that object. The paper + <citetitle>An Overview of AspectJ</citetitle> (available linked off + of the AspectJ web site -- <ulink + url="https://eclipse.org/aspectj" />), presented at ECOOP + 2001, presents a detailed discussion of various ways this aspect + could be expected to evolve. + </para> + + <para> + <emphasis>The functionality is easy to plug in and out.</emphasis> + Just as with development aspects, production aspects may need to be + removed from the system, either because the functionality is no + longer needed at all, or because it is not needed in certain + configurations of a system. Because the functionality is + modularized in a single aspect this is easy to do. + </para> + + <para> + <emphasis>The implementation is more stable.</emphasis> If, for + example, the programmer adds a subclass of + <classname>Line</classname> that overrides the existing methods, + this advice in this aspect will still apply. In the ordinary Java + implementation the programmer would have to remember to add the + call to <function>setFlag</function> in the new overriding + method. This benefit is often even more compelling for + property-based aspects (see the section <xref + linkend="starting-production-consistentBehavior"/>). + </para> + </sect2> + +<!-- ============================== --> + + <sect2 id="context-passing" xreflabel="context-passing"> + <title>Context Passing</title> + + <para> + The crosscutting structure of context passing can be a significant + source of complexity in Java programs. Consider implementing + functionality that would allow a client of the figure editor (a + program client rather than a human) to set the color of any figure + elements that are created. Typically this requires passing a color, + or a color factory, from the client, down through the calls that + lead to the figure element factory. All programmers are familiar + with the inconvenience of adding a first argument to a number of + methods just to pass this kind of context information. + </para> + + <para> + Using AspectJ, this kind of context passing can be implemented in a + modular way. The following code adds after advice that runs only + when the factory methods of <classname>Figure</classname> are + called in the control flow of a method on a + <classname>ColorControllingClient</classname>. + </para> + +<programlisting><![CDATA[ +aspect ColorControl { + pointcut CCClientCflow(ColorControllingClient client): + cflow(call(* * (..)) && target(client)); + + pointcut make(): call(FigureElement Figure.make*(..)); + + after (ColorControllingClient c) returning (FigureElement fe): + make() && CCClientCflow(c) { + fe.setColor(c.colorFor(fe)); + } +} +]]></programlisting> + + <para> + This aspect affects only a small number of methods, but note that + the non-AOP implementation of this functionality might require + editing many more methods, specifically, all the methods in the + control flow from the client to the factory. This is a benefit + common to many property-based aspects while the aspect is short and + affects only a modest number of benefits, the complexity the aspect + saves is potentially much larger. + </para> + + </sect2> + +<!-- ============================== --> + + <sect2 id="starting-production-consistentBehavior" xreflabel="Providing Consistent Behavior"> + <title>Providing Consistent Behavior</title> + + <para> + This example shows how a property-based aspect can be used to + provide consistent handling of functionality across a large set of + operations. This aspect ensures that all public methods of the + <literal>com.bigboxco</literal> package log any Errors they throw + to their caller (in Java, an Error is like an Exception, but it + indicates that something really bad and usually unrecoverable has + happened). The <function>publicMethodCall</function> pointcut + captures the public method calls of the package, and the after + advice runs whenever one of those calls throws an Error. The advice + logs that Error and then the throw resumes. + </para> + + <programlisting><![CDATA[ +aspect PublicErrorLogging { + Log log = new Log(); + + pointcut publicMethodCall(): + call(public * com.bigboxco.*.*(..)); + + after() throwing (Error e): publicMethodCall() { + log.write(e); + } +} +]]></programlisting> + + <para> + In some cases this aspect can log an exception twice. This happens + if code inside the <literal>com.bigboxco</literal> package itself + calls a public method of the package. In that case this code will + log the error at both the outermost call into the + <literal>com.bigboxco</literal> package and the re-entrant + call. The <function>cflow</function> primitive pointcut can be used + in a nice way to exclude these re-entrant calls:</para> + +<programlisting><![CDATA[ +after() throwing (Error e): + publicMethodCall() && !cflow(publicMethodCall()) { + log.write(e); +} +]]></programlisting> + + <para> + The following aspect is taken from work on the AspectJ compiler. + The aspect advises about 35 methods in the + <classname>JavaParser</classname> class. The individual methods + handle each of the different kinds of elements that must be + parsed. They have names like <function>parseMethodDec</function>, + <function>parseThrows</function>, and + <function>parseExpr</function>. + </para> + +<programlisting><![CDATA[ +aspect ContextFilling { + pointcut parse(JavaParser jp): + call(* JavaParser.parse*(..)) + && target(jp) + && !call(Stmt parseVarDec(boolean)); // var decs + // are tricky + + around(JavaParser jp) returns ASTObject: parse(jp) { + Token beginToken = jp.peekToken(); + ASTObject ret = proceed(jp); + if (ret != null) jp.addContext(ret, beginToken); + return ret; + } +} +]]></programlisting> + + <para> + This example exhibits a property found in many aspects with large + property-based pointcuts. In addition to a general property based + pattern <literal>call(* JavaParser.parse*(..))</literal> it + includes an exception to the pattern <literal>!call(Stmt + parseVarDec(boolean))</literal>. The exclusion of + <function>parseVarDec</function> happens because the parsing of + variable declarations in Java is too complex to fit with the clean + pattern of the other <function>parse*</function> methods. Even with + the explicit exclusion this aspect is a clear expression of a clean + crosscutting modularity. Namely that all + <function>parse*</function> methods that return + <classname>ASTObjects</classname>, except for + <function>parseVarDec</function> share a common behavior for + establishing the parse context of their result. + </para> + + <para> + The process of writing an aspect with a large property-based + pointcut, and of developing the appropriate exceptions can clarify + the structure of the system. This is especially true, as in this + case, when refactoring existing code to use aspects. When we first + looked at the code for this aspect, we were able to use the IDE + support provided in AJDE for JBuilder to see what methods the + aspect was advising compared to our manual coding. We quickly + discovered that there were a dozen places where the aspect advice + was in effect but we had not manually inserted the required + functionality. Two of these were bugs in our prior non-AOP + implementation of the parser. The other ten were needless + performance optimizations. So, here, refactoring the code to + express the crosscutting structure of the aspect explicitly made + the code more concise and eliminated latent bugs. + </para> + </sect2> + </sect1> + +<!-- ============================== --> + + <sect1 id="starting-conclusion"> + <title>Conclusion</title> + + <para> + AspectJ is a simple and practical aspect-oriented extension to + Java. With just a few new constructs, AspectJ provides support for + modular implementation of a range of crosscutting concerns. + </para> + + <para> + Adoption of AspectJ into an existing Java development project can be + a straightforward and incremental task. One path is to begin by using + only development aspects, going on to using production aspects and + then reusable aspects after building up experience with + AspectJ. Adoption can follow other paths as well. For example, some + developers will benefit from using production aspects right + away. Others may be able to write clean reusable aspects almost right + away. + </para> + + <para> + AspectJ enables both name-based and property based crosscutting. + Aspects that use name-based crosscutting tend to affect a small + number of other classes. But despite their small scale, they can + often eliminate significant complexity compared to an ordinary Java + implementation. Aspects that use property-based crosscutting can + have small or large scale. + </para> + + <para> + Using AspectJ results in clean well-modularized implementations of + crosscutting concerns. When written as an AspectJ aspect the + structure of a crosscutting concern is explicit and easy to + understand. Aspects are also highly modular, making it possible to + develop plug-and-play implementations of crosscutting + functionality. + </para> + + <para> + AspectJ provides more functionality than was covered by this short + introduction. The next chapter, <xref linkend="language"/>, + covers in detail more of the features of the AspectJ language. The + following chapter, <xref linkend="examples"/>, then presents some + carefully chosen examples that show you how AspectJ might be used. We + recommend that you read the next two chapters carefully before + deciding to adopt AspectJ into a project. + </para> + </sect1> +</chapter> |