You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

examples.xml 82KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438
  1. <chapter id="examples" xreflabel="Examples">
  2. <title>Examples</title>
  3. <sect1 id="examples-intro">
  4. <title>Introduction</title>
  5. <para>
  6. This chapter consists entirely of examples of AspectJ use.
  7. </para>
  8. <para>The examples can be grouped into four categories:</para>
  9. <simplelist columns="2" type="horiz">
  10. <member><emphasis role="bold">technique</emphasis></member>
  11. <member>Examples which illustrate how to use one or more features of the
  12. language. </member>
  13. <member><emphasis role="bold">development</emphasis></member>
  14. <member>Examples of using AspectJ during the development phase of a
  15. project. </member>
  16. <member><emphasis role="bold">production</emphasis></member>
  17. <member>Examples of using AspectJ to provide functionality in an
  18. application. </member>
  19. <member><emphasis role="bold">reusable</emphasis></member>
  20. <member>Examples of reuse of aspects and pointcuts.</member>
  21. </simplelist>
  22. </sect1>
  23. <!-- ============================== -->
  24. <sect1 id="examples-howto">
  25. <title>Obtaining, Compiling and Running the Examples</title>
  26. <para>
  27. The examples source code is part of the AspectJ distribution which may be
  28. downloaded from the AspectJ project page ( <ulink
  29. url="http://eclipse.org/aspectj" /> ).
  30. </para>
  31. <para>
  32. Compiling most examples is straightforward. Go the
  33. <filename><replaceable>InstallDir</replaceable>/examples</filename>
  34. directory, and look for a <filename>.lst</filename> file in one of
  35. the example subdirectories. Use the <literal>-arglist</literal>
  36. option to <literal>ajc</literal> to compile the example. For
  37. instance, to compile the telecom example with billing, type
  38. </para>
  39. <programlisting>
  40. ajc -argfile telecom/billing.lst
  41. </programlisting>
  42. <para>
  43. To run the examples, your classpath must include the AspectJ run-time
  44. Java archive (<literal>aspectjrt.jar</literal>). You may either set the
  45. <literal>CLASSPATH</literal> environment variable or use the
  46. <literal>-classpath</literal> command line option to the Java
  47. interpreter:
  48. </para>
  49. <programlisting>
  50. (In Unix use a : in the CLASSPATH)
  51. java -classpath ".:<replaceable>InstallDir</replaceable>/lib/aspectjrt.jar" telecom.billingSimulation
  52. </programlisting>
  53. <programlisting>
  54. (In Windows use a ; in the CLASSPATH)
  55. java -classpath ".;<replaceable>InstallDir</replaceable>/lib/aspectjrt.jar" telecom.billingSimulation
  56. </programlisting>
  57. </sect1>
  58. <!-- ============================================================ -->
  59. <sect1 id="examples-basic">
  60. <title>Basic Techniques</title>
  61. <para>
  62. This section presents two basic techniques of using AspectJ, one each
  63. from the two fundamental ways of capturing crosscutting concerns:
  64. with dynamic join points and advice, and with static
  65. introduction. Advice changes an application's behavior. Introduction
  66. changes both an application's behavior and its structure.
  67. </para>
  68. <para>
  69. The first example, <xref linkend="examples-joinPoints" />, is about
  70. gathering and using information about the join point that has
  71. triggered some advice. The second example, <xref
  72. linkend="examples-roles" />, concerns a crosscutting view of an
  73. existing class hierarchy. </para>
  74. <!-- ======================================== -->
  75. <sect2 id="examples-joinPoints">
  76. <title>Join Points and <literal>thisJoinPoint</literal></title>
  77. <para>
  78. (The code for this example is in
  79. <filename><replaceable>InstallDir</replaceable>/examples/tjp</filename>.)
  80. </para>
  81. <para>
  82. A join point is some point in the execution of a program together
  83. with a view into the execution context when that point occurs. Join
  84. points are picked out by pointcuts. When a program reaches a join
  85. point, advice on that join point may run in addition to (or instead
  86. of) the join point itself.
  87. </para>
  88. <para>
  89. When using a pointcut that picks out join points of a single kind
  90. by name, typicaly the the advice will know exactly what kind of
  91. join point it is associated with. The pointcut may even publish
  92. context about the join point. Here, for example, since the only
  93. join points picked out by the pointcut are calls of a certain
  94. method, we can get the target value and one of the argument values
  95. of the method calls directly.
  96. </para>
  97. <programlisting><![CDATA[
  98. before(Point p, int x): target(p)
  99. && args(x)
  100. && call(void setX(int)) {
  101. if (!p.assertX(x)) {
  102. System.out.println("Illegal value for x"); return;
  103. }
  104. }
  105. ]]></programlisting>
  106. <para>
  107. But sometimes the shape of the join point is not so clear. For
  108. instance, suppose a complex application is being debugged, and we
  109. want to trace when any method of some class is executed. The
  110. pointcut
  111. </para>
  112. <programlisting><![CDATA[
  113. pointcut execsInProblemClass(): within(ProblemClass)
  114. && execution(* *(..));
  115. ]]></programlisting>
  116. <para>
  117. will pick out each execution join point of every method defined
  118. within <classname>ProblemClass</classname>. Since advice executes
  119. at each join point picked out by the pointcut, we can reasonably
  120. ask which join point was reached.
  121. </para>
  122. <para>
  123. Information about the join point that was matched is available to
  124. advice through the special variable
  125. <varname>thisJoinPoint</varname>, of type <ulink
  126. url="../api/org/aspectj/lang/JoinPoint.html"><classname>org.aspectj.lang.JoinPoint</classname></ulink>.
  127. Through this object we can access information such as</para>
  128. <itemizedlist spacing="compact">
  129. <listitem>
  130. the kind of join point that was matched
  131. </listitem>
  132. <listitem>
  133. the source location of the code associated with the join point
  134. </listitem>
  135. <listitem>
  136. normal, short and long string representations of the
  137. current join point
  138. </listitem>
  139. <listitem>
  140. the actual argument values of the join point
  141. </listitem>
  142. <listitem>
  143. the signature of the member associated with the join point
  144. </listitem>
  145. <listitem>the currently executing object</listitem>
  146. <listitem>the target object</listitem>
  147. <listitem>
  148. an object encapsulating the static information about the join
  149. point. This is also available through the special variable
  150. <varname>thisJoinPointStaticPart</varname>.</listitem>
  151. </itemizedlist>
  152. <sect3>
  153. <title>The <classname>Demo</classname> class</title>
  154. <para>The class <classname>tjp.Demo</classname> in
  155. <filename>tjp/Demo.java</filename> defines two methods
  156. <literal>foo</literal> and <literal>bar</literal> with different
  157. parameter lists and return types. Both are called, with suitable
  158. arguments, by <classname>Demo</classname>'s
  159. <function>go</function> method which was invoked from within its
  160. <function>main</function> method.
  161. </para>
  162. <programlisting><![CDATA[
  163. public class Demo {
  164. static Demo d;
  165. public static void main(String[] args){
  166. new Demo().go();
  167. }
  168. void go(){
  169. d = new Demo();
  170. d.foo(1,d);
  171. System.out.println(d.bar(new Integer(3)));
  172. }
  173. void foo(int i, Object o){
  174. System.out.println("Demo.foo(" + i + ", " + o + ")\n");
  175. }
  176. String bar (Integer j){
  177. System.out.println("Demo.bar(" + j + ")\n");
  178. return "Demo.bar(" + j + ")";
  179. }
  180. }
  181. ]]></programlisting>
  182. </sect3>
  183. <sect3>
  184. <title>The <literal>GetInfo</literal> aspect</title>
  185. <para>
  186. This aspect uses around advice to intercept the execution of
  187. methods <literal>foo</literal> and <literal>bar</literal> in
  188. <classname>Demo</classname>, and prints out information garnered
  189. from <literal>thisJoinPoint</literal> to the console.
  190. </para>
  191. <programlisting><![CDATA[
  192. aspect GetInfo {
  193. static final void println(String s){ System.out.println(s); }
  194. pointcut goCut(): cflow(this(Demo) && execution(void go()));
  195. pointcut demoExecs(): within(Demo) && execution(* *(..));
  196. Object around(): demoExecs() && !execution(* go()) && goCut() {
  197. println("Intercepted message: " +
  198. thisJoinPointStaticPart.getSignature().getName());
  199. println("in class: " +
  200. thisJoinPointStaticPart.getSignature().getDeclaringType().getName());
  201. printParameters(thisJoinPoint);
  202. println("Running original method: \n" );
  203. Object result = proceed();
  204. println(" result: " + result );
  205. return result;
  206. }
  207. static private void printParameters(JoinPoint jp) {
  208. println("Arguments: " );
  209. Object[] args = jp.getArgs();
  210. String[] names = ((CodeSignature)jp.getSignature()).getParameterNames();
  211. Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes();
  212. for (int i = 0; i < args.length; i++) {
  213. println(" " + i + ". " + names[i] +
  214. " : " + types[i].getName() +
  215. " = " + args[i]);
  216. }
  217. }
  218. }
  219. ]]></programlisting>
  220. <sect4>
  221. <title>Defining the scope of a pointcut</title>
  222. <para>The pointcut <function>goCut</function> is defined as
  223. <programlisting><![CDATA[
  224. cflow(this(Demo)) && execution(void go())
  225. ]]></programlisting>
  226. so that only executions made in the control flow of
  227. <literal>Demo.go</literal> are intercepted. The control flow
  228. from the method <literal>go</literal> includes the execution of
  229. <literal>go</literal> itself, so the definition of the around
  230. advice includes <literal>!execution(* go())</literal> to
  231. exclude it from the set of executions advised. </para>
  232. </sect4>
  233. <sect4>
  234. <title>Printing the class and method name</title>
  235. <para>
  236. The name of the method and that method's defining class are
  237. available as parts of the <ulink
  238. url="../api/org/aspectj/lang/Signature.html">org.aspectj.lang.Signature</ulink>
  239. object returned by calling <literal>getSignature()</literal> on
  240. either <literal>thisJoinPoint</literal> or
  241. <literal>thisJoinPointStaticPart</literal>.
  242. </para>
  243. </sect4>
  244. <sect4>
  245. <title>Printing the parameters</title>
  246. <para>
  247. The static portions of the parameter details, the name and
  248. types of the parameters, can be accessed through the <ulink
  249. url="../api/org/aspectj/lang/reflect/CodeSignature.html"><literal>org.aspectj.lang.reflect.CodeSignature</literal></ulink>
  250. associated with the join point. All execution join points have code
  251. signatures, so the cast to <literal>CodeSignature</literal>
  252. cannot fail. </para>
  253. <para>
  254. The dynamic portions of the parameter details, the actual
  255. values of the parameters, are accessed directly from the
  256. execution join point object.
  257. </para>
  258. </sect4>
  259. </sect3>
  260. </sect2>
  261. <!-- ============================== -->
  262. <sect2 id="examples-roles">
  263. <title>Roles and Views</title>
  264. <para>
  265. (The code for this example is in
  266. <filename><replaceable>InstallDir</replaceable>/examples/introduction</filename>.)
  267. </para>
  268. <para>
  269. Like advice, inter-type declarations are members of an aspect. They
  270. declare members that act as if they were defined on another class.
  271. Unlike advice, inter-type declarations affect not only the behavior
  272. of the application, but also the structural relationship between an
  273. application's classes.
  274. </para>
  275. <para>
  276. This is crucial: Publically affecting the class structure of an
  277. application makes these modifications available to other components
  278. of the application.
  279. </para>
  280. <para>
  281. Aspects can declare inter-type
  282. <itemizedlist spacing="compact">
  283. <listitem>fields</listitem>
  284. <listitem>methods</listitem>
  285. <listitem>constructors</listitem>
  286. </itemizedlist>
  287. and can also declare that target types
  288. <itemizedlist spacing="compact">
  289. <listitem>implement new interfaces</listitem>
  290. <listitem>extend new classes</listitem>
  291. </itemizedlist>
  292. </para>
  293. <para>
  294. This example provides three illustrations of the use of inter-type
  295. declarations to encapsulate roles or views of a class. The class
  296. our aspect will be dealing with, <classname>Point</classname>, is a
  297. simple class with rectangular and polar coordinates. Our inter-type
  298. declarations will make the class <classname>Point</classname>, in
  299. turn, cloneable, hashable, and comparable. These facilities are
  300. provided by AspectJ without having to modify the code for the class
  301. <classname>Point</classname>.
  302. </para>
  303. <sect3>
  304. <title>The <classname>Point</classname> class</title>
  305. <para>The <classname>Point</classname> class defines geometric points
  306. whose interface includes polar and rectangular coordinates, plus some
  307. simple operations to relocate points. <classname>Point</classname>'s
  308. implementation has attributes for both its polar and rectangular
  309. coordinates, plus flags to indicate which currently reflect the
  310. position of the point. Some operations cause the polar coordinates to
  311. be updated from the rectangular, and some have the opposite effect.
  312. This implementation, which is in intended to give the minimum number
  313. of conversions between coordinate systems, has the property that not
  314. all the attributes stored in a <classname>Point</classname> object
  315. are necessary to give a canonical representation such as might be
  316. used for storing, comparing, cloning or making hash codes from
  317. points. Thus the aspects, though simple, are not totally trivial.
  318. </para>
  319. <para>
  320. The diagram below gives an overview of the aspects and their
  321. interaction with the class <classname>Point</classname>.</para>
  322. <para>
  323. <inlinemediaobject>
  324. <imageobject>
  325. <imagedata fileref="aspects.gif"/>
  326. </imageobject>
  327. </inlinemediaobject>
  328. </para>
  329. <para></para>
  330. </sect3>
  331. <sect3>
  332. <title>The <classname>CloneablePoint</classname> aspect</title>
  333. <para>
  334. This first aspect is responsible for
  335. <classname>Point</classname>'s implementation of the
  336. <classname>Cloneable</classname> interface. It declares that
  337. <literal>Point implements Cloneable</literal> with a
  338. <literal>declare parents</literal> form, and also publically
  339. declares a specialized <literal>Point</literal>'s
  340. <literal>clone()</literal> method. In Java, all objects inherit
  341. the method <literal>clone</literal> from the class
  342. <classname>Object</classname>, but an object is not cloneable
  343. unless its class also implements the interface
  344. <classname>Cloneable</classname>. In addition, classes
  345. frequently have requirements over and above the simple
  346. bit-for-bit copying that <literal>Object.clone</literal> does. In
  347. our case, we want to update a <classname>Point</classname>'s
  348. coordinate systems before we actually clone the
  349. <classname>Point</classname>. So our aspect makes sure that
  350. <literal>Point</literal> overrides
  351. <literal>Object.clone</literal> with a new method that does what
  352. we want.
  353. </para>
  354. <para>
  355. We also define a test <literal>main</literal> method in the
  356. aspect for convenience.
  357. </para>
  358. <programlisting><![CDATA[
  359. public aspect CloneablePoint {
  360. declare parents: Point implements Cloneable;
  361. public Object Point.clone() throws CloneNotSupportedException {
  362. // we choose to bring all fields up to date before cloning.
  363. makeRectangular();
  364. makePolar();
  365. return super.clone();
  366. }
  367. public static void main(String[] args){
  368. Point p1 = new Point();
  369. Point p2 = null;
  370. p1.setPolar(Math.PI, 1.0);
  371. try {
  372. p2 = (Point)p1.clone();
  373. } catch (CloneNotSupportedException e) {}
  374. System.out.println("p1 =" + p1 );
  375. System.out.println("p2 =" + p2 );
  376. p1.rotate(Math.PI / -2);
  377. System.out.println("p1 =" + p1 );
  378. System.out.println("p2 =" + p2 );
  379. }
  380. }
  381. ]]></programlisting>
  382. </sect3>
  383. <sect3>
  384. <title>The <classname>ComparablePoint</classname> aspect</title>
  385. <para>
  386. <classname>ComparablePoint</classname> is responsible for
  387. <literal>Point</literal>'s implementation of the
  388. <literal>Comparable</literal> interface. </para>
  389. <para>
  390. The interface <classname>Comparable</classname> defines the
  391. single method <literal>compareTo</literal> which can be use to define
  392. a natural ordering relation among the objects of a class that
  393. implement it.
  394. </para>
  395. <para>
  396. <classname>ComparablePoint</classname> uses <literal>declare
  397. parents</literal> to declare that <literal>Point implements
  398. Comparable</literal>, and also publically declares the
  399. appropriate <literal>compareTo(Object)</literal> method: A
  400. <classname>Point</classname> <literal>p1</literal> is said to be
  401. less than another <classname>Point</classname><literal>
  402. p2</literal> if <literal>p1</literal> is closer to the
  403. origin.
  404. </para>
  405. <para>
  406. We also define a test <literal>main</literal> method in the
  407. aspect for convenience.
  408. </para>
  409. <programlisting><![CDATA[
  410. public aspect ComparablePoint {
  411. declare parents: Point implements Comparable;
  412. public int Point.compareTo(Object o) {
  413. return (int) (this.getRho() - ((Point)o).getRho());
  414. }
  415. public static void main(String[] args){
  416. Point p1 = new Point();
  417. Point p2 = new Point();
  418. System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
  419. p1.setRectangular(2,5);
  420. p2.setRectangular(2,5);
  421. System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
  422. p2.setRectangular(3,6);
  423. System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
  424. p1.setPolar(Math.PI, 4);
  425. p2.setPolar(Math.PI, 4);
  426. System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
  427. p1.rotate(Math.PI / 4.0);
  428. System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
  429. p1.offset(1,1);
  430. System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
  431. }
  432. }
  433. ]]></programlisting>
  434. </sect3>
  435. <sect3>
  436. <title>The <classname>HashablePoint</classname> aspect</title>
  437. <para>
  438. Our third aspect is responsible for <literal>Point</literal>'s
  439. overriding of <literal>Object</literal>'s
  440. <literal>equals</literal> and <literal>hashCode</literal> methods
  441. in order to make <literal>Point</literal>s hashable.
  442. </para>
  443. <para>
  444. The method <literal>Object.hashCode</literal> returns an unique
  445. integer, suitable for use as a hash table key. Different
  446. implementations are allowed return different integers, but must
  447. return distinct integers for distinct objects, and the same integer
  448. for objects that test equal. But since the default implementation
  449. of <literal>Object.equal</literal> returns <literal>true</literal>
  450. only when two objects are identical, we need to redefine both
  451. <function>equals</function> and <function>hashCode</function> to work
  452. correctly with objects of type <classname>Point</classname>. For
  453. example, we want two <classname>Point</classname> objects to test
  454. equal when they have the same <literal>x</literal> and
  455. <literal>y</literal> values, or the same <literal>rho</literal> and
  456. <literal>theta</literal> values, not just when they refer to the same
  457. object. We do this by overriding the methods
  458. <literal>equals</literal> and <literal>hashCode</literal> in the
  459. class <classname>Point</classname>.
  460. </para>
  461. <para>
  462. So <classname>HashablePoint</classname> declares
  463. <literal>Point</literal>'s <literal>hashCode</literal> and
  464. <literal>equals</literal> methods, using
  465. <classname>Point</classname>'s rectangular coordinates to
  466. generate a hash code and to test for equality. The
  467. <literal>x</literal> and <literal>y</literal> coordinates are
  468. obtained using the appropriate get methods, which ensure the
  469. rectangular coordinates are up-to-date before returning their
  470. values.
  471. </para>
  472. <para>
  473. And again, we supply a <literal>main</literal> method in the
  474. aspect for testing.
  475. </para>
  476. <programlisting><![CDATA[
  477. public aspect HashablePoint {
  478. public int Point.hashCode() {
  479. return (int) (getX() + getY() % Integer.MAX_VALUE);
  480. }
  481. public boolean Point.equals(Object o) {
  482. if (o == this) { return true; }
  483. if (!(o instanceof Point)) { return false; }
  484. Point other = (Point)o;
  485. return (getX() == other.getX()) && (getY() == other.getY());
  486. }
  487. public static void main(String[] args) {
  488. Hashtable h = new Hashtable();
  489. Point p1 = new Point();
  490. p1.setRectangular(10, 10);
  491. Point p2 = new Point();
  492. p2.setRectangular(10, 10);
  493. System.out.println("p1 = " + p1);
  494. System.out.println("p2 = " + p2);
  495. System.out.println("p1.hashCode() = " + p1.hashCode());
  496. System.out.println("p2.hashCode() = " + p2.hashCode());
  497. h.put(p1, "P1");
  498. System.out.println("Got: " + h.get(p2));
  499. }
  500. }
  501. ]]></programlisting>
  502. </sect3>
  503. </sect2>
  504. </sect1>
  505. <!-- ============================================================ -->
  506. <!-- ============================================================ -->
  507. <sect1 id="examples-development">
  508. <title>Development Aspects</title>
  509. <sect2>
  510. <title>Tracing using aspects</title>
  511. <para>
  512. (The code for this example is in
  513. <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.)
  514. </para>
  515. <para>
  516. Writing a class that provides tracing functionality is easy: a
  517. couple of functions, a boolean flag for turning tracing on and
  518. off, a choice for an output stream, maybe some code for
  519. formatting the output -- these are all elements that
  520. <classname>Trace</classname> classes have been known to
  521. have. <classname>Trace</classname> classes may be highly
  522. sophisticated, too, if the task of tracing the execution of a
  523. program demands it.
  524. </para>
  525. <para>
  526. But developing the support for tracing is just one part of the
  527. effort of inserting tracing into a program, and, most likely, not
  528. the biggest part. The other part of the effort is calling the
  529. tracing functions at appropriate times. In large systems, this
  530. interaction with the tracing support can be overwhelming. Plus,
  531. tracing is one of those things that slows the system down, so
  532. these calls should often be pulled out of the system before the
  533. product is shipped. For these reasons, it is not unusual for
  534. developers to write ad-hoc scripting programs that rewrite the
  535. source code by inserting/deleting trace calls before and after
  536. the method bodies.
  537. </para>
  538. <para>
  539. AspectJ can be used for some of these tracing concerns in a less
  540. ad-hoc way. Tracing can be seen as a concern that crosscuts the
  541. entire system and as such is amenable to encapsulation in an
  542. aspect. In addition, it is fairly independent of what the system
  543. is doing. Therefore tracing is one of those kind of system
  544. aspects that can potentially be plugged in and unplugged without
  545. any side-effects in the basic functionality of the system.
  546. </para>
  547. <sect3>
  548. <title>An Example Application</title>
  549. <para>
  550. Throughout this example we will use a simple application that
  551. contains only four classes. The application is about shapes. The
  552. <classname>TwoDShape</classname> class is the root of the shape
  553. hierarchy:
  554. </para>
  555. <programlisting><![CDATA[
  556. public abstract class TwoDShape {
  557. protected double x, y;
  558. protected TwoDShape(double x, double y) {
  559. this.x = x; this.y = y;
  560. }
  561. public double getX() { return x; }
  562. public double getY() { return y; }
  563. public double distance(TwoDShape s) {
  564. double dx = Math.abs(s.getX() - x);
  565. double dy = Math.abs(s.getY() - y);
  566. return Math.sqrt(dx*dx + dy*dy);
  567. }
  568. public abstract double perimeter();
  569. public abstract double area();
  570. public String toString() {
  571. return (" @ (" + String.valueOf(x) + ", " + String.valueOf(y) + ") ");
  572. }
  573. }
  574. ]]></programlisting>
  575. <para>
  576. <classname>TwoDShape</classname> has two subclasses,
  577. <classname>Circle</classname> and <classname>Square</classname>:
  578. </para>
  579. <programlisting><![CDATA[
  580. public class Circle extends TwoDShape {
  581. protected double r;
  582. public Circle(double x, double y, double r) {
  583. super(x, y); this.r = r;
  584. }
  585. public Circle(double x, double y) { this( x, y, 1.0); }
  586. public Circle(double r) { this(0.0, 0.0, r); }
  587. public Circle() { this(0.0, 0.0, 1.0); }
  588. public double perimeter() {
  589. return 2 * Math.PI * r;
  590. }
  591. public double area() {
  592. return Math.PI * r*r;
  593. }
  594. public String toString() {
  595. return ("Circle radius = " + String.valueOf(r) + super.toString());
  596. }
  597. }
  598. ]]></programlisting>
  599. <programlisting><![CDATA[
  600. public class Square extends TwoDShape {
  601. protected double s; // side
  602. public Square(double x, double y, double s) {
  603. super(x, y); this.s = s;
  604. }
  605. public Square(double x, double y) { this( x, y, 1.0); }
  606. public Square(double s) { this(0.0, 0.0, s); }
  607. public Square() { this(0.0, 0.0, 1.0); }
  608. public double perimeter() {
  609. return 4 * s;
  610. }
  611. public double area() {
  612. return s*s;
  613. }
  614. public String toString() {
  615. return ("Square side = " + String.valueOf(s) + super.toString());
  616. }
  617. }
  618. ]]></programlisting>
  619. <para>
  620. To run this application, compile the classes. You can do it with or
  621. without ajc, the AspectJ compiler. If you've installed AspectJ, go
  622. to the directory
  623. <filename><replaceable>InstallDir</replaceable>/examples</filename>
  624. and type:
  625. </para>
  626. <programlisting>
  627. ajc -argfile tracing/notrace.lst
  628. </programlisting>
  629. <para>To run the program, type</para>
  630. <programlisting>
  631. java tracing.ExampleMain
  632. </programlisting>
  633. <para>(we don't need anything special on the classpath since this is pure
  634. Java code). You should see the following output:</para>
  635. <programlisting><![CDATA[
  636. c1.perimeter() = 12.566370614359172
  637. c1.area() = 12.566370614359172
  638. s1.perimeter() = 4.0
  639. s1.area() = 1.0
  640. c2.distance(c1) = 4.242640687119285
  641. s1.distance(c1) = 2.23606797749979
  642. s1.toString(): Square side = 1.0 @ (1.0, 2.0)
  643. ]]></programlisting>
  644. </sect3>
  645. <sect3>
  646. <title>Tracing&mdash;Version 1</title>
  647. <para>
  648. In a first attempt to insert tracing in this application, we will
  649. start by writing a <classname>Trace</classname> class that is
  650. exactly what we would write if we didn't have aspects. The
  651. implementation is in <filename>version1/Trace.java</filename>. Its
  652. public interface is:
  653. </para>
  654. <programlisting><![CDATA[
  655. public class Trace {
  656. public static int TRACELEVEL = 0;
  657. public static void initStream(PrintStream s) {...}
  658. public static void traceEntry(String str) {...}
  659. public static void traceExit(String str) {...}
  660. }
  661. ]]></programlisting>
  662. <para>
  663. If we didn't have AspectJ, we would have to insert calls to
  664. <literal>traceEntry</literal> and <literal>traceExit</literal> in
  665. all methods and constructors we wanted to trace, and to initialize
  666. <literal>TRACELEVEL</literal> and the stream. If we wanted to trace
  667. all the methods and constructors in our example, that would amount
  668. to around 40 calls, and we would hope we had not forgotten any
  669. method. But we can do that more consistently and reliably with the
  670. following aspect (found in
  671. <filename>version1/TraceMyClasses.java</filename>):
  672. </para>
  673. <programlisting><![CDATA[
  674. aspect TraceMyClasses {
  675. pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
  676. pointcut myConstructor(): myClass() && execution(new(..));
  677. pointcut myMethod(): myClass() && execution(* *(..));
  678. before (): myConstructor() {
  679. Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
  680. }
  681. after(): myConstructor() {
  682. Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
  683. }
  684. before (): myMethod() {
  685. Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
  686. }
  687. after(): myMethod() {
  688. Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
  689. }
  690. }]]></programlisting>
  691. <para>
  692. This aspect performs the tracing calls at appropriate
  693. times. According to this aspect, tracing is performed at the
  694. entrance and exit of every method and constructor defined within
  695. the shape hierarchy.
  696. </para>
  697. <para>
  698. What is printed at before and after each of the traced join points
  699. is the signature of the method executing. Since the signature is
  700. static information, we can get it through
  701. <literal>thisJoinPointStaticPart</literal>.
  702. </para>
  703. <para>
  704. To run this version of tracing, go to the directory
  705. <filename><replaceable>InstallDir</replaceable>/examples</filename>
  706. and type:
  707. </para>
  708. <programlisting><![CDATA[
  709. ajc -argfile tracing/tracev1.lst
  710. ]]></programlisting>
  711. <para>
  712. Running the main method of
  713. <classname>tracing.version1.TraceMyClasses</classname> should produce
  714. the output:
  715. </para>
  716. <programlisting><![CDATA[
  717. --> tracing.TwoDShape(double, double)
  718. <-- tracing.TwoDShape(double, double)
  719. --> tracing.Circle(double, double, double)
  720. <-- tracing.Circle(double, double, double)
  721. --> tracing.TwoDShape(double, double)
  722. <-- tracing.TwoDShape(double, double)
  723. --> tracing.Circle(double, double, double)
  724. <-- tracing.Circle(double, double, double)
  725. --> tracing.Circle(double)
  726. <-- tracing.Circle(double)
  727. --> tracing.TwoDShape(double, double)
  728. <-- tracing.TwoDShape(double, double)
  729. --> tracing.Square(double, double, double)
  730. <-- tracing.Square(double, double, double)
  731. --> tracing.Square(double, double)
  732. <-- tracing.Square(double, double)
  733. --> double tracing.Circle.perimeter()
  734. <-- double tracing.Circle.perimeter()
  735. c1.perimeter() = 12.566370614359172
  736. --> double tracing.Circle.area()
  737. <-- double tracing.Circle.area()
  738. c1.area() = 12.566370614359172
  739. --> double tracing.Square.perimeter()
  740. <-- double tracing.Square.perimeter()
  741. s1.perimeter() = 4.0
  742. --> double tracing.Square.area()
  743. <-- double tracing.Square.area()
  744. s1.area() = 1.0
  745. --> double tracing.TwoDShape.distance(TwoDShape)
  746. --> double tracing.TwoDShape.getX()
  747. <-- double tracing.TwoDShape.getX()
  748. --> double tracing.TwoDShape.getY()
  749. <-- double tracing.TwoDShape.getY()
  750. <-- double tracing.TwoDShape.distance(TwoDShape)
  751. c2.distance(c1) = 4.242640687119285
  752. --> double tracing.TwoDShape.distance(TwoDShape)
  753. --> double tracing.TwoDShape.getX()
  754. <-- double tracing.TwoDShape.getX()
  755. --> double tracing.TwoDShape.getY()
  756. <-- double tracing.TwoDShape.getY()
  757. <-- double tracing.TwoDShape.distance(TwoDShape)
  758. s1.distance(c1) = 2.23606797749979
  759. --> String tracing.Square.toString()
  760. --> String tracing.TwoDShape.toString()
  761. <-- String tracing.TwoDShape.toString()
  762. <-- String tracing.Square.toString()
  763. s1.toString(): Square side = 1.0 @ (1.0, 2.0)
  764. ]]></programlisting>
  765. <para>
  766. When <filename>TraceMyClasses.java</filename> is not provided to
  767. <command>ajc</command>, the aspect does not have any affect on the
  768. system and the tracing is unplugged.
  769. </para>
  770. </sect3>
  771. <sect3>
  772. <title>Tracing&mdash;Version 2</title>
  773. <para>
  774. Another way to accomplish the same thing would be to write a
  775. reusable tracing aspect that can be used not only for these
  776. application classes, but for any class. One way to do this is to
  777. merge the tracing functionality of
  778. <literal>Trace&mdash;version1</literal> with the crosscutting
  779. support of <literal>TraceMyClasses&mdash;version1</literal>. We end
  780. up with a <literal>Trace</literal> aspect (found in
  781. <filename>version2/Trace.java</filename>) with the following public
  782. interface
  783. </para>
  784. <programlisting><![CDATA[
  785. abstract aspect Trace {
  786. public static int TRACELEVEL = 2;
  787. public static void initStream(PrintStream s) {...}
  788. protected static void traceEntry(String str) {...}
  789. protected static void traceExit(String str) {...}
  790. abstract pointcut myClass();
  791. }
  792. ]]></programlisting>
  793. <para>
  794. In order to use it, we need to define our own subclass that knows
  795. about our application classes, in
  796. <filename>version2/TraceMyClasses.java</filename>:
  797. </para>
  798. <programlisting><![CDATA[
  799. public aspect TraceMyClasses extends Trace {
  800. pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
  801. public static void main(String[] args) {
  802. Trace.TRACELEVEL = 2;
  803. Trace.initStream(System.err);
  804. ExampleMain.main(args);
  805. }
  806. }
  807. ]]></programlisting>
  808. <para>
  809. Notice that we've simply made the pointcut
  810. <literal>classes</literal>, that was an abstract pointcut in the
  811. super-aspect, concrete. To run this version of tracing, go to the
  812. directory <filename>examples</filename> and type:
  813. </para>
  814. <programlisting><![CDATA[
  815. ajc -argfile tracing/tracev2.lst
  816. ]]></programlisting>
  817. <para>
  818. The file tracev2.lst lists the application classes as well as this
  819. version of the files Trace.java and TraceMyClasses.java. Running
  820. the main method of
  821. <classname>tracing.version2.TraceMyClasses</classname> should
  822. output exactly the same trace information as that from version 1.
  823. </para>
  824. <para>
  825. The entire implementation of the new <classname>Trace</classname>
  826. class is:
  827. </para>
  828. <programlisting><![CDATA[
  829. abstract aspect Trace {
  830. // implementation part
  831. public static int TRACELEVEL = 2;
  832. protected static PrintStream stream = System.err;
  833. protected static int callDepth = 0;
  834. public static void initStream(PrintStream s) {
  835. stream = s;
  836. }
  837. protected static void traceEntry(String str) {
  838. if (TRACELEVEL == 0) return;
  839. if (TRACELEVEL == 2) callDepth++;
  840. printEntering(str);
  841. }
  842. protected static void traceExit(String str) {
  843. if (TRACELEVEL == 0) return;
  844. printExiting(str);
  845. if (TRACELEVEL == 2) callDepth--;
  846. }
  847. private static void printEntering(String str) {
  848. printIndent();
  849. stream.println("--> " + str);
  850. }
  851. private static void printExiting(String str) {
  852. printIndent();
  853. stream.println("<-- " + str);
  854. }
  855. private static void printIndent() {
  856. for (int i = 0; i < callDepth; i++)
  857. stream.print(" ");
  858. }
  859. // protocol part
  860. abstract pointcut myClass();
  861. pointcut myConstructor(): myClass() && execution(new(..));
  862. pointcut myMethod(): myClass() && execution(* *(..));
  863. before(): myConstructor() {
  864. traceEntry("" + thisJoinPointStaticPart.getSignature());
  865. }
  866. after(): myConstructor() {
  867. traceExit("" + thisJoinPointStaticPart.getSignature());
  868. }
  869. before(): myMethod() {
  870. traceEntry("" + thisJoinPointStaticPart.getSignature());
  871. }
  872. after(): myMethod() {
  873. traceExit("" + thisJoinPointStaticPart.getSignature());
  874. }
  875. }
  876. ]]></programlisting>
  877. <para>
  878. This version differs from version 1 in several subtle ways. The
  879. first thing to notice is that this <classname>Trace</classname>
  880. class merges the functional part of tracing with the crosscutting
  881. of the tracing calls. That is, in version 1, there was a sharp
  882. separation between the tracing support (the class
  883. <classname>Trace</classname>) and the crosscutting usage of it (by
  884. the class <classname>TraceMyClasses</classname>). In this version
  885. those two things are merged. That's why the description of this
  886. class explicitly says that "Trace messages are printed before and
  887. after constructors and methods are," which is what we wanted in the
  888. first place. That is, the placement of the calls, in this version,
  889. is established by the aspect class itself, leaving less opportunity
  890. for misplacing calls.</para>
  891. <para>
  892. A consequence of this is that there is no need for providing
  893. <literal>traceEntry</literal> and <literal>traceExit</literal> as
  894. public operations of this class. You can see that they were
  895. classified as protected. They are supposed to be internal
  896. implementation details of the advice.
  897. </para>
  898. <para>
  899. The key piece of this aspect is the abstract pointcut classes that
  900. serves as the base for the definition of the pointcuts constructors
  901. and methods. Even though <classname>classes</classname> is
  902. abstract, and therefore no concrete classes are mentioned, we can
  903. put advice on it, as well as on the pointcuts that are based on
  904. it. The idea is "we don't know exactly what the pointcut will be,
  905. but when we do, here's what we want to do with it." In some ways,
  906. abstract pointcuts are similar to abstract methods. Abstract
  907. methods don't provide the implementation, but you know that the
  908. concrete subclasses will, so you can invoke those methods.
  909. </para>
  910. </sect3>
  911. </sect2>
  912. </sect1>
  913. <!-- ============================================================ -->
  914. <!-- ============================================================ -->
  915. <sect1 id="examples-production">
  916. <title>Production Aspects</title>
  917. <!-- ==================== -->
  918. <sect2><!-- A Bean Aspect -->
  919. <title>A Bean Aspect</title>
  920. <para>
  921. (The code for this example is in
  922. <filename><replaceable>InstallDir</replaceable>/examples/bean</filename>.)
  923. </para>
  924. <para>
  925. This example examines an aspect that makes Point objects into
  926. Java beans with bound properties.
  927. </para>
  928. <para>
  929. Java beans are reusable software components that can be visually
  930. manipulated in a builder tool. The requirements for an object to be
  931. a bean are few. Beans must define a no-argument constructor and
  932. must be either <classname>Serializable</classname> or
  933. <classname>Externalizable</classname>. Any properties of the object
  934. that are to be treated as bean properties should be indicated by
  935. the presence of appropriate <literal>get</literal> and
  936. <literal>set</literal> methods whose names are
  937. <literal>get</literal><emphasis>property</emphasis> and
  938. <literal>set </literal><emphasis>property</emphasis> where
  939. <emphasis>property</emphasis> is the name of a field in the bean
  940. class. Some bean properties, known as bound properties, fire events
  941. whenever their values change so that any registered listeners (such
  942. as, other beans) will be informed of those changes. Making a bound
  943. property involves keeping a list of registered listeners, and
  944. creating and dispatching event objects in methods that change the
  945. property values, such as set<emphasis>property</emphasis>
  946. methods.
  947. </para>
  948. <para>
  949. <classname>Point</classname> is a simple class representing points
  950. with rectangular coordinates. <classname>Point</classname> does not
  951. know anything about being a bean: there are set methods for
  952. <literal>x</literal> and <literal>y</literal> but they do not fire
  953. events, and the class is not serializable. Bound is an aspect that
  954. makes <classname>Point</classname> a serializable class and makes
  955. its <literal>get</literal> and <literal>set</literal> methods
  956. support the bound property protocol.
  957. </para>
  958. <sect3>
  959. <title>The <classname>Point</classname> class</title>
  960. <para>
  961. The <classname>Point</classname> class is a very simple class with
  962. trivial getters and setters, and a simple vector offset method.
  963. </para>
  964. <programlisting><![CDATA[
  965. class Point {
  966. protected int x = 0;
  967. protected int y = 0;
  968. public int getX() {
  969. return x;
  970. }
  971. public int getY() {
  972. return y;
  973. }
  974. public void setRectangular(int newX, int newY) {
  975. setX(newX);
  976. setY(newY);
  977. }
  978. public void setX(int newX) {
  979. x = newX;
  980. }
  981. public void setY(int newY) {
  982. y = newY;
  983. }
  984. public void offset(int deltaX, int deltaY) {
  985. setRectangular(x + deltaX, y + deltaY);
  986. }
  987. public String toString() {
  988. return "(" + getX() + ", " + getY() + ")" ;
  989. }
  990. }
  991. ]]></programlisting>
  992. </sect3>
  993. <sect3>
  994. <title>The <classname>BoundPoint</classname> aspect</title>
  995. <para>
  996. The <classname>BoundPoint</classname> aspect is responsible for
  997. <literal>Point</literal>'s "beanness". The first thing it does is
  998. privately declare that each <literal>Point</literal> has a
  999. <literal>support</literal> field that holds reference to an
  1000. instance of <classname>PropertyChangeSupport</classname>.
  1001. <programlisting><![CDATA[
  1002. private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
  1003. ]]></programlisting>
  1004. The property change support object must be constructed with a
  1005. reference to the bean for which it is providing support, so it is
  1006. initialized by passing it <literal>this</literal>, an instance of
  1007. <classname>Point</classname>. Since the <literal>support</literal>
  1008. field is private declared in the aspect, only the code in the
  1009. aspect can refer to it.
  1010. </para>
  1011. <para>
  1012. The aspect also declares <literal>Point</literal>'s methods for
  1013. registering and managing listeners for property change events,
  1014. which delegate the work to the property change support object:
  1015. <programlisting><![CDATA[
  1016. public void Point.addPropertyChangeListener(PropertyChangeListener listener){
  1017. support.addPropertyChangeListener(listener);
  1018. }
  1019. public void Point.addPropertyChangeListener(String propertyName,
  1020. PropertyChangeListener listener){
  1021. support.addPropertyChangeListener(propertyName, listener);
  1022. }
  1023. public void Point.removePropertyChangeListener(String propertyName,
  1024. PropertyChangeListener listener) {
  1025. support.removePropertyChangeListener(propertyName, listener);
  1026. }
  1027. public void Point.removePropertyChangeListener(PropertyChangeListener listener) {
  1028. support.removePropertyChangeListener(listener);
  1029. }
  1030. public void Point.hasListeners(String propertyName) {
  1031. support.hasListeners(propertyName);
  1032. }
  1033. ]]></programlisting>
  1034. </para>
  1035. <para>
  1036. The aspect is also responsible for making sure
  1037. <classname>Point</classname> implements the
  1038. <classname>Serializable</classname> interface:
  1039. <programlisting><![CDATA[
  1040. declare parents: Point implements Serializable;
  1041. ]]></programlisting>
  1042. Implementing this interface in Java does not require any methods to
  1043. be implemented. Serialization for <classname>Point</classname>
  1044. objects is provided by the default serialization method.
  1045. </para>
  1046. <para>
  1047. The <function>setters</function> pointcut picks out calls to the
  1048. <literal>Point</literal>'s <literal>set</literal> methods: any
  1049. method whose name begins with "<literal>set</literal>" and takes
  1050. one parameter. The around advice on <literal>setters()</literal>
  1051. stores the values of the <literal>X</literal> and
  1052. <literal>Y</literal> properties, calls the original
  1053. <literal>set</literal> method and then fires the appropriate
  1054. property change event according to which set method was
  1055. called.
  1056. </para>
  1057. <programlisting><![CDATA[
  1058. aspect BoundPoint {
  1059. private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
  1060. public void Point.addPropertyChangeListener(PropertyChangeListener listener){
  1061. support.addPropertyChangeListener(listener);
  1062. }
  1063. public void Point.addPropertyChangeListener(String propertyName,
  1064. PropertyChangeListener listener){
  1065. support.addPropertyChangeListener(propertyName, listener);
  1066. }
  1067. public void Point.removePropertyChangeListener(String propertyName,
  1068. PropertyChangeListener listener) {
  1069. support.removePropertyChangeListener(propertyName, listener);
  1070. }
  1071. public void Point.removePropertyChangeListener(PropertyChangeListener listener) {
  1072. support.removePropertyChangeListener(listener);
  1073. }
  1074. public void Point.hasListeners(String propertyName) {
  1075. support.hasListeners(propertyName);
  1076. }
  1077. declare parents: Point implements Serializable;
  1078. pointcut setter(Point p): call(void Point.set*(*)) && target(p);
  1079. void around(Point p): setter(p) {
  1080. String propertyName =
  1081. thisJoinPointStaticPart.getSignature().getName().substring("set".length());
  1082. int oldX = p.getX();
  1083. int oldY = p.getY();
  1084. proceed(p);
  1085. if (propertyName.equals("X")){
  1086. firePropertyChange(p, propertyName, oldX, p.getX());
  1087. } else {
  1088. firePropertyChange(p, propertyName, oldY, p.getY());
  1089. }
  1090. }
  1091. void firePropertyChange(Point p,
  1092. String property,
  1093. double oldval,
  1094. double newval) {
  1095. p.support.firePropertyChange(property,
  1096. new Double(oldval),
  1097. new Double(newval));
  1098. }
  1099. }
  1100. ]]></programlisting>
  1101. </sect3>
  1102. <sect3>
  1103. <title>The Test Program</title>
  1104. <para>
  1105. The test program registers itself as a property change listener to
  1106. a <literal>Point</literal> object that it creates and then performs
  1107. simple manipulation of that point: calling its set methods and the
  1108. offset method. Then it serializes the point and writes it to a file
  1109. and then reads it back. The result of saving and restoring the
  1110. point is that a new point is created.
  1111. </para>
  1112. <programlisting><![CDATA[
  1113. class Demo implements PropertyChangeListener {
  1114. static final String fileName = "test.tmp";
  1115. public void propertyChange(PropertyChangeEvent e){
  1116. System.out.println("Property " + e.getPropertyName() + " changed from " +
  1117. e.getOldValue() + " to " + e.getNewValue() );
  1118. }
  1119. public static void main(String[] args){
  1120. Point p1 = new Point();
  1121. p1.addPropertyChangeListener(new Demo());
  1122. System.out.println("p1 =" + p1);
  1123. p1.setRectangular(5,2);
  1124. System.out.println("p1 =" + p1);
  1125. p1.setX( 6 );
  1126. p1.setY( 3 );
  1127. System.out.println("p1 =" + p1);
  1128. p1.offset(6,4);
  1129. System.out.println("p1 =" + p1);
  1130. save(p1, fileName);
  1131. Point p2 = (Point) restore(fileName);
  1132. System.out.println("Had: " + p1);
  1133. System.out.println("Got: " + p2);
  1134. }
  1135. ...
  1136. }
  1137. ]]></programlisting>
  1138. </sect3>
  1139. <sect3>
  1140. <title>Compiling and Running the Example</title>
  1141. <para>
  1142. To compile and run this example, go to the examples directory and type:
  1143. </para>
  1144. <programlisting><![CDATA[
  1145. ajc -argfile bean/files.lst
  1146. java bean.Demo
  1147. ]]></programlisting>
  1148. </sect3>
  1149. </sect2>
  1150. <!-- ==================== -->
  1151. <sect2>
  1152. <title>The Subject/Observer Protocol</title>
  1153. <para>
  1154. (The code for this example is in
  1155. <filename><replaceable>InstallDir</replaceable>/examples/observer</filename>.)
  1156. </para>
  1157. <para>
  1158. This demo illustrates how the Subject/Observer design pattern can be
  1159. coded with aspects.
  1160. </para>
  1161. <para>
  1162. The demo consists of the following: A colored label is a
  1163. renderable object that has a color that cycles through a set of
  1164. colors, and a number that records the number of cycles it has been
  1165. through. A button is an action item that records when it is
  1166. clicked.
  1167. </para>
  1168. <para>
  1169. With these two kinds of objects, we can build up a Subject/Observer
  1170. relationship in which colored labels observe the clicks of buttons;
  1171. that is, where colored labels are the observers and buttons are the
  1172. subjects.
  1173. </para>
  1174. <para>
  1175. The demo is designed and implemented using the Subject/Observer
  1176. design pattern. The remainder of this example explains the classes
  1177. and aspects of this demo, and tells you how to run it.
  1178. </para>
  1179. <sect3>
  1180. <title>Generic Components</title>
  1181. <para>
  1182. The generic parts of the protocol are the interfaces
  1183. <classname>Subject</classname> and <classname>Observer</classname>,
  1184. and the abstract aspect
  1185. <classname>SubjectObserverProtocol</classname>. The
  1186. <classname>Subject</classname> interface is simple, containing
  1187. methods to add, remove, and view <classname>Observer</classname>
  1188. objects, and a method for getting data about state changes:
  1189. </para>
  1190. <programlisting><![CDATA[
  1191. interface Subject {
  1192. void addObserver(Observer obs);
  1193. void removeObserver(Observer obs);
  1194. Vector getObservers();
  1195. Object getData();
  1196. }
  1197. ]]></programlisting>
  1198. <para>
  1199. The <classname>Observer</classname> interface is just as simple,
  1200. with methods to set and get <classname>Subject</classname> objects,
  1201. and a method to call when the subject gets updated.
  1202. </para>
  1203. <programlisting><![CDATA[
  1204. interface Observer {
  1205. void setSubject(Subject s);
  1206. Subject getSubject();
  1207. void update();
  1208. }
  1209. ]]></programlisting>
  1210. <para>
  1211. The <classname>SubjectObserverProtocol</classname> aspect contains
  1212. within it all of the generic parts of the protocol, namely, how to
  1213. fire the <classname>Observer</classname> objects' update methods
  1214. when some state changes in a subject.
  1215. </para>
  1216. <programlisting><![CDATA[
  1217. abstract aspect SubjectObserverProtocol {
  1218. abstract pointcut stateChanges(Subject s);
  1219. after(Subject s): stateChanges(s) {
  1220. for (int i = 0; i < s.getObservers().size(); i++) {
  1221. ((Observer)s.getObservers().elementAt(i)).update();
  1222. }
  1223. }
  1224. private Vector Subject.observers = new Vector();
  1225. public void Subject.addObserver(Observer obs) {
  1226. observers.addElement(obs);
  1227. obs.setSubject(this);
  1228. }
  1229. public void Subject.removeObserver(Observer obs) {
  1230. observers.removeElement(obs);
  1231. obs.setSubject(null);
  1232. }
  1233. public Vector Subject.getObservers() { return observers; }
  1234. private Subject Observer.subject = null;
  1235. public void Observer.setSubject(Subject s) { subject = s; }
  1236. public Subject Observer.getSubject() { return subject; }
  1237. }
  1238. ]]></programlisting>
  1239. <para>
  1240. Note that this aspect does three things. It define an abstract
  1241. pointcut that extending aspects can override. It defines advice
  1242. that should run after the join points of the pointcut. And it
  1243. declares an inter-tpye field and two inter-type methods so that
  1244. each <literal>Observer</literal> can hold onto its <literal>Subject</literal>.
  1245. </para>
  1246. </sect3>
  1247. <sect3>
  1248. <title>Application Classes</title>
  1249. <para>
  1250. <classname>Button</classname> objects extend
  1251. <classname>java.awt.Button</classname>, and all they do is make
  1252. sure the <literal>void click()</literal> method is called whenever
  1253. a button is clicked.
  1254. </para>
  1255. <programlisting><![CDATA[
  1256. class Button extends java.awt.Button {
  1257. static final Color defaultBackgroundColor = Color.gray;
  1258. static final Color defaultForegroundColor = Color.black;
  1259. static final String defaultText = "cycle color";
  1260. Button(Display display) {
  1261. super();
  1262. setLabel(defaultText);
  1263. setBackground(defaultBackgroundColor);
  1264. setForeground(defaultForegroundColor);
  1265. addActionListener(new ActionListener() {
  1266. public void actionPerformed(ActionEvent e) {
  1267. Button.this.click();
  1268. }
  1269. });
  1270. display.addToFrame(this);
  1271. }
  1272. public void click() {}
  1273. }
  1274. ]]></programlisting>
  1275. <para>
  1276. Note that this class knows nothing about being a Subject.
  1277. </para>
  1278. <para>
  1279. ColorLabel objects are labels that support the void colorCycle()
  1280. method. Again, they know nothing about being an observer.
  1281. </para>
  1282. <programlisting><![CDATA[
  1283. class ColorLabel extends Label {
  1284. ColorLabel(Display display) {
  1285. super();
  1286. display.addToFrame(this);
  1287. }
  1288. final static Color[] colors = {Color.red, Color.blue,
  1289. Color.green, Color.magenta};
  1290. private int colorIndex = 0;
  1291. private int cycleCount = 0;
  1292. void colorCycle() {
  1293. cycleCount++;
  1294. colorIndex = (colorIndex + 1) % colors.length;
  1295. setBackground(colors[colorIndex]);
  1296. setText("" + cycleCount);
  1297. }
  1298. }
  1299. ]]></programlisting>
  1300. <para>
  1301. Finally, the <classname>SubjectObserverProtocolImpl</classname>
  1302. implements the subject/observer protocol, with
  1303. <classname>Button</classname> objects as subjects and
  1304. <classname>ColorLabel</classname> objects as observers:
  1305. </para>
  1306. <programlisting><![CDATA[
  1307. package observer;
  1308. import java.util.Vector;
  1309. aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol {
  1310. declare parents: Button implements Subject;
  1311. public Object Button.getData() { return this; }
  1312. declare parents: ColorLabel implements Observer;
  1313. public void ColorLabel.update() {
  1314. colorCycle();
  1315. }
  1316. pointcut stateChanges(Subject s):
  1317. target(s) &&
  1318. call(void Button.click());
  1319. }]]></programlisting>
  1320. <para>
  1321. It does this by assuring that <classname>Button</classname> and
  1322. <classname>ColorLabel</classname> implement the appropriate
  1323. interfaces, declaring that they implement the methods required by
  1324. those interfaces, and providing a definition for the abstract
  1325. <literal>stateChanges</literal> pointcut. Now, every time a
  1326. <classname>Button</classname> is clicked, all
  1327. <classname>ColorLabel</classname> objects observing that button
  1328. will <literal>colorCycle</literal>.
  1329. </para>
  1330. </sect3>
  1331. <sect3>
  1332. <title>Compiling and Running</title>
  1333. <para>
  1334. <classname>Demo</classname> is the top class that starts this
  1335. demo. It instantiates a two buttons and three observers and links
  1336. them together as subjects and observers. So to run the demo, go to
  1337. the <filename>examples</filename> directory and type:
  1338. </para>
  1339. <programlisting><![CDATA[
  1340. ajc -argfile observer/files.lst
  1341. java observer.Demo
  1342. ]]></programlisting>
  1343. </sect3>
  1344. </sect2>
  1345. <!-- ==================== -->
  1346. <sect2>
  1347. <title>A Simple Telecom Simulation</title>
  1348. <para>
  1349. (The code for this example is in
  1350. <filename><replaceable>InstallDir</replaceable>/examples/telecom</filename>.)
  1351. </para>
  1352. <para>
  1353. This example illustrates some ways that dependent concerns can be
  1354. encoded with aspects. It uses an example system comprising a simple
  1355. model of telephone connections to which timing and billing features
  1356. are added using aspects, where the billing feature depends upon the
  1357. timing feature.
  1358. </para>
  1359. <sect3>
  1360. <title>The Application</title>
  1361. <para>
  1362. The example application is a simple simulation of a telephony
  1363. system in which customers make, accept, merge and hang-up both
  1364. local and long distance calls. The application architecture is in
  1365. three layers.
  1366. </para>
  1367. <itemizedlist>
  1368. <listitem>
  1369. <para>
  1370. The basic objects provide basic functionality to simulate
  1371. customers, calls and connections (regular calls have one
  1372. connection, conference calls have more than one).
  1373. </para>
  1374. </listitem>
  1375. <listitem>
  1376. <para>
  1377. The timing feature is concerned with timing the connections
  1378. and keeping the total connection time per customer. Aspects
  1379. are used to add a timer to each connection and to manage the
  1380. total time per customer.
  1381. </para>
  1382. </listitem>
  1383. <listitem>
  1384. <para>
  1385. The billing feature is concerned with charging customers for
  1386. the calls they make. Aspects are used to calculate a charge
  1387. per connection and, upon termination of a connection, to add
  1388. the charge to the appropriate customer's bill. The billing
  1389. aspect builds upon the timing aspect: it uses a pointcut
  1390. defined in Timing and it uses the timers that are associated
  1391. with connections.
  1392. </para>
  1393. </listitem>
  1394. </itemizedlist>
  1395. <para>
  1396. The simulation of system has three configurations: basic, timing
  1397. and billing. Programs for the three configurations are in classes
  1398. <classname>BasicSimulation</classname>,
  1399. <classname>TimingSimulation</classname> and
  1400. <classname>BillingSimulation</classname>. These share a common
  1401. superclass <classname>AbstractSimulation</classname>, which
  1402. defines the method run with the simulation itself and the method
  1403. wait used to simulate elapsed time.
  1404. </para>
  1405. </sect3>
  1406. <sect3>
  1407. <title>The Basic Objects</title>
  1408. <para>
  1409. The telecom simulation comprises the classes
  1410. <classname>Customer</classname>, <classname>Call</classname> and
  1411. the abstract class <classname>Connection</classname> with its two
  1412. concrete subclasses <classname>Local</classname> and
  1413. <classname>LongDistance</classname>. Customers have a name and a
  1414. numeric area code. They also have methods for managing
  1415. calls. Simple calls are made between one customer (the caller)
  1416. and another (the receiver), a <classname>Connection</classname>
  1417. object is used to connect them. Conference calls between more
  1418. than two customers will involve more than one connection. A
  1419. customer may be involved in many calls at one time.
  1420. <inlinemediaobject>
  1421. <imageobject>
  1422. <imagedata fileref="telecom.gif"/>
  1423. </imageobject>
  1424. </inlinemediaobject>
  1425. </para>
  1426. </sect3>
  1427. <sect3>
  1428. <title>The <classname>Customer</classname> class</title>
  1429. <para>
  1430. <classname>Customer</classname> has methods
  1431. <literal>call</literal>, <literal>pickup</literal>,
  1432. <literal>hangup</literal> and <literal>merge</literal> for
  1433. managing calls.
  1434. </para>
  1435. <programlisting><![CDATA[
  1436. public class Customer {
  1437. private String name;
  1438. private int areacode;
  1439. private Vector calls = new Vector();
  1440. protected void removeCall(Call c){
  1441. calls.removeElement(c);
  1442. }
  1443. protected void addCall(Call c){
  1444. calls.addElement(c);
  1445. }
  1446. public Customer(String name, int areacode) {
  1447. this.name = name;
  1448. this.areacode = areacode;
  1449. }
  1450. public String toString() {
  1451. return name + "(" + areacode + ")";
  1452. }
  1453. public int getAreacode(){
  1454. return areacode;
  1455. }
  1456. public boolean localTo(Customer other){
  1457. return areacode == other.areacode;
  1458. }
  1459. public Call call(Customer receiver) {
  1460. Call call = new Call(this, receiver);
  1461. addCall(call);
  1462. return call;
  1463. }
  1464. public void pickup(Call call) {
  1465. call.pickup();
  1466. addCall(call);
  1467. }
  1468. public void hangup(Call call) {
  1469. call.hangup(this);
  1470. removeCall(call);
  1471. }
  1472. public void merge(Call call1, Call call2){
  1473. call1.merge(call2);
  1474. removeCall(call2);
  1475. }
  1476. }
  1477. ]]></programlisting>
  1478. </sect3>
  1479. <sect3>
  1480. <title>The <classname>Call</classname> class</title>
  1481. <para>
  1482. Calls are created with a caller and receiver who are customers. If
  1483. the caller and receiver have the same area code then the call can
  1484. be established with a <classname>Local</classname> connection (see
  1485. below), otherwise a <classname>LongDistance</classname> connection
  1486. is required. A call comprises a number of connections between
  1487. customers. Initially there is only the connection between the
  1488. caller and receiver but additional connections can be added if
  1489. calls are merged to form conference calls.
  1490. </para>
  1491. </sect3>
  1492. <sect3>
  1493. <title>The <classname>Connection</classname> class</title>
  1494. <para>
  1495. The class <classname>Connection</classname> models the physical
  1496. details of establishing a connection between customers. It does
  1497. this with a simple state machine (connections are initially
  1498. <literal>PENDING</literal>, then <literal>COMPLETED</literal> and
  1499. finally <literal>DROPPED</literal>). Messages are printed to the
  1500. console so that the state of connections can be
  1501. observed. Connection is an abstract class with two concrete
  1502. subclasses: <classname>Local</classname> and
  1503. <classname>LongDistance</classname>.
  1504. </para>
  1505. <programlisting><![CDATA[
  1506. abstract class Connection {
  1507. public static final int PENDING = 0;
  1508. public static final int COMPLETE = 1;
  1509. public static final int DROPPED = 2;
  1510. Customer caller, receiver;
  1511. private int state = PENDING;
  1512. Connection(Customer a, Customer b) {
  1513. this.caller = a;
  1514. this.receiver = b;
  1515. }
  1516. public int getState(){
  1517. return state;
  1518. }
  1519. public Customer getCaller() { return caller; }
  1520. public Customer getReceiver() { return receiver; }
  1521. void complete() {
  1522. state = COMPLETE;
  1523. System.out.println("connection completed");
  1524. }
  1525. void drop() {
  1526. state = DROPPED;
  1527. System.out.println("connection dropped");
  1528. }
  1529. public boolean connects(Customer c){
  1530. return (caller == c || receiver == c);
  1531. }
  1532. }
  1533. ]]></programlisting>
  1534. </sect3>
  1535. <sect3>
  1536. <title>The <literal>Local</literal> and <literal>LongDistance</literal> classes</title>
  1537. <para>
  1538. The two kinds of connections supported by our simulation are
  1539. <literal>Local</literal> and <literal>LongDistance</literal>
  1540. connections.
  1541. </para>
  1542. <programlisting><![CDATA[
  1543. class Local extends Connection {
  1544. Local(Customer a, Customer b) {
  1545. super(a, b);
  1546. System.out.println("[new local connection from " +
  1547. a + " to " + b + "]");
  1548. }
  1549. }
  1550. ]]></programlisting>
  1551. <programlisting><![CDATA[
  1552. class LongDistance extends Connection {
  1553. LongDistance(Customer a, Customer b) {
  1554. super(a, b);
  1555. System.out.println("[new long distance connection from " +
  1556. a + " to " + b + "]");
  1557. }
  1558. }
  1559. ]]></programlisting>
  1560. </sect3>
  1561. <sect3>
  1562. <title>Compiling and Running the Basic Simulation</title>
  1563. <para>
  1564. The source files for the basic system are listed in the file
  1565. <filename>basic.lst</filename>. To build and run the basic system,
  1566. in a shell window, type these commands:
  1567. </para>
  1568. <programlisting><![CDATA[
  1569. ajc -argfile telecom/basic.lst
  1570. java telecom.BasicSimulation
  1571. ]]></programlisting>
  1572. </sect3>
  1573. <sect3>
  1574. <title>The Timing aspect</title>
  1575. <para>
  1576. The <classname>Timing</classname> aspect keeps track of total
  1577. connection time for each <classname>Customer</classname> by
  1578. starting and stopping a timer associated with each connection. It
  1579. uses some helper classes:
  1580. </para>
  1581. <sect4>
  1582. <title>The <classname>Timer</classname> class</title>
  1583. <para>
  1584. A <classname>Timer</classname> object simply records the current
  1585. time when it is started and stopped, and returns their difference
  1586. when asked for the elapsed time. The aspect
  1587. <classname>TimerLog</classname> (below) can be used to cause the
  1588. start and stop times to be printed to standard output.
  1589. </para>
  1590. <programlisting><![CDATA[
  1591. class Timer {
  1592. long startTime, stopTime;
  1593. public void start() {
  1594. startTime = System.currentTimeMillis();
  1595. stopTime = startTime;
  1596. }
  1597. public void stop() {
  1598. stopTime = System.currentTimeMillis();
  1599. }
  1600. public long getTime() {
  1601. return stopTime - startTime;
  1602. }
  1603. }
  1604. ]]></programlisting>
  1605. </sect4>
  1606. </sect3>
  1607. <sect3>
  1608. <title>The <classname>TimerLog</classname> aspect</title>
  1609. <para>
  1610. The <classname>TimerLog</classname> aspect can be included in a
  1611. build to get the timer to announce when it is started and
  1612. stopped.
  1613. </para>
  1614. <programlisting><![CDATA[
  1615. public aspect TimerLog {
  1616. after(Timer t): target(t) && call(* Timer.start()) {
  1617. System.err.println("Timer started: " + t.startTime);
  1618. }
  1619. after(Timer t): target(t) && call(* Timer.stop()) {
  1620. System.err.println("Timer stopped: " + t.stopTime);
  1621. }
  1622. }
  1623. ]]></programlisting>
  1624. </sect3>
  1625. <sect3>
  1626. <title>The <classname>Timing</classname> aspect</title>
  1627. <para>
  1628. The <classname>Timing</classname> aspect is declares an
  1629. inter-type field <literal>totalConnectTime</literal> for
  1630. <classname>Customer</classname> to store the accumulated connection
  1631. time per <classname>Customer</classname>. It also declares that
  1632. each <classname>Connection</classname> object has a timer.
  1633. <programlisting><![CDATA[
  1634. public long Customer.totalConnectTime = 0;
  1635. private Timer Connection.timer = new Timer();
  1636. ]]></programlisting>
  1637. Two pieces of after advice ensure that the timer is started when
  1638. a connection is completed and and stopped when it is dropped. The
  1639. pointcut <literal>endTiming</literal> is defined so that it can
  1640. be used by the <classname>Billing</classname> aspect.
  1641. </para>
  1642. <programlisting><![CDATA[
  1643. public aspect Timing {
  1644. public long Customer.totalConnectTime = 0;
  1645. public long getTotalConnectTime(Customer cust) {
  1646. return cust.totalConnectTime;
  1647. }
  1648. private Timer Connection.timer = new Timer();
  1649. public Timer getTimer(Connection conn) { return conn.timer; }
  1650. after (Connection c): target(c) && call(void Connection.complete()) {
  1651. getTimer(c).start();
  1652. }
  1653. pointcut endTiming(Connection c): target(c) &&
  1654. call(void Connection.drop());
  1655. after(Connection c): endTiming(c) {
  1656. getTimer(c).stop();
  1657. c.getCaller().totalConnectTime += getTimer(c).getTime();
  1658. c.getReceiver().totalConnectTime += getTimer(c).getTime();
  1659. }
  1660. }]]></programlisting>
  1661. </sect3>
  1662. <sect3>
  1663. <title>The <literal>Billing</literal> aspect</title>
  1664. <para>
  1665. The Billing system adds billing functionality to the telecom
  1666. application on top of timing.
  1667. </para>
  1668. <para>
  1669. The <classname>Billing</classname> aspect declares that each
  1670. <classname>Connection</classname> has a <literal>payer</literal>
  1671. inter-type field to indicate who initiated the call and therefore
  1672. who is responsible to pay for it. It also declares the inter-type
  1673. method <literal>callRate</literal> of
  1674. <classname>Connection</classname> so that local and long distance
  1675. calls can be charged differently. The call charge must be
  1676. calculated after the timer is stopped; the after advice on pointcut
  1677. <literal>Timing.endTiming</literal> does this, and
  1678. <classname>Billing</classname> is declared to be more precedent
  1679. than <classname>Timing</classname> to make sure that this advice
  1680. runs after <classname>Timing</classname>'s advice on the same join
  1681. point. Finally, it declares inter-type methods and fields for
  1682. <classname>Customer</classname> to handle the
  1683. <literal>totalCharge</literal>.
  1684. </para>
  1685. <programlisting><![CDATA[
  1686. public aspect Billing {
  1687. // precedence required to get advice on endtiming in the right order
  1688. declare precedence: Billing, Timing;
  1689. public static final long LOCAL_RATE = 3;
  1690. public static final long LONG_DISTANCE_RATE = 10;
  1691. public Customer Connection.payer;
  1692. public Customer getPayer(Connection conn) { return conn.payer; }
  1693. after(Customer cust) returning (Connection conn):
  1694. args(cust, ..) && call(Connection+.new(..)) {
  1695. conn.payer = cust;
  1696. }
  1697. public abstract long Connection.callRate();
  1698. public long LongDistance.callRate() { return LONG_DISTANCE_RATE; }
  1699. public long Local.callRate() { return LOCAL_RATE; }
  1700. after(Connection conn): Timing.endTiming(conn) {
  1701. long time = Timing.aspectOf().getTimer(conn).getTime();
  1702. long rate = conn.callRate();
  1703. long cost = rate * time;
  1704. getPayer(conn).addCharge(cost);
  1705. }
  1706. public long Customer.totalCharge = 0;
  1707. public long getTotalCharge(Customer cust) { return cust.totalCharge; }
  1708. public void Customer.addCharge(long charge){
  1709. totalCharge += charge;
  1710. }
  1711. }
  1712. ]]></programlisting>
  1713. </sect3>
  1714. <sect3>
  1715. <title>Accessing the inter-type state</title>
  1716. <para>
  1717. Both the aspects <classname>Timing</classname> and
  1718. <classname>Billing</classname> contain the definition of operations
  1719. that the rest of the system may want to access. For example, when
  1720. running the simulation with one or both aspects, we want to find
  1721. out how much time each customer spent on the telephone and how big
  1722. their bill is. That information is also stored in the classes, but
  1723. they are accessed through static methods of the aspects, since the
  1724. state they refer to is private to the aspect.
  1725. </para>
  1726. <para>
  1727. Take a look at the file
  1728. <filename>TimingSimulation.java</filename>. The most important
  1729. method of this class is the method
  1730. <filename>report(Customer)</filename>, which is used in the method
  1731. run of the superclass
  1732. <classname>AbstractSimulation</classname>. This method is intended
  1733. to print out the status of the customer, with respect to the
  1734. <classname>Timing</classname> feature.
  1735. </para>
  1736. <programlisting><![CDATA[
  1737. protected void report(Customer c){
  1738. Timing t = Timing.aspectOf();
  1739. System.out.println(c + " spent " + t.getTotalConnectTime(c));
  1740. }
  1741. ]]></programlisting>
  1742. </sect3>
  1743. <sect3>
  1744. <title>Compiling and Running</title>
  1745. <para>
  1746. The files timing.lst and billing.lst contain file lists for the
  1747. timing and billing configurations. To build and run the application
  1748. with only the timing feature, go to the directory examples and
  1749. type:
  1750. </para>
  1751. <programlisting><![CDATA[
  1752. ajc -argfile telecom/timing.lst
  1753. java telecom.TimingSimulation
  1754. ]]></programlisting>
  1755. <para>
  1756. To build and run the application with the timing and billing
  1757. features, go to the directory examples and type:
  1758. </para>
  1759. <programlisting><![CDATA[
  1760. ajc -argfile telecom/billing.lst
  1761. java telecom.BillingSimulation
  1762. ]]></programlisting>
  1763. </sect3>
  1764. <sect3>
  1765. <title>Discussion</title>
  1766. <para>
  1767. There are some explicit dependencies between the aspects Billing
  1768. and Timing:
  1769. <itemizedlist>
  1770. <listitem>
  1771. <para>
  1772. Billing is declared more precedent than Timing so that Billing's
  1773. after advice runs after that of Timing when they are on the
  1774. same join point.
  1775. </para>
  1776. </listitem>
  1777. <listitem>
  1778. <para>
  1779. Billing uses the pointcut Timing.endTiming.
  1780. </para>
  1781. </listitem>
  1782. <listitem>
  1783. <para>
  1784. Billing needs access to the timer associated with a connection.
  1785. </para>
  1786. </listitem>
  1787. </itemizedlist>
  1788. </para>
  1789. </sect3>
  1790. </sect2>
  1791. </sect1>
  1792. <!-- ============================================================ -->
  1793. <!-- ============================================================ -->
  1794. <sect1 id="examples-reusable">
  1795. <title>Reusable Aspects</title>
  1796. <sect2>
  1797. <title>Tracing using Aspects, Revisited</title>
  1798. <para>
  1799. (The code for this example is in
  1800. <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.)
  1801. </para>
  1802. <sect3>
  1803. <title>Tracing&mdash;Version 3</title>
  1804. <para>
  1805. One advantage of not exposing the methods traceEntry and
  1806. traceExit as public operations is that we can easily change their
  1807. interface without any dramatic consequences in the rest of the
  1808. code.
  1809. </para>
  1810. <para>
  1811. Consider, again, the program without AspectJ. Suppose, for
  1812. example, that at some point later the requirements for tracing
  1813. change, stating that the trace messages should always include the
  1814. string representation of the object whose methods are being
  1815. traced. This can be achieved in at least two ways. One way is
  1816. keep the interface of the methods <literal>traceEntry</literal>
  1817. and <literal>traceExit</literal> as it was before,
  1818. </para>
  1819. <programlisting><![CDATA[
  1820. public static void traceEntry(String str);
  1821. public static void traceExit(String str);
  1822. ]]></programlisting>
  1823. <para>
  1824. In this case, the caller is responsible for ensuring that the
  1825. string representation of the object is part of the string given
  1826. as argument. So, calls must look like:
  1827. </para>
  1828. <programlisting><![CDATA[
  1829. Trace.traceEntry("Square.distance in " + toString());
  1830. ]]></programlisting>
  1831. <para>
  1832. Another way is to enforce the requirement with a second argument
  1833. in the trace operations, e.g.
  1834. </para>
  1835. <programlisting><![CDATA[
  1836. public static void traceEntry(String str, Object obj);
  1837. public static void traceExit(String str, Object obj);
  1838. ]]></programlisting>
  1839. <para>
  1840. In this case, the caller is still responsible for sending the
  1841. right object, but at least there is some guarantees that some
  1842. object will be passed. The calls will look like:
  1843. </para>
  1844. <programlisting><![CDATA[
  1845. Trace.traceEntry("Square.distance", this);
  1846. ]]></programlisting>
  1847. <para>
  1848. In either case, this change to the requirements of tracing will
  1849. have dramatic consequences in the rest of the code -- every call
  1850. to the trace operations traceEntry and traceExit must be changed!
  1851. </para>
  1852. <para>
  1853. Here's another advantage of doing tracing with an aspect. We've
  1854. already seen that in version 2 <literal>traceEntry</literal> and
  1855. <literal>traceExit</literal> are not publicly exposed. So
  1856. changing their interfaces, or the way they are used, has only a
  1857. small effect inside the <classname>Trace</classname>
  1858. class. Here's a partial view at the implementation of
  1859. <classname>Trace</classname>, version 3. The differences with
  1860. respect to version 2 are stressed in the comments:
  1861. </para>
  1862. <programlisting><![CDATA[
  1863. abstract aspect Trace {
  1864. public static int TRACELEVEL = 0;
  1865. protected static PrintStream stream = null;
  1866. protected static int callDepth = 0;
  1867. public static void initStream(PrintStream s) {
  1868. stream = s;
  1869. }
  1870. protected static void traceEntry(String str, Object o) {
  1871. if (TRACELEVEL == 0) return;
  1872. if (TRACELEVEL == 2) callDepth++;
  1873. printEntering(str + ": " + o.toString());
  1874. }
  1875. protected static void traceExit(String str, Object o) {
  1876. if (TRACELEVEL == 0) return;
  1877. printExiting(str + ": " + o.toString());
  1878. if (TRACELEVEL == 2) callDepth--;
  1879. }
  1880. private static void printEntering(String str) {
  1881. printIndent();
  1882. stream.println("Entering " + str);
  1883. }
  1884. private static void printExiting(String str) {
  1885. printIndent();
  1886. stream.println("Exiting " + str);
  1887. }
  1888. private static void printIndent() {
  1889. for (int i = 0; i < callDepth; i++)
  1890. stream.print(" ");
  1891. }
  1892. abstract pointcut myClass(Object obj);
  1893. pointcut myConstructor(Object obj): myClass(obj) && execution(new(..));
  1894. pointcut myMethod(Object obj): myClass(obj) &&
  1895. execution(* *(..)) && !execution(String toString());
  1896. before(Object obj): myConstructor(obj) {
  1897. traceEntry("" + thisJoinPointStaticPart.getSignature(), obj);
  1898. }
  1899. after(Object obj): myConstructor(obj) {
  1900. traceExit("" + thisJoinPointStaticPart.getSignature(), obj);
  1901. }
  1902. before(Object obj): myMethod(obj) {
  1903. traceEntry("" + thisJoinPointStaticPart.getSignature(), obj);
  1904. }
  1905. after(Object obj): myMethod(obj) {
  1906. traceExit("" + thisJoinPointStaticPart.getSignature(), obj);
  1907. }
  1908. }
  1909. ]]></programlisting>
  1910. <para>
  1911. As you can see, we decided to apply the first design by preserving
  1912. the interface of the methods <literal>traceEntry</literal> and
  1913. <literal>traceExit</literal>. But it doesn't matter&mdash;we could
  1914. as easily have applied the second design (the code in the directory
  1915. <filename>examples/tracing/version3</filename> has the second
  1916. design). The point is that the effects of this change in the
  1917. tracing requirements are limited to the
  1918. <classname>Trace</classname> aspect class.
  1919. </para>
  1920. <para>
  1921. One implementation change worth noticing is the specification of
  1922. the pointcuts. They now expose the object. To maintain full
  1923. consistency with the behavior of version 2, we should have included
  1924. tracing for static methods, by defining another pointcut for static
  1925. methods and advising it. We leave that as an exercise.
  1926. </para>
  1927. <para>
  1928. Moreover, we had to exclude the execution join point of the method
  1929. <filename>toString</filename> from the <literal>methods</literal>
  1930. pointcut. The problem here is that <literal>toString</literal> is
  1931. being called from inside the advice. Therefore if we trace it, we
  1932. will end up in an infinite recursion of calls. This is a subtle
  1933. point, and one that you must be aware when writing advice. If the
  1934. advice calls back to the objects, there is always the possibility
  1935. of recursion. Keep that in mind!
  1936. </para>
  1937. <para>
  1938. In fact, esimply excluding the execution join point may not be
  1939. enough, if there are calls to other traced methods within it -- in
  1940. which case, the restriction should be
  1941. </para>
  1942. <programlisting><![CDATA[
  1943. && !cflow(execution(String toString()))
  1944. ]]></programlisting>
  1945. <para>
  1946. excluding both the execution of toString methods and all join
  1947. points under that execution.
  1948. </para>
  1949. <para>
  1950. In summary, to implement the change in the tracing requirements we
  1951. had to make a couple of changes in the implementation of the
  1952. <classname>Trace</classname> aspect class, including changing the
  1953. specification of the pointcuts. That's only natural. But the
  1954. implementation changes were limited to this aspect. Without
  1955. aspects, we would have to change the implementation of every
  1956. application class.
  1957. </para>
  1958. <para>
  1959. Finally, to run this version of tracing, go to the directory
  1960. <filename>examples</filename> and type:
  1961. </para>
  1962. <programlisting><![CDATA[
  1963. ajc -argfile tracing/tracev3.lst
  1964. ]]></programlisting>
  1965. <para>
  1966. The file tracev3.lst lists the application classes as well as this
  1967. version of the files <filename>Trace.java</filename> and
  1968. <filename>TraceMyClasses.java</filename>. To run the program, type
  1969. </para>
  1970. <programlisting><![CDATA[
  1971. java tracing.version3.TraceMyClasses
  1972. ]]></programlisting>
  1973. <para>The output should be:</para>
  1974. <programlisting><![CDATA[
  1975. --> tracing.TwoDShape(double, double)
  1976. <-- tracing.TwoDShape(double, double)
  1977. --> tracing.Circle(double, double, double)
  1978. <-- tracing.Circle(double, double, double)
  1979. --> tracing.TwoDShape(double, double)
  1980. <-- tracing.TwoDShape(double, double)
  1981. --> tracing.Circle(double, double, double)
  1982. <-- tracing.Circle(double, double, double)
  1983. --> tracing.Circle(double)
  1984. <-- tracing.Circle(double)
  1985. --> tracing.TwoDShape(double, double)
  1986. <-- tracing.TwoDShape(double, double)
  1987. --> tracing.Square(double, double, double)
  1988. <-- tracing.Square(double, double, double)
  1989. --> tracing.Square(double, double)
  1990. <-- tracing.Square(double, double)
  1991. --> double tracing.Circle.perimeter()
  1992. <-- double tracing.Circle.perimeter()
  1993. c1.perimeter() = 12.566370614359172
  1994. --> double tracing.Circle.area()
  1995. <-- double tracing.Circle.area()
  1996. c1.area() = 12.566370614359172
  1997. --> double tracing.Square.perimeter()
  1998. <-- double tracing.Square.perimeter()
  1999. s1.perimeter() = 4.0
  2000. --> double tracing.Square.area()
  2001. <-- double tracing.Square.area()
  2002. s1.area() = 1.0
  2003. --> double tracing.TwoDShape.distance(TwoDShape)
  2004. --> double tracing.TwoDShape.getX()
  2005. <-- double tracing.TwoDShape.getX()
  2006. --> double tracing.TwoDShape.getY()
  2007. <-- double tracing.TwoDShape.getY()
  2008. <-- double tracing.TwoDShape.distance(TwoDShape)
  2009. c2.distance(c1) = 4.242640687119285
  2010. --> double tracing.TwoDShape.distance(TwoDShape)
  2011. --> double tracing.TwoDShape.getX()
  2012. <-- double tracing.TwoDShape.getX()
  2013. --> double tracing.TwoDShape.getY()
  2014. <-- double tracing.TwoDShape.getY()
  2015. <-- double tracing.TwoDShape.distance(TwoDShape)
  2016. s1.distance(c1) = 2.23606797749979
  2017. --> String tracing.Square.toString()
  2018. --> String tracing.TwoDShape.toString()
  2019. <-- String tracing.TwoDShape.toString()
  2020. <-- String tracing.Square.toString()
  2021. s1.toString(): Square side = 1.0 @ (1.0, 2.0)
  2022. ]]></programlisting>
  2023. </sect3>
  2024. </sect2>
  2025. </sect1>
  2026. </chapter>