| <?xml version="1.0" encoding="iso-8859-1"?> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
| |
| <!-- This file represents the Exercises for the hands-on AspectJ |
| tutorial. It is commonly checked into CVS with identifying |
| information for the latest conference (such as presenters |
| and publication information). |
| |
| When you use it for your own purposes, don't forget to |
| modify at the very least anything that says |
| id="copyright" or class="presenter". If you're in an A4 |
| country, don't forget to modify the paper size. |
| |
| The gif included at the end is somewhat fragile, |
| so be careful with different paper sizes. |
| |
| TODO: There is currently something weird about PDF generation |
| from this: If generated from a windows machine, it will |
| generate mac-unfriendly PDF because of the requested windows |
| font. If the PDF is only used for immediate printing, |
| that's fine, but if it's used for distribution, bad. |
| --> |
| |
| <head> |
| <title>Hands-on Programming with AspectJ® — Exercises</title> |
| <style type="text/css"> |
| div.instruction { padding: 0.5em; border-width: 1px; border-style: solid } |
| body { background-color: #FFF; margin: 2em } |
| body { font-family: "Gill Sans MT", "Gill sans", "Trebuchet ms", Verdana, sans-serif; } |
| .newpage { page-break-before: always } |
| pre { margin-left: 1em; border-left-style: solid; border-width: 1px; padding-left: 1em;} |
| h2 { margin-top: 4ex; } |
| h3 { margin-top: 4ex; border-bottom-style: solid; border-width: 1px } |
| .presenter { text-align: right } |
| @page { |
| size: 8.5in 11in; |
| margin: 3in; |
| marks: cross |
| } |
| @media print { |
| body { font-size: 10pt } |
| #copyright { |
| font-family: "Times New Roman", "Times Roman", fixed; |
| font-size: 8pt; |
| display: normal; |
| position: absolute; |
| bottom: 1in; |
| border-style: none |
| } |
| } |
| @media screen { |
| #copyright { display: none } |
| } |
| </style> |
| </head> |
| |
| <body> |
| |
| <h1>Hands-on Programming with AspectJ<sup>®</sup></h1> |
| |
| <div class="presenter">Matt Chapman</div> |
| <div class="presenter">Matthew Webster</div> |
| <div class="presenter">Mik Kersten</div> |
| <div class="presenter">http://www.eclipse.org/aspectj</div> |
| <div class="presenter">http://www.eclipse.org/ajdt</div> |
| |
| <h2>Overview</h2> |
| |
| <p> In this tutorial you will solve some basic programming |
| tasks using AspectJ. The tasks progress from writing |
| non-functional, development-only aspects to writing aspects that |
| augment a deployed program with crosscutting features. This |
| follows the same progression most users see in their own adoption |
| of AspectJ. </p> |
| |
| <p> Since this is a hands-on tutorial, you will be working with a |
| live AspectJ distribution. The example code we will be working |
| with is a simple figure editor, along with JUnit tests for each |
| exercise. We will break up into groups of two to three people |
| per computer to foster discussion within the group as well as |
| with the presenters. </p> |
| |
| <p> If you have a laptop running a recent version of Windows, |
| MacOS or Linux, feel free to bring it along. We will provide CDs |
| and other installation media for a standalone AspectJ system, |
| including the figure editor code these exercises are based on and |
| unit tests for the exercises. If you don't have a laptop with |
| you, don't worry about it. </p> |
| |
| <p> These notes consist of four sections of exercises, a quick |
| reference to AspectJ syntax, and a UML diagram of a figure editor |
| program. </p> |
| |
| <div class="instruction"> If you receive these tutorial notes |
| early, feel free to have a quick look, especially at the UML |
| diagram and quick reference. But you'll be cheating yourself if |
| you try to do the exercises early; you'll learn a lot more by |
| working through it in groups during the tutorial proper. </div> |
| |
| <!-- |
| This space is used for a copyright that appears on the |
| bottom of the _printed_ page. It's suppressed when viewed on |
| a computer screen by the stylesheet. |
| |
| <div id="copyright"> |
| Copyright is held by the author/owner(s). <br /> |
| OOPSLA04, October 24-28, 2004, Vancouver, British Columbia, Canada <br /> |
| 2004 ACM 04/0010 |
| </div> |
| --> |
| <h3 class="newpage">AspectJ Development in Eclipse</h3> |
| |
| <p>The AspectJ Development Tools (AJDT) plugins for Eclipse |
| provide support for using the AspectJ compiler in the Eclipse environment. |
| Different versions of AJDT are available to support both the latest |
| release version of Eclipse, and the latest milestone build. |
| As part of the tutorial we will be providing distributions of base |
| eclipse, the AJDT plugins and the exercises. Should you wish to |
| install the exercises into an existing configuration on your machine, |
| you can download the exercises plugin via the following URL: |
| </p> |
| |
| <a href="http://eclipse.org/ajdt/EclipseCon2006/org.aspectj.tutorial.exercises_1.0.0.jar">http://eclipse.org/ajdt/EclipseCon2006/org.aspectj.tutorial.exercises_1.0.0.jar</a> |
| |
| <p> |
| Simply copy this JAR file to your eclipse/plugins folder. |
| </p> |
| |
| <h3>Installation</h3> |
| |
| <p>The key components to have installed are:</p> |
| <ul> |
| <li>An Eclipse distribution - 3.1.2 or 3.2M5 |
| <li>An AJDT distribution - 1.3 or 1.4.dev |
| <li>An AspectJ Exercises plugin - 1.0.0 |
| </ul> |
| |
| <p>The best way to verify your installation is by attempting to |
| create one of the 4 tutorial projects. To do this, open File>New>Other... |
| as shown here (or press the New button on the toolbar):</p> |
| <p align="center"><img src="shots/FileNew.png"></p> |
| <p>You should then see the following option:</p> |
| <p align="center"><img src="shots/AJTutorials.png"></p> |
| <p>If you do, congratulations, you are ready to go !!</p> |
| |
| <!-- ============================== --> |
| |
| <h2 class="newpage">1. Static Invariants</h2> |
| |
| <p> The easiest way to get started with AspectJ is to use it to |
| enforce static invariants, also known as compile time checks. These |
| can be as simple as verifying a particular API is never called or as |
| sophisticated as verifying your layered architecture is adhered to. |
| </p> |
| <p>The tutorial plugin includes four eclipse projects representing |
| the four major parts of this tutorial. Use the menus described in |
| the previous two screenshots to create each exercise - create |
| the first project now, <code>Exercise1</code>.</p> |
| |
| <h3>1.a. Find old tracing</h3> |
| |
| <div class="instruction"> <strong>Sample Exercise</strong>: The |
| main point of this exercise is to make sure your configuration |
| works.</div> |
| |
| <p> <strong>Task:</strong> Signal an error for calls to |
| <code>System.out.println</code>. |
| </p> |
| |
| <p> The way that we are all taught to print "hello world" from Java is |
| to use <code>System.out.println()</code>, so that is what we typically |
| use for one-off debugging traces. It's a common mistake to leave |
| these in your system far longer than is necessary. Type in the aspect |
| below to signal an error at compile time if this mistake is made. |
| </p> |
| <p>This is your first aspect, in order to create the necessary Eclipse |
| resource into which you can type the answer, use the New Aspect Wizard. |
| You can access this wizard in two ways:</p> |
| |
| <p> |
| 1. From the New Java Class drop-down on the toolbar: |
| </p> |
| |
| <p align="center"><img src="shots/NewAspectToolbarOption.png"></p> |
| |
| <p> |
| 2. From the File>New menu:</p> |
| </p> |
| |
| <p align="center"><img src="shots/NewAspectMenuOption.png"></p> |
| |
| |
| <p>For this first aspect, fill it in as shown below:</p> |
| <p align="center"><img src="shots/NewAspectWizard.png"></p> |
| <p>After clicking <code>Finish</code> you should find yourself in the |
| new aspect, change it to look like this following code</p> |
| |
| <p> <strong>Answer:</strong> |
| </p> |
| |
| <pre> |
| package answers; |
| |
| import figures.*; |
| |
| aspect Answer { |
| declare error |
| : get(java.io.PrintStream System.out) && within(figures..*) |
| : "illegal access to System.out"; |
| } |
| </pre> |
| |
| <div class="instruction"><strong>Note: </strong> For every task in this tutorial, you should work in the same |
| Answer aspect that you create at the start of the exercise, comment out |
| each previous answer as you move to the next task - if you don't then |
| you may unexpectedly get some test failures.</p></div> |
| |
| <p> After saving, a build will take place and you'll find one incorrect |
| trace in <code>SlothfulPoint</code>:</p> |
| <p align="center"><img src="shots/Answer1a.png"></p> |
| |
| <p> Note that this answer does not say that the <em>call</em> to the |
| <code>println()</code> method is incorrect, rather, that the field get |
| of the <code>out</code> field is illegal. This will also catch those |
| users who bind System.out to a static field to save typing. </p> |
| |
| <p> After successfully finding the error, edit your |
| program to remove the illegal tracing call. </p> |
| |
| <p> Make sure your program still passes the JUnit test |
| <code>tests.CoreTest</code> (which it should also pass at the beginning of |
| all exercises) before continuing. Every exercise in this tutorial includes |
| tests, each of which should be run individually. To run a particular test, |
| locate it in the <code>test-src</code> folder, then, right click the test |
| and navigate to the <code>Run>JUnit Test</code> menu option as shown here:</p> |
| <p align="center"><img src="shots/runningJUnitTests.png"></p> |
| |
| <p>If it runs OK, you should get the trusty green bar:</p> |
| <p align="center"><img src="shots/junitTestsPassing.png"></p> |
| |
| <p>When it passes, you are ready to move on!</p> |
| |
| <h3 class="newpage">1.b. Mandate setters</h3> |
| |
| <p> <strong>Task:</strong> Signal a warning for assignments outside |
| of setter methods. </p> |
| |
| <p> <strong>Tools:</strong> <code>set</code>, <code>withincode</code>, |
| the <code>void set*(..)</code> pattern |
| </p> |
| |
| <p> One common coding convention is that no private field should |
| be assigned to outside of setter methods. Write an aspect to |
| signal a warning at compile time for these illegal assignment |
| expressions. </p> |
| |
| <p> This is going to look like |
| </p> |
| |
| <pre> |
| aspect Answer { |
| declare warning: <em><pointcut here></em> : "bad field set"; |
| } |
| </pre> |
| |
| <p> where the pointcut picks out join points of private field sets |
| outside of setter methods. "Outside", here, means that the code for |
| the assignment is outside the <em>text</em> of the setter. |
| |
| |
| |
| <p> Make sure your program still passes the JUnit test |
| <code>tests.CoreTest</code> before continuing. Make sure you get eleven |
| warnings from this:</p> |
| <p align="center"><img src="shots/1b_11warnings.png"></p> |
| |
| |
| <p>Wait to fix them until the next exercise. </p> |
| |
| <h3>1.c. Refine setters mandate</h3> |
| |
| <p> <strong>Task:</strong> Allow assignmnents inside of constructors. |
| </p> |
| |
| <p> <strong>Tools:</strong> the <code>new(..)</code> pattern</p> |
| |
| <p> Look at some of the warnings from the previous exercise. Notice |
| that a lot of them are from within constructors. Actually, the common |
| coding convention is that no private field should be assigned to outside of |
| setter methods <em>or constructors</em>. Modify your answer to signal |
| an actual error at compile time (rather than just a warning) when such |
| an illegal assignment expression exists. </p> |
| |
| <p>You'll want to add another <code>withincode</code> primitive |
| pointcut to deal with the constructors. |
| </p> |
| |
| <p>After you specify your pointcut correctly, you'll still find that |
| the convention is violated twice in the figures package. You should see |
| the following two errors:</p> |
| |
| <pre> |
| .\figures\Point.java:37 bad field set |
| .\figures\Point.java:38 bad field set |
| </pre> |
| |
| <p>Rewrite these two occurrences so as not to violate |
| the convention. Make sure your program still passes the JUnit test |
| <code>tests.CoreTest</code> before continuing. </p> |
| |
| <div class="instruction"> Congratulations, you've taken your |
| first steps. At this point, check the people to your left and |
| right. If they're stuck somewhere, see if you can help them. |
| Try to resist moving on to the next section until we discuss |
| solutions as a group. </div> |
| |
| <!-- ============================== --> |
| |
| <h2 class="newpage">2. Dynamic invariants</h2> |
| |
| <p> The next step in AspectJ adoption is often to augment a test suite |
| by including additional dynamic tests, sometimes called runtime checks. |
| </p> |
| |
| <div class="instruction"> Tutorial attendees typically progress |
| at different speeds through these exercises. Throughout this |
| tutorial, if you finish early, see what the people around you are |
| doing and if they need help. Don't help them out of charity, |
| help them out of naked self-interest—we promise you'll learn a |
| lot about using AspectJ by explaining it. </div> |
| |
| <h3>2.a. Check a simple precondition</h3> |
| |
| <div class="instruction"> <strong>Sample Exercise</strong>: We've |
| provided the answer to this exercise to get you started. Feel |
| free to think a bit, but don't get stuck on this one. </div> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test2a</code>. |
| </p> |
| |
| <p> <strong>Tools:</strong> <code>args</code>, <code>before</code> |
| </p> |
| |
| <p> Write an aspect to throw an <code>IllegalArgumentException</code> |
| whenever an attempt is made to set one of <code>Point</code>'s |
| <code>int</code> fields to a value that is less than zero. </p> |
| |
| <p> This should make the test case of <code>tests.Test2a</code> pass, |
| which wouldn't without your aspect. So before compiling in the |
| aspect: |
| </p> |
| |
| <p align="center"><img src="shots/fail.png"></p> |
| |
| <p> But after compiling in the aspect... |
| </p> |
| |
| <p align="center"><img src="shots/pass.png"></p> |
| |
| <p> <strong>Answer:</strong> |
| </p> |
| |
| <pre> |
| package answers; |
| |
| import figures.*; |
| |
| aspect Answer { |
| before(int newValue): set(int Point.*) && args(newValue) { |
| if (newValue < 0) { |
| throw new IllegalArgumentException("too small"); |
| } |
| } |
| } |
| </pre> |
| |
| <h3>2.b. Check another precondition</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test2b</code>. </p> |
| |
| <p> <strong>Tools: </strong> <code>call</code> |
| </p> |
| |
| <p> <code>Group</code> is a <code>FigureElement</code> class that |
| encapsulates groups of other figure elements. As such, only actual |
| figure element objects should be added to <code>Group</code> objects. |
| Write an aspect to throw an <code>IllegalArgumentException</code> |
| whenever <code>Group.add()</code> is called with a <code>null</code> |
| value. </p> |
| |
| <p> Look at <code>tests/Test2b.java</code> to see exactly what we're |
| testing for. </p> |
| |
| <h3>2.c. Check yet another precondition</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test2c</code>. </p> |
| |
| <p> <strong>Tools:</strong> <code>target</code> |
| </p> |
| |
| <p> Another constraint on a well-formed group is that it should not |
| contain itself as a member (though it may contain other groups). Write |
| an aspect to throw an <code>IllegalArgumentException</code> whenever |
| an attempt is made to call <code>Group.add()</code> on a |
| <code>null</code> value, or on the group itself. </p> |
| |
| <p> You will want to use a <code>target</code> pointcut to expose the |
| <code>Group</code> object that is the target of the <code>add</code> |
| call. |
| </p> |
| |
| <h3>2.d. Assure input</h3> |
| |
| <p> <strong>Task: </strong> Pass <code>tests.Test2d</code>. |
| </p> |
| |
| <p> <strong>Tools: </strong> <code>around advice</code> |
| </p> |
| |
| <p> Instead of throwing an exception when one of <code>Point</code>'s |
| <code>int</code> fields is set to a negative value, write an aspect |
| to trim the value to zero. You'll want to use <code>around</code> |
| advice that exposes the new value of the field assignment with an |
| <code>args</code> pointcut, and <code>proceed</code> with the trimmed |
| value. </p> |
| |
| <p> This is going to look something like |
| </p> |
| |
| <pre> |
| aspect Answer { |
| void around(int val): <var><Pointcut></var> { |
| <var><Do something with val></var> |
| proceed(val); |
| } |
| } |
| </pre> |
| |
| <h3 class="newpage">2.e. Check a postcondition</h3> |
| |
| <p> <strong>Task: </strong> Pass <code>tests.Test2e</code> |
| </p> |
| |
| <p> <strong>Tools: </strong> <code>around advice</code> |
| </p> |
| |
| <p> A postcondition of a <code>Point</code>'s <code>move</code> |
| operation is that the <code>Point</code>'s coordinates should change. |
| If a call to move didn't actually move a point by the desired |
| offset, then the point is in an illegal state and so an |
| <code>IllegalStateException</code> should be thrown. |
| </p> |
| |
| <p> Note that because we're dealing with how the coordinates change |
| during move, we need some way of getting access to the coordinates |
| both before <em>and</em> after the move, in one piece of advice. </p> |
| |
| <h3>2.f. Check another postcondition</h3> |
| |
| <p> <strong>Task: </strong> Pass <code>tests.Test2f</code> |
| </p> |
| |
| <p> <strong>Tools:</strong> the <code> Rectangle(Rectangle)</code> |
| constructor, the <code>Rectangle.translate(int, int)</code> method. |
| </p> |
| |
| <p> <code>FigureElement</code> objects have a <code>getBounds()</code> |
| method that returns a <code>java.awt.Rectangle</code> representing the |
| bounds of the object. An important postcondition of the general |
| <code>move</code> operation on a figure element is that the figure |
| element's bounds rectangle should move by the same amount as the |
| figure itself. Write an aspect to check for this postcondition -- |
| throw an <code>IllegalStateException</code> if it is violated. </p> |
| |
| <!-- ============================== --> |
| |
| <h2 class="newpage">3. Tracing</h2> |
| |
| <p> Tracing is one of the classic AspectJ applications, and is often |
| the first where AspectJ is used on deployed code. |
| </p> |
| |
| <h3>3.a. Simple tracing</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test3a</code>.</p> |
| |
| <p> <strong>Tools:</strong> |
| <code>Log.write(String)</code>, |
| <code>thisJoinPoint.toString()</code>, |
| <code>execution</code>, |
| <code>within</code> |
| </p> |
| |
| <p> Write an aspect to log the execution of all public methods |
| in the figures package. To do this, use the utility class |
| <code>Log</code> (this is in the <code>support</code> package, so |
| remember to import it into your answer aspect). Write a message |
| into the log with the static <code>write(String)</code> method.</p> |
| |
| <h3>3.b. Exposing a value</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test3b</code>.</p> |
| |
| <p> <strong>Tools:</strong> <code>target</code> |
| </p> |
| |
| <p> AspectJ can expose the target object at a join point for tracing. |
| In this exercise, you will print not only the join point information, |
| but also the target object, with the form |
| </p> |
| |
| <pre> |
| <em>thisJoinPointInfo</em> at <em>targetObject</em> |
| </pre> |
| |
| |
| <h3>3.c. More specialized logging</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test3c</code>.</p> |
| |
| <p> <strong>Tools:</strong> <code>args</code>. |
| </p> |
| |
| <p> Write an aspect to log whenever a <code>Point</code> is added to a |
| group. The <code>args</code> pointcut allows you to select join points |
| based on the type of a parameter to a method call. </p> |
| |
| <p> Look at the test case to see the trace message we expect you |
| to write in the log. |
| </p> |
| |
| <h3 class="newpage">3.d. Logging extended to checking an invariant</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test3d</code>.</p> |
| |
| <p> <strong>Tools:</strong> <code>inter-type field declaration</code> |
| </p> |
| |
| <p> Make sure that a <code>Point</code> is never added to more |
| than one <code>Group</code>. To do so, associate a boolean flag |
| with each <code>Point</code> using an inter-type declaration, |
| such as </p> |
| |
| <pre> |
| boolean Point.hasBeenAdded = false; |
| </pre> |
| |
| <p> Check and set this flag with the same kind of advice from your |
| answer to problem (c). Throw an <code>IllegalStateException</code> if |
| the point has already been added. |
| </p> |
| |
| <h3>3.e. Better error messages for 3.d.</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test3e</code>.</p> |
| |
| <p> Extend your solution to problem (d) by using the string |
| representation of the Point's containing group as the <code>msg</code> |
| part of the <code>IllegalStateException</code>. </p> |
| |
| <!-- ============================== --> |
| |
| <h2 class="newpage">4. Caching</h2> |
| |
| <p> Computation of the bounding box of <code>Group</code> objects |
| needs to deal with all aggregate parts of the group, and this |
| computation can be expensive. In this section, we will explore |
| various ways of reducing this expense. </p> |
| |
| <div class="instruction"> <strong>Optional</strong>: In all of |
| these exercises, you should only deal with points that are added |
| directly to Groups, rather than those that are added "indirectly" |
| through Lines and Boxes. You should handle those points |
| contained in Lines and Boxes only if time permits. </div> |
| |
| <h3>4.a. Make a constant override</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test4a</code>.</p> |
| |
| <p> <strong>Tools:</strong> <code>around</code>, |
| <code>FigureElement.MAX_BOUNDS</code> |
| </p> |
| |
| <p> <code>Group</code>'s <code>getBounds()</code> method could be |
| understood to be a conservative approximation of the bounding box of a |
| group. If that is true, then it would be a legal (and much faster) |
| implementation of <code>getBounds()</code> to simply always return a |
| rectangle consisting of the entire canvas. The entire canvas is returned |
| by the static field <code>FigureElement.MAX_BOUNDS</code>. |
| </p> |
| |
| <p> Write an aspect to implement this change. You can override |
| <code>Group</code>'s <code>getBounds()</code> method entirely with |
| around advice intercepting the method. |
| </p> |
| |
| <h3>4.b. Make a constant cache</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test4b</code>. |
| </p> |
| |
| <p> <strong>Tools:</strong> inter-type field. |
| </p> |
| |
| <p> Instead of making the (very) conservative approximation of |
| <code>getBounds()</code> from part (a), write an aspect instead that |
| remembers the return value from the first time |
| <code>getBounds()</code> has been called on a <code>Group</code>, and |
| returns that first <code>Rectangle</code> for every subsequent |
| call. </p> |
| |
| <p> <em>Hint: You can use an inter-type declaration to keep some |
| state for every <code>Group</code> object.</em> </p> |
| |
| |
| <h3>4.c. Invalidate, part 1</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test4c</code>. |
| </p> |
| |
| <p> <strong>Tools:</strong> <code>before</code> |
| </p> |
| |
| <p> While caching in this way does save computation, it will lead to |
| incorrect bounding boxes if a <code>Group</code> is ever moved. |
| Change your aspect so that it invalidates the cache whenever the |
| <code>move()</code> method of <code>Group</code> is called. |
| </p> |
| |
| <h3 class="newpage">4.d. Invalidate, part 2</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test4d</code>.</p> |
| |
| <p> Of course, part (c) didn't really solve the problem. What if a |
| <code>Point</code> that is part of a <code>Group</code> moves? |
| Whenever either of a Point's fields are set it should invalidate the |
| caches of all enclosing groups. Use your solution to problem 3c to |
| modify your invalidation criteria in this way, but note that this is |
| slightly different than the problem in 3c: Here you care about fields, |
| where there you cared about method calls. </p> |
| |
| <h3>4.e. Invalidate, part 3</h3> |
| |
| <p> <strong>Task:</strong> Pass <code>tests.Test4e</code>.</p> |
| |
| <p> <strong>Tools:</strong> <em>You're on you're own</em></p> |
| |
| <p> Did you really do part (d) correctly? Run the JUnit test |
| <code>tests.Test4e</code> to see. If you pass, congratulations, now |
| go help other people. Otherwise, you have fallen prey to our cruel |
| trap: Remember that whenever a point moves it should invalidate the |
| caches of <em>all</em> enclosing groups. </p> |
| |
| <div class="instruction"> |
| |
| <p> Congratulations! Not only have you learned about how to |
| program in AspectJ, you have worked through exercises paralleling |
| a common AspectJ adoption strategy. You should be able to |
| pick up AspectJ and use it to improve your own software's |
| crosscutting modularity. </p> |
| |
| <p> You can find the current binaries, source, documentation and |
| an active user community for AspectJ at</p> |
| |
| <blockquote> |
| http://www.eclipse.org/aspectj |
| </blockquote> |
| |
| </div> |
| |
| <img style="newpage" src="figures_classes.gif" height="900" alt="" /> |
| |
| </body> </html> |