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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443
  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
  445. integer, suitable for use as a hash table key. It is not required
  446. that two objects which are not equal (according to the
  447. <literal>equals</literal> method) return different integer
  448. results from <literal>hashCode</literal> but it can
  449. improve performance when the integer is used as a key into a
  450. data structure. However, any two objects which are equal
  451. must return the same integer value from a call to
  452. <literal>hashCode</literal>. Since the default implementation
  453. of <literal>Object.equals</literal> returns <literal>true</literal>
  454. only when two objects are identical, we need to redefine both
  455. <function>equals</function> and <function>hashCode</function> to work
  456. correctly with objects of type <classname>Point</classname>. For
  457. example, we want two <classname>Point</classname> objects to test
  458. equal when they have the same <literal>x</literal> and
  459. <literal>y</literal> values, or the same <literal>rho</literal> and
  460. <literal>theta</literal> values, not just when they refer to the same
  461. object. We do this by overriding the methods
  462. <literal>equals</literal> and <literal>hashCode</literal> in the
  463. class <classname>Point</classname>.
  464. </para>
  465. <para>
  466. So <classname>HashablePoint</classname> declares
  467. <literal>Point</literal>'s <literal>hashCode</literal> and
  468. <literal>equals</literal> methods, using
  469. <classname>Point</classname>'s rectangular coordinates to
  470. generate a hash code and to test for equality. The
  471. <literal>x</literal> and <literal>y</literal> coordinates are
  472. obtained using the appropriate get methods, which ensure the
  473. rectangular coordinates are up-to-date before returning their
  474. values.
  475. </para>
  476. <para>
  477. And again, we supply a <literal>main</literal> method in the
  478. aspect for testing.
  479. </para>
  480. <programlisting><![CDATA[
  481. public aspect HashablePoint {
  482. public int Point.hashCode() {
  483. return (int) (getX() + getY() % Integer.MAX_VALUE);
  484. }
  485. public boolean Point.equals(Object o) {
  486. if (o == this) { return true; }
  487. if (!(o instanceof Point)) { return false; }
  488. Point other = (Point)o;
  489. return (getX() == other.getX()) && (getY() == other.getY());
  490. }
  491. public static void main(String[] args) {
  492. Hashtable h = new Hashtable();
  493. Point p1 = new Point();
  494. p1.setRectangular(10, 10);
  495. Point p2 = new Point();
  496. p2.setRectangular(10, 10);
  497. System.out.println("p1 = " + p1);
  498. System.out.println("p2 = " + p2);
  499. System.out.println("p1.hashCode() = " + p1.hashCode());
  500. System.out.println("p2.hashCode() = " + p2.hashCode());
  501. h.put(p1, "P1");
  502. System.out.println("Got: " + h.get(p2));
  503. }
  504. }
  505. ]]></programlisting>
  506. </sect3>
  507. </sect2>
  508. </sect1>
  509. <!-- ============================================================ -->
  510. <!-- ============================================================ -->
  511. <sect1 id="examples-development">
  512. <title>Development Aspects</title>
  513. <sect2 id="tracing-using-aspects" xreflabel="tracing-using-aspects">
  514. <title>Tracing using aspects</title>
  515. <para>
  516. (The code for this example is in
  517. <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.)
  518. </para>
  519. <para>
  520. Writing a class that provides tracing functionality is easy: a
  521. couple of functions, a boolean flag for turning tracing on and
  522. off, a choice for an output stream, maybe some code for
  523. formatting the output -- these are all elements that
  524. <classname>Trace</classname> classes have been known to
  525. have. <classname>Trace</classname> classes may be highly
  526. sophisticated, too, if the task of tracing the execution of a
  527. program demands it.
  528. </para>
  529. <para>
  530. But developing the support for tracing is just one part of the
  531. effort of inserting tracing into a program, and, most likely, not
  532. the biggest part. The other part of the effort is calling the
  533. tracing functions at appropriate times. In large systems, this
  534. interaction with the tracing support can be overwhelming. Plus,
  535. tracing is one of those things that slows the system down, so
  536. these calls should often be pulled out of the system before the
  537. product is shipped. For these reasons, it is not unusual for
  538. developers to write ad-hoc scripting programs that rewrite the
  539. source code by inserting/deleting trace calls before and after
  540. the method bodies.
  541. </para>
  542. <para>
  543. AspectJ can be used for some of these tracing concerns in a less
  544. ad-hoc way. Tracing can be seen as a concern that crosscuts the
  545. entire system and as such is amenable to encapsulation in an
  546. aspect. In addition, it is fairly independent of what the system
  547. is doing. Therefore tracing is one of those kind of system
  548. aspects that can potentially be plugged in and unplugged without
  549. any side-effects in the basic functionality of the system.
  550. </para>
  551. <sect3>
  552. <title>An Example Application</title>
  553. <para>
  554. Throughout this example we will use a simple application that
  555. contains only four classes. The application is about shapes. The
  556. <classname>TwoDShape</classname> class is the root of the shape
  557. hierarchy:
  558. </para>
  559. <programlisting><![CDATA[
  560. public abstract class TwoDShape {
  561. protected double x, y;
  562. protected TwoDShape(double x, double y) {
  563. this.x = x; this.y = y;
  564. }
  565. public double getX() { return x; }
  566. public double getY() { return y; }
  567. public double distance(TwoDShape s) {
  568. double dx = Math.abs(s.getX() - x);
  569. double dy = Math.abs(s.getY() - y);
  570. return Math.sqrt(dx*dx + dy*dy);
  571. }
  572. public abstract double perimeter();
  573. public abstract double area();
  574. public String toString() {
  575. return (" @ (" + String.valueOf(x) + ", " + String.valueOf(y) + ") ");
  576. }
  577. }
  578. ]]></programlisting>
  579. <para>
  580. <classname>TwoDShape</classname> has two subclasses,
  581. <classname>Circle</classname> and <classname>Square</classname>:
  582. </para>
  583. <programlisting><![CDATA[
  584. public class Circle extends TwoDShape {
  585. protected double r;
  586. public Circle(double x, double y, double r) {
  587. super(x, y); this.r = r;
  588. }
  589. public Circle(double x, double y) { this( x, y, 1.0); }
  590. public Circle(double r) { this(0.0, 0.0, r); }
  591. public Circle() { this(0.0, 0.0, 1.0); }
  592. public double perimeter() {
  593. return 2 * Math.PI * r;
  594. }
  595. public double area() {
  596. return Math.PI * r*r;
  597. }
  598. public String toString() {
  599. return ("Circle radius = " + String.valueOf(r) + super.toString());
  600. }
  601. }
  602. ]]></programlisting>
  603. <programlisting><![CDATA[
  604. public class Square extends TwoDShape {
  605. protected double s; // side
  606. public Square(double x, double y, double s) {
  607. super(x, y); this.s = s;
  608. }
  609. public Square(double x, double y) { this( x, y, 1.0); }
  610. public Square(double s) { this(0.0, 0.0, s); }
  611. public Square() { this(0.0, 0.0, 1.0); }
  612. public double perimeter() {
  613. return 4 * s;
  614. }
  615. public double area() {
  616. return s*s;
  617. }
  618. public String toString() {
  619. return ("Square side = " + String.valueOf(s) + super.toString());
  620. }
  621. }
  622. ]]></programlisting>
  623. <para>
  624. To run this application, compile the classes. You can do it with or
  625. without ajc, the AspectJ compiler. If you've installed AspectJ, go
  626. to the directory
  627. <filename><replaceable>InstallDir</replaceable>/examples</filename>
  628. and type:
  629. </para>
  630. <programlisting>
  631. ajc -argfile tracing/notrace.lst
  632. </programlisting>
  633. <para>To run the program, type</para>
  634. <programlisting>
  635. java tracing.ExampleMain
  636. </programlisting>
  637. <para>(we don't need anything special on the classpath since this is pure
  638. Java code). You should see the following output:</para>
  639. <programlisting><![CDATA[
  640. c1.perimeter() = 12.566370614359172
  641. c1.area() = 12.566370614359172
  642. s1.perimeter() = 4.0
  643. s1.area() = 1.0
  644. c2.distance(c1) = 4.242640687119285
  645. s1.distance(c1) = 2.23606797749979
  646. s1.toString(): Square side = 1.0 @ (1.0, 2.0)
  647. ]]></programlisting>
  648. </sect3>
  649. <sect3>
  650. <title>Tracing&mdash;Version 1</title>
  651. <para>
  652. In a first attempt to insert tracing in this application, we will
  653. start by writing a <classname>Trace</classname> class that is
  654. exactly what we would write if we didn't have aspects. The
  655. implementation is in <filename>version1/Trace.java</filename>. Its
  656. public interface is:
  657. </para>
  658. <programlisting><![CDATA[
  659. public class Trace {
  660. public static int TRACELEVEL = 0;
  661. public static void initStream(PrintStream s) {...}
  662. public static void traceEntry(String str) {...}
  663. public static void traceExit(String str) {...}
  664. }
  665. ]]></programlisting>
  666. <para>
  667. If we didn't have AspectJ, we would have to insert calls to
  668. <literal>traceEntry</literal> and <literal>traceExit</literal> in
  669. all methods and constructors we wanted to trace, and to initialize
  670. <literal>TRACELEVEL</literal> and the stream. If we wanted to trace
  671. all the methods and constructors in our example, that would amount
  672. to around 40 calls, and we would hope we had not forgotten any
  673. method. But we can do that more consistently and reliably with the
  674. following aspect (found in
  675. <filename>version1/TraceMyClasses.java</filename>):
  676. </para>
  677. <programlisting><![CDATA[
  678. aspect TraceMyClasses {
  679. pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
  680. pointcut myConstructor(): myClass() && execution(new(..));
  681. pointcut myMethod(): myClass() && execution(* *(..));
  682. before (): myConstructor() {
  683. Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
  684. }
  685. after(): myConstructor() {
  686. Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
  687. }
  688. before (): myMethod() {
  689. Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
  690. }
  691. after(): myMethod() {
  692. Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
  693. }
  694. }]]></programlisting>
  695. <para>
  696. This aspect performs the tracing calls at appropriate
  697. times. According to this aspect, tracing is performed at the
  698. entrance and exit of every method and constructor defined within
  699. the shape hierarchy.
  700. </para>
  701. <para>
  702. What is printed at before and after each of the traced join points
  703. is the signature of the method executing. Since the signature is
  704. static information, we can get it through
  705. <literal>thisJoinPointStaticPart</literal>.
  706. </para>
  707. <para>
  708. To run this version of tracing, go to the directory
  709. <filename><replaceable>InstallDir</replaceable>/examples</filename>
  710. and type:
  711. </para>
  712. <programlisting><![CDATA[
  713. ajc -argfile tracing/tracev1.lst
  714. ]]></programlisting>
  715. <para>
  716. Running the main method of
  717. <classname>tracing.version1.TraceMyClasses</classname> should produce
  718. the output:
  719. </para>
  720. <programlisting><![CDATA[
  721. --> tracing.TwoDShape(double, double)
  722. <-- tracing.TwoDShape(double, double)
  723. --> tracing.Circle(double, double, double)
  724. <-- tracing.Circle(double, double, double)
  725. --> tracing.TwoDShape(double, double)
  726. <-- tracing.TwoDShape(double, double)
  727. --> tracing.Circle(double, double, double)
  728. <-- tracing.Circle(double, double, double)
  729. --> tracing.Circle(double)
  730. <-- tracing.Circle(double)
  731. --> tracing.TwoDShape(double, double)
  732. <-- tracing.TwoDShape(double, double)
  733. --> tracing.Square(double, double, double)
  734. <-- tracing.Square(double, double, double)
  735. --> tracing.Square(double, double)
  736. <-- tracing.Square(double, double)
  737. --> double tracing.Circle.perimeter()
  738. <-- double tracing.Circle.perimeter()
  739. c1.perimeter() = 12.566370614359172
  740. --> double tracing.Circle.area()
  741. <-- double tracing.Circle.area()
  742. c1.area() = 12.566370614359172
  743. --> double tracing.Square.perimeter()
  744. <-- double tracing.Square.perimeter()
  745. s1.perimeter() = 4.0
  746. --> double tracing.Square.area()
  747. <-- double tracing.Square.area()
  748. s1.area() = 1.0
  749. --> double tracing.TwoDShape.distance(TwoDShape)
  750. --> double tracing.TwoDShape.getX()
  751. <-- double tracing.TwoDShape.getX()
  752. --> double tracing.TwoDShape.getY()
  753. <-- double tracing.TwoDShape.getY()
  754. <-- double tracing.TwoDShape.distance(TwoDShape)
  755. c2.distance(c1) = 4.242640687119285
  756. --> double tracing.TwoDShape.distance(TwoDShape)
  757. --> double tracing.TwoDShape.getX()
  758. <-- double tracing.TwoDShape.getX()
  759. --> double tracing.TwoDShape.getY()
  760. <-- double tracing.TwoDShape.getY()
  761. <-- double tracing.TwoDShape.distance(TwoDShape)
  762. s1.distance(c1) = 2.23606797749979
  763. --> String tracing.Square.toString()
  764. --> String tracing.TwoDShape.toString()
  765. <-- String tracing.TwoDShape.toString()
  766. <-- String tracing.Square.toString()
  767. s1.toString(): Square side = 1.0 @ (1.0, 2.0)
  768. ]]></programlisting>
  769. <para>
  770. When <filename>TraceMyClasses.java</filename> is not provided to
  771. <command>ajc</command>, the aspect does not have any affect on the
  772. system and the tracing is unplugged.
  773. </para>
  774. </sect3>
  775. <sect3>
  776. <title>Tracing&mdash;Version 2</title>
  777. <para>
  778. Another way to accomplish the same thing would be to write a
  779. reusable tracing aspect that can be used not only for these
  780. application classes, but for any class. One way to do this is to
  781. merge the tracing functionality of
  782. <literal>Trace&mdash;version1</literal> with the crosscutting
  783. support of <literal>TraceMyClasses&mdash;version1</literal>. We end
  784. up with a <literal>Trace</literal> aspect (found in
  785. <filename>version2/Trace.java</filename>) with the following public
  786. interface
  787. </para>
  788. <programlisting><![CDATA[
  789. abstract aspect Trace {
  790. public static int TRACELEVEL = 2;
  791. public static void initStream(PrintStream s) {...}
  792. protected static void traceEntry(String str) {...}
  793. protected static void traceExit(String str) {...}
  794. abstract pointcut myClass();
  795. }
  796. ]]></programlisting>
  797. <para>
  798. In order to use it, we need to define our own subclass that knows
  799. about our application classes, in
  800. <filename>version2/TraceMyClasses.java</filename>:
  801. </para>
  802. <programlisting><![CDATA[
  803. public aspect TraceMyClasses extends Trace {
  804. pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
  805. public static void main(String[] args) {
  806. Trace.TRACELEVEL = 2;
  807. Trace.initStream(System.err);
  808. ExampleMain.main(args);
  809. }
  810. }
  811. ]]></programlisting>
  812. <para>
  813. Notice that we've simply made the pointcut
  814. <literal>classes</literal>, that was an abstract pointcut in the
  815. super-aspect, concrete. To run this version of tracing, go to the
  816. directory <filename>examples</filename> and type:
  817. </para>
  818. <programlisting><![CDATA[
  819. ajc -argfile tracing/tracev2.lst
  820. ]]></programlisting>
  821. <para>
  822. The file tracev2.lst lists the application classes as well as this
  823. version of the files Trace.java and TraceMyClasses.java. Running
  824. the main method of
  825. <classname>tracing.version2.TraceMyClasses</classname> should
  826. output exactly the same trace information as that from version 1.
  827. </para>
  828. <para>
  829. The entire implementation of the new <classname>Trace</classname>
  830. class is:
  831. </para>
  832. <programlisting><![CDATA[
  833. abstract aspect Trace {
  834. // implementation part
  835. public static int TRACELEVEL = 2;
  836. protected static PrintStream stream = System.err;
  837. protected static int callDepth = 0;
  838. public static void initStream(PrintStream s) {
  839. stream = s;
  840. }
  841. protected static void traceEntry(String str) {
  842. if (TRACELEVEL == 0) return;
  843. if (TRACELEVEL == 2) callDepth++;
  844. printEntering(str);
  845. }
  846. protected static void traceExit(String str) {
  847. if (TRACELEVEL == 0) return;
  848. printExiting(str);
  849. if (TRACELEVEL == 2) callDepth--;
  850. }
  851. private static void printEntering(String str) {
  852. printIndent();
  853. stream.println("--> " + str);
  854. }
  855. private static void printExiting(String str) {
  856. printIndent();
  857. stream.println("<-- " + str);
  858. }
  859. private static void printIndent() {
  860. for (int i = 0; i < callDepth; i++)
  861. stream.print(" ");
  862. }
  863. // protocol part
  864. abstract pointcut myClass();
  865. pointcut myConstructor(): myClass() && execution(new(..));
  866. pointcut myMethod(): myClass() && execution(* *(..));
  867. before(): myConstructor() {
  868. traceEntry("" + thisJoinPointStaticPart.getSignature());
  869. }
  870. after(): myConstructor() {
  871. traceExit("" + thisJoinPointStaticPart.getSignature());
  872. }
  873. before(): myMethod() {
  874. traceEntry("" + thisJoinPointStaticPart.getSignature());
  875. }
  876. after(): myMethod() {
  877. traceExit("" + thisJoinPointStaticPart.getSignature());
  878. }
  879. }
  880. ]]></programlisting>
  881. <para>
  882. This version differs from version 1 in several subtle ways. The
  883. first thing to notice is that this <classname>Trace</classname>
  884. class merges the functional part of tracing with the crosscutting
  885. of the tracing calls. That is, in version 1, there was a sharp
  886. separation between the tracing support (the class
  887. <classname>Trace</classname>) and the crosscutting usage of it (by
  888. the class <classname>TraceMyClasses</classname>). In this version
  889. those two things are merged. That's why the description of this
  890. class explicitly says that "Trace messages are printed before and
  891. after constructors and methods are," which is what we wanted in the
  892. first place. That is, the placement of the calls, in this version,
  893. is established by the aspect class itself, leaving less opportunity
  894. for misplacing calls.</para>
  895. <para>
  896. A consequence of this is that there is no need for providing
  897. <literal>traceEntry</literal> and <literal>traceExit</literal> as
  898. public operations of this class. You can see that they were
  899. classified as protected. They are supposed to be internal
  900. implementation details of the advice.
  901. </para>
  902. <para>
  903. The key piece of this aspect is the abstract pointcut classes that
  904. serves as the base for the definition of the pointcuts constructors
  905. and methods. Even though <classname>classes</classname> is
  906. abstract, and therefore no concrete classes are mentioned, we can
  907. put advice on it, as well as on the pointcuts that are based on
  908. it. The idea is "we don't know exactly what the pointcut will be,
  909. but when we do, here's what we want to do with it." In some ways,
  910. abstract pointcuts are similar to abstract methods. Abstract
  911. methods don't provide the implementation, but you know that the
  912. concrete subclasses will, so you can invoke those methods.
  913. </para>
  914. </sect3>
  915. </sect2>
  916. </sect1>
  917. <!-- ============================================================ -->
  918. <!-- ============================================================ -->
  919. <sect1 id="examples-production">
  920. <title>Production Aspects</title>
  921. <!-- ==================== -->
  922. <sect2 id="a-bean-aspect" xreflabel="a-bean-aspect"><!-- A Bean Aspect -->
  923. <title>A Bean Aspect</title>
  924. <para>
  925. (The code for this example is in
  926. <filename><replaceable>InstallDir</replaceable>/examples/bean</filename>.)
  927. </para>
  928. <para>
  929. This example examines an aspect that makes Point objects into
  930. Java beans with bound properties.
  931. </para>
  932. <para>
  933. Java beans are reusable software components that can be visually
  934. manipulated in a builder tool. The requirements for an object to be
  935. a bean are few. Beans must define a no-argument constructor and
  936. must be either <classname>Serializable</classname> or
  937. <classname>Externalizable</classname>. Any properties of the object
  938. that are to be treated as bean properties should be indicated by
  939. the presence of appropriate <literal>get</literal> and
  940. <literal>set</literal> methods whose names are
  941. <literal>get</literal><emphasis>property</emphasis> and
  942. <literal>set </literal><emphasis>property</emphasis> where
  943. <emphasis>property</emphasis> is the name of a field in the bean
  944. class. Some bean properties, known as bound properties, fire events
  945. whenever their values change so that any registered listeners (such
  946. as, other beans) will be informed of those changes. Making a bound
  947. property involves keeping a list of registered listeners, and
  948. creating and dispatching event objects in methods that change the
  949. property values, such as set<emphasis>property</emphasis>
  950. methods.
  951. </para>
  952. <para>
  953. <classname>Point</classname> is a simple class representing points
  954. with rectangular coordinates. <classname>Point</classname> does not
  955. know anything about being a bean: there are set methods for
  956. <literal>x</literal> and <literal>y</literal> but they do not fire
  957. events, and the class is not serializable. Bound is an aspect that
  958. makes <classname>Point</classname> a serializable class and makes
  959. its <literal>get</literal> and <literal>set</literal> methods
  960. support the bound property protocol.
  961. </para>
  962. <sect3>
  963. <title>The <classname>Point</classname> class</title>
  964. <para>
  965. The <classname>Point</classname> class is a very simple class with
  966. trivial getters and setters, and a simple vector offset method.
  967. </para>
  968. <programlisting><![CDATA[
  969. class Point {
  970. protected int x = 0;
  971. protected int y = 0;
  972. public int getX() {
  973. return x;
  974. }
  975. public int getY() {
  976. return y;
  977. }
  978. public void setRectangular(int newX, int newY) {
  979. setX(newX);
  980. setY(newY);
  981. }
  982. public void setX(int newX) {
  983. x = newX;
  984. }
  985. public void setY(int newY) {
  986. y = newY;
  987. }
  988. public void offset(int deltaX, int deltaY) {
  989. setRectangular(x + deltaX, y + deltaY);
  990. }
  991. public String toString() {
  992. return "(" + getX() + ", " + getY() + ")" ;
  993. }
  994. }
  995. ]]></programlisting>
  996. </sect3>
  997. <sect3>
  998. <title>The <classname>BoundPoint</classname> aspect</title>
  999. <para>
  1000. The <classname>BoundPoint</classname> aspect is responsible for
  1001. <literal>Point</literal>'s "beanness". The first thing it does is
  1002. privately declare that each <literal>Point</literal> has a
  1003. <literal>support</literal> field that holds reference to an
  1004. instance of <classname>PropertyChangeSupport</classname>.
  1005. <programlisting><![CDATA[
  1006. private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
  1007. ]]></programlisting>
  1008. The property change support object must be constructed with a
  1009. reference to the bean for which it is providing support, so it is
  1010. initialized by passing it <literal>this</literal>, an instance of
  1011. <classname>Point</classname>. Since the <literal>support</literal>
  1012. field is private declared in the aspect, only the code in the
  1013. aspect can refer to it.
  1014. </para>
  1015. <para>
  1016. The aspect also declares <literal>Point</literal>'s methods for
  1017. registering and managing listeners for property change events,
  1018. which delegate the work to the property change support object:
  1019. <programlisting><![CDATA[
  1020. public void Point.addPropertyChangeListener(PropertyChangeListener listener){
  1021. support.addPropertyChangeListener(listener);
  1022. }
  1023. public void Point.addPropertyChangeListener(String propertyName,
  1024. PropertyChangeListener listener){
  1025. support.addPropertyChangeListener(propertyName, listener);
  1026. }
  1027. public void Point.removePropertyChangeListener(String propertyName,
  1028. PropertyChangeListener listener) {
  1029. support.removePropertyChangeListener(propertyName, listener);
  1030. }
  1031. public void Point.removePropertyChangeListener(PropertyChangeListener listener) {
  1032. support.removePropertyChangeListener(listener);
  1033. }
  1034. public void Point.hasListeners(String propertyName) {
  1035. support.hasListeners(propertyName);
  1036. }
  1037. ]]></programlisting>
  1038. </para>
  1039. <para>
  1040. The aspect is also responsible for making sure
  1041. <classname>Point</classname> implements the
  1042. <classname>Serializable</classname> interface:
  1043. <programlisting><![CDATA[
  1044. declare parents: Point implements Serializable;
  1045. ]]></programlisting>
  1046. Implementing this interface in Java does not require any methods to
  1047. be implemented. Serialization for <classname>Point</classname>
  1048. objects is provided by the default serialization method.
  1049. </para>
  1050. <para>
  1051. The <function>setters</function> pointcut picks out calls to the
  1052. <literal>Point</literal>'s <literal>set</literal> methods: any
  1053. method whose name begins with "<literal>set</literal>" and takes
  1054. one parameter. The around advice on <literal>setters()</literal>
  1055. stores the values of the <literal>X</literal> and
  1056. <literal>Y</literal> properties, calls the original
  1057. <literal>set</literal> method and then fires the appropriate
  1058. property change event according to which set method was
  1059. called.
  1060. </para>
  1061. <programlisting><![CDATA[
  1062. aspect BoundPoint {
  1063. private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
  1064. public void Point.addPropertyChangeListener(PropertyChangeListener listener){
  1065. support.addPropertyChangeListener(listener);
  1066. }
  1067. public void Point.addPropertyChangeListener(String propertyName,
  1068. PropertyChangeListener listener){
  1069. support.addPropertyChangeListener(propertyName, listener);
  1070. }
  1071. public void Point.removePropertyChangeListener(String propertyName,
  1072. PropertyChangeListener listener) {
  1073. support.removePropertyChangeListener(propertyName, listener);
  1074. }
  1075. public void Point.removePropertyChangeListener(PropertyChangeListener listener) {
  1076. support.removePropertyChangeListener(listener);
  1077. }
  1078. public void Point.hasListeners(String propertyName) {
  1079. support.hasListeners(propertyName);
  1080. }
  1081. declare parents: Point implements Serializable;
  1082. pointcut setter(Point p): call(void Point.set*(*)) && target(p);
  1083. void around(Point p): setter(p) {
  1084. String propertyName =
  1085. thisJoinPointStaticPart.getSignature().getName().substring("set".length());
  1086. int oldX = p.getX();
  1087. int oldY = p.getY();
  1088. proceed(p);
  1089. if (propertyName.equals("X")){
  1090. firePropertyChange(p, propertyName, oldX, p.getX());
  1091. } else {
  1092. firePropertyChange(p, propertyName, oldY, p.getY());
  1093. }
  1094. }
  1095. void firePropertyChange(Point p,
  1096. String property,
  1097. double oldval,
  1098. double newval) {
  1099. p.support.firePropertyChange(property,
  1100. new Double(oldval),
  1101. new Double(newval));
  1102. }
  1103. }
  1104. ]]></programlisting>
  1105. </sect3>
  1106. <sect3>
  1107. <title>The Test Program</title>
  1108. <para>
  1109. The test program registers itself as a property change listener to
  1110. a <literal>Point</literal> object that it creates and then performs
  1111. simple manipulation of that point: calling its set methods and the
  1112. offset method. Then it serializes the point and writes it to a file
  1113. and then reads it back. The result of saving and restoring the
  1114. point is that a new point is created.
  1115. </para>
  1116. <programlisting><![CDATA[
  1117. class Demo implements PropertyChangeListener {
  1118. static final String fileName = "test.tmp";
  1119. public void propertyChange(PropertyChangeEvent e){
  1120. System.out.println("Property " + e.getPropertyName() + " changed from " +
  1121. e.getOldValue() + " to " + e.getNewValue() );
  1122. }
  1123. public static void main(String[] args){
  1124. Point p1 = new Point();
  1125. p1.addPropertyChangeListener(new Demo());
  1126. System.out.println("p1 =" + p1);
  1127. p1.setRectangular(5,2);
  1128. System.out.println("p1 =" + p1);
  1129. p1.setX( 6 );
  1130. p1.setY( 3 );
  1131. System.out.println("p1 =" + p1);
  1132. p1.offset(6,4);
  1133. System.out.println("p1 =" + p1);
  1134. save(p1, fileName);
  1135. Point p2 = (Point) restore(fileName);
  1136. System.out.println("Had: " + p1);
  1137. System.out.println("Got: " + p2);
  1138. }
  1139. ...
  1140. }
  1141. ]]></programlisting>
  1142. </sect3>
  1143. <sect3>
  1144. <title>Compiling and Running the Example</title>
  1145. <para>
  1146. To compile and run this example, go to the examples directory and type:
  1147. </para>
  1148. <programlisting><![CDATA[
  1149. ajc -argfile bean/files.lst
  1150. java bean.Demo
  1151. ]]></programlisting>
  1152. </sect3>
  1153. </sect2>
  1154. <!-- ==================== -->
  1155. <sect2 id="the-subject-observer-protocol" xreflabel="the-subject-observer-protocol">
  1156. <title>The Subject/Observer Protocol</title>
  1157. <para>
  1158. (The code for this example is in
  1159. <filename><replaceable>InstallDir</replaceable>/examples/observer</filename>.)
  1160. </para>
  1161. <para>
  1162. This demo illustrates how the Subject/Observer design pattern can be
  1163. coded with aspects.
  1164. </para>
  1165. <para>
  1166. The demo consists of the following: A colored label is a
  1167. renderable object that has a color that cycles through a set of
  1168. colors, and a number that records the number of cycles it has been
  1169. through. A button is an action item that records when it is
  1170. clicked.
  1171. </para>
  1172. <para>
  1173. With these two kinds of objects, we can build up a Subject/Observer
  1174. relationship in which colored labels observe the clicks of buttons;
  1175. that is, where colored labels are the observers and buttons are the
  1176. subjects.
  1177. </para>
  1178. <para>
  1179. The demo is designed and implemented using the Subject/Observer
  1180. design pattern. The remainder of this example explains the classes
  1181. and aspects of this demo, and tells you how to run it.
  1182. </para>
  1183. <sect3>
  1184. <title>Generic Components</title>
  1185. <para>
  1186. The generic parts of the protocol are the interfaces
  1187. <classname>Subject</classname> and <classname>Observer</classname>,
  1188. and the abstract aspect
  1189. <classname>SubjectObserverProtocol</classname>. The
  1190. <classname>Subject</classname> interface is simple, containing
  1191. methods to add, remove, and view <classname>Observer</classname>
  1192. objects, and a method for getting data about state changes:
  1193. </para>
  1194. <programlisting><![CDATA[
  1195. interface Subject {
  1196. void addObserver(Observer obs);
  1197. void removeObserver(Observer obs);
  1198. Vector getObservers();
  1199. Object getData();
  1200. }
  1201. ]]></programlisting>
  1202. <para>
  1203. The <classname>Observer</classname> interface is just as simple,
  1204. with methods to set and get <classname>Subject</classname> objects,
  1205. and a method to call when the subject gets updated.
  1206. </para>
  1207. <programlisting><![CDATA[
  1208. interface Observer {
  1209. void setSubject(Subject s);
  1210. Subject getSubject();
  1211. void update();
  1212. }
  1213. ]]></programlisting>
  1214. <para>
  1215. The <classname>SubjectObserverProtocol</classname> aspect contains
  1216. within it all of the generic parts of the protocol, namely, how to
  1217. fire the <classname>Observer</classname> objects' update methods
  1218. when some state changes in a subject.
  1219. </para>
  1220. <programlisting><![CDATA[
  1221. abstract aspect SubjectObserverProtocol {
  1222. abstract pointcut stateChanges(Subject s);
  1223. after(Subject s): stateChanges(s) {
  1224. for (int i = 0; i < s.getObservers().size(); i++) {
  1225. ((Observer)s.getObservers().elementAt(i)).update();
  1226. }
  1227. }
  1228. private Vector Subject.observers = new Vector();
  1229. public void Subject.addObserver(Observer obs) {
  1230. observers.addElement(obs);
  1231. obs.setSubject(this);
  1232. }
  1233. public void Subject.removeObserver(Observer obs) {
  1234. observers.removeElement(obs);
  1235. obs.setSubject(null);
  1236. }
  1237. public Vector Subject.getObservers() { return observers; }
  1238. private Subject Observer.subject = null;
  1239. public void Observer.setSubject(Subject s) { subject = s; }
  1240. public Subject Observer.getSubject() { return subject; }
  1241. }
  1242. ]]></programlisting>
  1243. <para>
  1244. Note that this aspect does three things. It define an abstract
  1245. pointcut that extending aspects can override. It defines advice
  1246. that should run after the join points of the pointcut. And it
  1247. declares an inter-tpye field and two inter-type methods so that
  1248. each <literal>Observer</literal> can hold onto its <literal>Subject</literal>.
  1249. </para>
  1250. </sect3>
  1251. <sect3>
  1252. <title>Application Classes</title>
  1253. <para>
  1254. <classname>Button</classname> objects extend
  1255. <classname>java.awt.Button</classname>, and all they do is make
  1256. sure the <literal>void click()</literal> method is called whenever
  1257. a button is clicked.
  1258. </para>
  1259. <programlisting><![CDATA[
  1260. class Button extends java.awt.Button {
  1261. static final Color defaultBackgroundColor = Color.gray;
  1262. static final Color defaultForegroundColor = Color.black;
  1263. static final String defaultText = "cycle color";
  1264. Button(Display display) {
  1265. super();
  1266. setLabel(defaultText);
  1267. setBackground(defaultBackgroundColor);
  1268. setForeground(defaultForegroundColor);
  1269. addActionListener(new ActionListener() {
  1270. public void actionPerformed(ActionEvent e) {
  1271. Button.this.click();
  1272. }
  1273. });
  1274. display.addToFrame(this);
  1275. }
  1276. public void click() {}
  1277. }
  1278. ]]></programlisting>
  1279. <para>
  1280. Note that this class knows nothing about being a Subject.
  1281. </para>
  1282. <para>
  1283. ColorLabel objects are labels that support the void colorCycle()
  1284. method. Again, they know nothing about being an observer.
  1285. </para>
  1286. <programlisting><![CDATA[
  1287. class ColorLabel extends Label {
  1288. ColorLabel(Display display) {
  1289. super();
  1290. display.addToFrame(this);
  1291. }
  1292. final static Color[] colors = {Color.red, Color.blue,
  1293. Color.green, Color.magenta};
  1294. private int colorIndex = 0;
  1295. private int cycleCount = 0;
  1296. void colorCycle() {
  1297. cycleCount++;
  1298. colorIndex = (colorIndex + 1) % colors.length;
  1299. setBackground(colors[colorIndex]);
  1300. setText("" + cycleCount);
  1301. }
  1302. }
  1303. ]]></programlisting>
  1304. <para>
  1305. Finally, the <classname>SubjectObserverProtocolImpl</classname>
  1306. implements the subject/observer protocol, with
  1307. <classname>Button</classname> objects as subjects and
  1308. <classname>ColorLabel</classname> objects as observers:
  1309. </para>
  1310. <programlisting><![CDATA[
  1311. package observer;
  1312. import java.util.Vector;
  1313. aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol {
  1314. declare parents: Button implements Subject;
  1315. public Object Button.getData() { return this; }
  1316. declare parents: ColorLabel implements Observer;
  1317. public void ColorLabel.update() {
  1318. colorCycle();
  1319. }
  1320. pointcut stateChanges(Subject s):
  1321. target(s) &&
  1322. call(void Button.click());
  1323. }]]></programlisting>
  1324. <para>
  1325. It does this by assuring that <classname>Button</classname> and
  1326. <classname>ColorLabel</classname> implement the appropriate
  1327. interfaces, declaring that they implement the methods required by
  1328. those interfaces, and providing a definition for the abstract
  1329. <literal>stateChanges</literal> pointcut. Now, every time a
  1330. <classname>Button</classname> is clicked, all
  1331. <classname>ColorLabel</classname> objects observing that button
  1332. will <literal>colorCycle</literal>.
  1333. </para>
  1334. </sect3>
  1335. <sect3>
  1336. <title>Compiling and Running</title>
  1337. <para>
  1338. <classname>Demo</classname> is the top class that starts this
  1339. demo. It instantiates a two buttons and three observers and links
  1340. them together as subjects and observers. So to run the demo, go to
  1341. the <filename>examples</filename> directory and type:
  1342. </para>
  1343. <programlisting><![CDATA[
  1344. ajc -argfile observer/files.lst
  1345. java observer.Demo
  1346. ]]></programlisting>
  1347. </sect3>
  1348. </sect2>
  1349. <!-- ==================== -->
  1350. <sect2 id="a-simple-telecom-simulation" xreflabel="a-simple-telecom-simulation">
  1351. <title>A Simple Telecom Simulation</title>
  1352. <para>
  1353. (The code for this example is in
  1354. <filename><replaceable>InstallDir</replaceable>/examples/telecom</filename>.)
  1355. </para>
  1356. <para>
  1357. This example illustrates some ways that dependent concerns can be
  1358. encoded with aspects. It uses an example system comprising a simple
  1359. model of telephone connections to which timing and billing features
  1360. are added using aspects, where the billing feature depends upon the
  1361. timing feature.
  1362. </para>
  1363. <sect3>
  1364. <title>The Application</title>
  1365. <para>
  1366. The example application is a simple simulation of a telephony
  1367. system in which customers make, accept, merge and hang-up both
  1368. local and long distance calls. The application architecture is in
  1369. three layers.
  1370. </para>
  1371. <itemizedlist>
  1372. <listitem>
  1373. <para>
  1374. The basic objects provide basic functionality to simulate
  1375. customers, calls and connections (regular calls have one
  1376. connection, conference calls have more than one).
  1377. </para>
  1378. </listitem>
  1379. <listitem>
  1380. <para>
  1381. The timing feature is concerned with timing the connections
  1382. and keeping the total connection time per customer. Aspects
  1383. are used to add a timer to each connection and to manage the
  1384. total time per customer.
  1385. </para>
  1386. </listitem>
  1387. <listitem>
  1388. <para>
  1389. The billing feature is concerned with charging customers for
  1390. the calls they make. Aspects are used to calculate a charge
  1391. per connection and, upon termination of a connection, to add
  1392. the charge to the appropriate customer's bill. The billing
  1393. aspect builds upon the timing aspect: it uses a pointcut
  1394. defined in Timing and it uses the timers that are associated
  1395. with connections.
  1396. </para>
  1397. </listitem>
  1398. </itemizedlist>
  1399. <para>
  1400. The simulation of system has three configurations: basic, timing
  1401. and billing. Programs for the three configurations are in classes
  1402. <classname>BasicSimulation</classname>,
  1403. <classname>TimingSimulation</classname> and
  1404. <classname>BillingSimulation</classname>. These share a common
  1405. superclass <classname>AbstractSimulation</classname>, which
  1406. defines the method run with the simulation itself and the method
  1407. wait used to simulate elapsed time.
  1408. </para>
  1409. </sect3>
  1410. <sect3>
  1411. <title>The Basic Objects</title>
  1412. <para>
  1413. The telecom simulation comprises the classes
  1414. <classname>Customer</classname>, <classname>Call</classname> and
  1415. the abstract class <classname>Connection</classname> with its two
  1416. concrete subclasses <classname>Local</classname> and
  1417. <classname>LongDistance</classname>. Customers have a name and a
  1418. numeric area code. They also have methods for managing
  1419. calls. Simple calls are made between one customer (the caller)
  1420. and another (the receiver), a <classname>Connection</classname>
  1421. object is used to connect them. Conference calls between more
  1422. than two customers will involve more than one connection. A
  1423. customer may be involved in many calls at one time.
  1424. <inlinemediaobject>
  1425. <imageobject>
  1426. <imagedata fileref="telecom.gif"/>
  1427. </imageobject>
  1428. </inlinemediaobject>
  1429. </para>
  1430. </sect3>
  1431. <sect3>
  1432. <title>The <classname>Customer</classname> class</title>
  1433. <para>
  1434. <classname>Customer</classname> has methods
  1435. <literal>call</literal>, <literal>pickup</literal>,
  1436. <literal>hangup</literal> and <literal>merge</literal> for
  1437. managing calls.
  1438. </para>
  1439. <programlisting><![CDATA[
  1440. public class Customer {
  1441. private String name;
  1442. private int areacode;
  1443. private Vector calls = new Vector();
  1444. protected void removeCall(Call c){
  1445. calls.removeElement(c);
  1446. }
  1447. protected void addCall(Call c){
  1448. calls.addElement(c);
  1449. }
  1450. public Customer(String name, int areacode) {
  1451. this.name = name;
  1452. this.areacode = areacode;
  1453. }
  1454. public String toString() {
  1455. return name + "(" + areacode + ")";
  1456. }
  1457. public int getAreacode(){
  1458. return areacode;
  1459. }
  1460. public boolean localTo(Customer other){
  1461. return areacode == other.areacode;
  1462. }
  1463. public Call call(Customer receiver) {
  1464. Call call = new Call(this, receiver);
  1465. addCall(call);
  1466. return call;
  1467. }
  1468. public void pickup(Call call) {
  1469. call.pickup();
  1470. addCall(call);
  1471. }
  1472. public void hangup(Call call) {
  1473. call.hangup(this);
  1474. removeCall(call);
  1475. }
  1476. public void merge(Call call1, Call call2){
  1477. call1.merge(call2);
  1478. removeCall(call2);
  1479. }
  1480. }
  1481. ]]></programlisting>
  1482. </sect3>
  1483. <sect3>
  1484. <title>The <classname>Call</classname> class</title>
  1485. <para>
  1486. Calls are created with a caller and receiver who are customers. If
  1487. the caller and receiver have the same area code then the call can
  1488. be established with a <classname>Local</classname> connection (see
  1489. below), otherwise a <classname>LongDistance</classname> connection
  1490. is required. A call comprises a number of connections between
  1491. customers. Initially there is only the connection between the
  1492. caller and receiver but additional connections can be added if
  1493. calls are merged to form conference calls.
  1494. </para>
  1495. </sect3>
  1496. <sect3>
  1497. <title>The <classname>Connection</classname> class</title>
  1498. <para>
  1499. The class <classname>Connection</classname> models the physical
  1500. details of establishing a connection between customers. It does
  1501. this with a simple state machine (connections are initially
  1502. <literal>PENDING</literal>, then <literal>COMPLETED</literal> and
  1503. finally <literal>DROPPED</literal>). Messages are printed to the
  1504. console so that the state of connections can be
  1505. observed. Connection is an abstract class with two concrete
  1506. subclasses: <classname>Local</classname> and
  1507. <classname>LongDistance</classname>.
  1508. </para>
  1509. <programlisting><![CDATA[
  1510. abstract class Connection {
  1511. public static final int PENDING = 0;
  1512. public static final int COMPLETE = 1;
  1513. public static final int DROPPED = 2;
  1514. Customer caller, receiver;
  1515. private int state = PENDING;
  1516. Connection(Customer a, Customer b) {
  1517. this.caller = a;
  1518. this.receiver = b;
  1519. }
  1520. public int getState(){
  1521. return state;
  1522. }
  1523. public Customer getCaller() { return caller; }
  1524. public Customer getReceiver() { return receiver; }
  1525. void complete() {
  1526. state = COMPLETE;
  1527. System.out.println("connection completed");
  1528. }
  1529. void drop() {
  1530. state = DROPPED;
  1531. System.out.println("connection dropped");
  1532. }
  1533. public boolean connects(Customer c){
  1534. return (caller == c || receiver == c);
  1535. }
  1536. }
  1537. ]]></programlisting>
  1538. </sect3>
  1539. <sect3>
  1540. <title>The <literal>Local</literal> and <literal>LongDistance</literal> classes</title>
  1541. <para>
  1542. The two kinds of connections supported by our simulation are
  1543. <literal>Local</literal> and <literal>LongDistance</literal>
  1544. connections.
  1545. </para>
  1546. <programlisting><![CDATA[
  1547. class Local extends Connection {
  1548. Local(Customer a, Customer b) {
  1549. super(a, b);
  1550. System.out.println("[new local connection from " +
  1551. a + " to " + b + "]");
  1552. }
  1553. }
  1554. ]]></programlisting>
  1555. <programlisting><![CDATA[
  1556. class LongDistance extends Connection {
  1557. LongDistance(Customer a, Customer b) {
  1558. super(a, b);
  1559. System.out.println("[new long distance connection from " +
  1560. a + " to " + b + "]");
  1561. }
  1562. }
  1563. ]]></programlisting>
  1564. </sect3>
  1565. <sect3>
  1566. <title>Compiling and Running the Basic Simulation</title>
  1567. <para>
  1568. The source files for the basic system are listed in the file
  1569. <filename>basic.lst</filename>. To build and run the basic system,
  1570. in a shell window, type these commands:
  1571. </para>
  1572. <programlisting><![CDATA[
  1573. ajc -argfile telecom/basic.lst
  1574. java telecom.BasicSimulation
  1575. ]]></programlisting>
  1576. </sect3>
  1577. <sect3>
  1578. <title>The Timing aspect</title>
  1579. <para>
  1580. The <classname>Timing</classname> aspect keeps track of total
  1581. connection time for each <classname>Customer</classname> by
  1582. starting and stopping a timer associated with each connection. It
  1583. uses some helper classes:
  1584. </para>
  1585. <sect4>
  1586. <title>The <classname>Timer</classname> class</title>
  1587. <para>
  1588. A <classname>Timer</classname> object simply records the current
  1589. time when it is started and stopped, and returns their difference
  1590. when asked for the elapsed time. The aspect
  1591. <classname>TimerLog</classname> (below) can be used to cause the
  1592. start and stop times to be printed to standard output.
  1593. </para>
  1594. <programlisting><![CDATA[
  1595. class Timer {
  1596. long startTime, stopTime;
  1597. public void start() {
  1598. startTime = System.currentTimeMillis();
  1599. stopTime = startTime;
  1600. }
  1601. public void stop() {
  1602. stopTime = System.currentTimeMillis();
  1603. }
  1604. public long getTime() {
  1605. return stopTime - startTime;
  1606. }
  1607. }
  1608. ]]></programlisting>
  1609. </sect4>
  1610. </sect3>
  1611. <sect3>
  1612. <title>The <classname>TimerLog</classname> aspect</title>
  1613. <para>
  1614. The <classname>TimerLog</classname> aspect can be included in a
  1615. build to get the timer to announce when it is started and
  1616. stopped.
  1617. </para>
  1618. <programlisting><![CDATA[
  1619. public aspect TimerLog {
  1620. after(Timer t): target(t) && call(* Timer.start()) {
  1621. System.err.println("Timer started: " + t.startTime);
  1622. }
  1623. after(Timer t): target(t) && call(* Timer.stop()) {
  1624. System.err.println("Timer stopped: " + t.stopTime);
  1625. }
  1626. }
  1627. ]]></programlisting>
  1628. </sect3>
  1629. <sect3>
  1630. <title>The <classname>Timing</classname> aspect</title>
  1631. <para>
  1632. The <classname>Timing</classname> aspect is declares an
  1633. inter-type field <literal>totalConnectTime</literal> for
  1634. <classname>Customer</classname> to store the accumulated connection
  1635. time per <classname>Customer</classname>. It also declares that
  1636. each <classname>Connection</classname> object has a timer.
  1637. <programlisting><![CDATA[
  1638. public long Customer.totalConnectTime = 0;
  1639. private Timer Connection.timer = new Timer();
  1640. ]]></programlisting>
  1641. Two pieces of after advice ensure that the timer is started when
  1642. a connection is completed and and stopped when it is dropped. The
  1643. pointcut <literal>endTiming</literal> is defined so that it can
  1644. be used by the <classname>Billing</classname> aspect.
  1645. </para>
  1646. <programlisting><![CDATA[
  1647. public aspect Timing {
  1648. public long Customer.totalConnectTime = 0;
  1649. public long getTotalConnectTime(Customer cust) {
  1650. return cust.totalConnectTime;
  1651. }
  1652. private Timer Connection.timer = new Timer();
  1653. public Timer getTimer(Connection conn) { return conn.timer; }
  1654. after (Connection c): target(c) && call(void Connection.complete()) {
  1655. getTimer(c).start();
  1656. }
  1657. pointcut endTiming(Connection c): target(c) &&
  1658. call(void Connection.drop());
  1659. after(Connection c): endTiming(c) {
  1660. getTimer(c).stop();
  1661. c.getCaller().totalConnectTime += getTimer(c).getTime();
  1662. c.getReceiver().totalConnectTime += getTimer(c).getTime();
  1663. }
  1664. }]]></programlisting>
  1665. </sect3>
  1666. <sect3>
  1667. <title>The <literal>Billing</literal> aspect</title>
  1668. <para>
  1669. The Billing system adds billing functionality to the telecom
  1670. application on top of timing.
  1671. </para>
  1672. <para>
  1673. The <classname>Billing</classname> aspect declares that each
  1674. <classname>Connection</classname> has a <literal>payer</literal>
  1675. inter-type field to indicate who initiated the call and therefore
  1676. who is responsible to pay for it. It also declares the inter-type
  1677. method <literal>callRate</literal> of
  1678. <classname>Connection</classname> so that local and long distance
  1679. calls can be charged differently. The call charge must be
  1680. calculated after the timer is stopped; the after advice on pointcut
  1681. <literal>Timing.endTiming</literal> does this, and
  1682. <classname>Billing</classname> is declared to be more precedent
  1683. than <classname>Timing</classname> to make sure that this advice
  1684. runs after <classname>Timing</classname>'s advice on the same join
  1685. point. Finally, it declares inter-type methods and fields for
  1686. <classname>Customer</classname> to handle the
  1687. <literal>totalCharge</literal>.
  1688. </para>
  1689. <programlisting><![CDATA[
  1690. public aspect Billing {
  1691. // precedence required to get advice on endtiming in the right order
  1692. declare precedence: Billing, Timing;
  1693. public static final long LOCAL_RATE = 3;
  1694. public static final long LONG_DISTANCE_RATE = 10;
  1695. public Customer Connection.payer;
  1696. public Customer getPayer(Connection conn) { return conn.payer; }
  1697. after(Customer cust) returning (Connection conn):
  1698. args(cust, ..) && call(Connection+.new(..)) {
  1699. conn.payer = cust;
  1700. }
  1701. public abstract long Connection.callRate();
  1702. public long LongDistance.callRate() { return LONG_DISTANCE_RATE; }
  1703. public long Local.callRate() { return LOCAL_RATE; }
  1704. after(Connection conn): Timing.endTiming(conn) {
  1705. long time = Timing.aspectOf().getTimer(conn).getTime();
  1706. long rate = conn.callRate();
  1707. long cost = rate * time;
  1708. getPayer(conn).addCharge(cost);
  1709. }
  1710. public long Customer.totalCharge = 0;
  1711. public long getTotalCharge(Customer cust) { return cust.totalCharge; }
  1712. public void Customer.addCharge(long charge){
  1713. totalCharge += charge;
  1714. }
  1715. }
  1716. ]]></programlisting>
  1717. </sect3>
  1718. <sect3>
  1719. <title>Accessing the inter-type state</title>
  1720. <para>
  1721. Both the aspects <classname>Timing</classname> and
  1722. <classname>Billing</classname> contain the definition of operations
  1723. that the rest of the system may want to access. For example, when
  1724. running the simulation with one or both aspects, we want to find
  1725. out how much time each customer spent on the telephone and how big
  1726. their bill is. That information is also stored in the classes, but
  1727. they are accessed through static methods of the aspects, since the
  1728. state they refer to is private to the aspect.
  1729. </para>
  1730. <para>
  1731. Take a look at the file
  1732. <filename>TimingSimulation.java</filename>. The most important
  1733. method of this class is the method
  1734. <filename>report(Customer)</filename>, which is used in the method
  1735. run of the superclass
  1736. <classname>AbstractSimulation</classname>. This method is intended
  1737. to print out the status of the customer, with respect to the
  1738. <classname>Timing</classname> feature.
  1739. </para>
  1740. <programlisting><![CDATA[
  1741. protected void report(Customer c){
  1742. Timing t = Timing.aspectOf();
  1743. System.out.println(c + " spent " + t.getTotalConnectTime(c));
  1744. }
  1745. ]]></programlisting>
  1746. </sect3>
  1747. <sect3>
  1748. <title>Compiling and Running</title>
  1749. <para>
  1750. The files timing.lst and billing.lst contain file lists for the
  1751. timing and billing configurations. To build and run the application
  1752. with only the timing feature, go to the directory examples and
  1753. type:
  1754. </para>
  1755. <programlisting><![CDATA[
  1756. ajc -argfile telecom/timing.lst
  1757. java telecom.TimingSimulation
  1758. ]]></programlisting>
  1759. <para>
  1760. To build and run the application with the timing and billing
  1761. features, go to the directory examples and type:
  1762. </para>
  1763. <programlisting><![CDATA[
  1764. ajc -argfile telecom/billing.lst
  1765. java telecom.BillingSimulation
  1766. ]]></programlisting>
  1767. </sect3>
  1768. <sect3>
  1769. <title>Discussion</title>
  1770. <para>
  1771. There are some explicit dependencies between the aspects Billing
  1772. and Timing:
  1773. <itemizedlist>
  1774. <listitem>
  1775. <para>
  1776. Billing is declared more precedent than Timing so that Billing's
  1777. after advice runs after that of Timing when they are on the
  1778. same join point.
  1779. </para>
  1780. </listitem>
  1781. <listitem>
  1782. <para>
  1783. Billing uses the pointcut Timing.endTiming.
  1784. </para>
  1785. </listitem>
  1786. <listitem>
  1787. <para>
  1788. Billing needs access to the timer associated with a connection.
  1789. </para>
  1790. </listitem>
  1791. </itemizedlist>
  1792. </para>
  1793. </sect3>
  1794. </sect2>
  1795. </sect1>
  1796. <!-- ============================================================ -->
  1797. <!-- ============================================================ -->
  1798. <sect1 id="examples-reusable">
  1799. <title>Reusable Aspects</title>
  1800. <sect2 id="tracing-using-aspects-revisited" xreflabel="tracing-using-aspects-revisited">
  1801. <title>Tracing using Aspects, Revisited</title>
  1802. <para>
  1803. (The code for this example is in
  1804. <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.)
  1805. </para>
  1806. <sect3>
  1807. <title>Tracing&mdash;Version 3</title>
  1808. <para>
  1809. One advantage of not exposing the methods traceEntry and
  1810. traceExit as public operations is that we can easily change their
  1811. interface without any dramatic consequences in the rest of the
  1812. code.
  1813. </para>
  1814. <para>
  1815. Consider, again, the program without AspectJ. Suppose, for
  1816. example, that at some point later the requirements for tracing
  1817. change, stating that the trace messages should always include the
  1818. string representation of the object whose methods are being
  1819. traced. This can be achieved in at least two ways. One way is
  1820. keep the interface of the methods <literal>traceEntry</literal>
  1821. and <literal>traceExit</literal> as it was before,
  1822. </para>
  1823. <programlisting><![CDATA[
  1824. public static void traceEntry(String str);
  1825. public static void traceExit(String str);
  1826. ]]></programlisting>
  1827. <para>
  1828. In this case, the caller is responsible for ensuring that the
  1829. string representation of the object is part of the string given
  1830. as argument. So, calls must look like:
  1831. </para>
  1832. <programlisting><![CDATA[
  1833. Trace.traceEntry("Square.distance in " + toString());
  1834. ]]></programlisting>
  1835. <para>
  1836. Another way is to enforce the requirement with a second argument
  1837. in the trace operations, e.g.
  1838. </para>
  1839. <programlisting><![CDATA[
  1840. public static void traceEntry(String str, Object obj);
  1841. public static void traceExit(String str, Object obj);
  1842. ]]></programlisting>
  1843. <para>
  1844. In this case, the caller is still responsible for sending the
  1845. right object, but at least there is some guarantees that some
  1846. object will be passed. The calls will look like:
  1847. </para>
  1848. <programlisting><![CDATA[
  1849. Trace.traceEntry("Square.distance", this);
  1850. ]]></programlisting>
  1851. <para>
  1852. In either case, this change to the requirements of tracing will
  1853. have dramatic consequences in the rest of the code -- every call
  1854. to the trace operations traceEntry and traceExit must be changed!
  1855. </para>
  1856. <para>
  1857. Here's another advantage of doing tracing with an aspect. We've
  1858. already seen that in version 2 <literal>traceEntry</literal> and
  1859. <literal>traceExit</literal> are not publicly exposed. So
  1860. changing their interfaces, or the way they are used, has only a
  1861. small effect inside the <classname>Trace</classname>
  1862. class. Here's a partial view at the implementation of
  1863. <classname>Trace</classname>, version 3. The differences with
  1864. respect to version 2 are stressed in the comments:
  1865. </para>
  1866. <programlisting><![CDATA[
  1867. abstract aspect Trace {
  1868. public static int TRACELEVEL = 0;
  1869. protected static PrintStream stream = null;
  1870. protected static int callDepth = 0;
  1871. public static void initStream(PrintStream s) {
  1872. stream = s;
  1873. }
  1874. protected static void traceEntry(String str, Object o) {
  1875. if (TRACELEVEL == 0) return;
  1876. if (TRACELEVEL == 2) callDepth++;
  1877. printEntering(str + ": " + o.toString());
  1878. }
  1879. protected static void traceExit(String str, Object o) {
  1880. if (TRACELEVEL == 0) return;
  1881. printExiting(str + ": " + o.toString());
  1882. if (TRACELEVEL == 2) callDepth--;
  1883. }
  1884. private static void printEntering(String str) {
  1885. printIndent();
  1886. stream.println("Entering " + str);
  1887. }
  1888. private static void printExiting(String str) {
  1889. printIndent();
  1890. stream.println("Exiting " + str);
  1891. }
  1892. private static void printIndent() {
  1893. for (int i = 0; i < callDepth; i++)
  1894. stream.print(" ");
  1895. }
  1896. abstract pointcut myClass(Object obj);
  1897. pointcut myConstructor(Object obj): myClass(obj) && execution(new(..));
  1898. pointcut myMethod(Object obj): myClass(obj) &&
  1899. execution(* *(..)) && !execution(String toString());
  1900. before(Object obj): myConstructor(obj) {
  1901. traceEntry("" + thisJoinPointStaticPart.getSignature(), obj);
  1902. }
  1903. after(Object obj): myConstructor(obj) {
  1904. traceExit("" + thisJoinPointStaticPart.getSignature(), obj);
  1905. }
  1906. before(Object obj): myMethod(obj) {
  1907. traceEntry("" + thisJoinPointStaticPart.getSignature(), obj);
  1908. }
  1909. after(Object obj): myMethod(obj) {
  1910. traceExit("" + thisJoinPointStaticPart.getSignature(), obj);
  1911. }
  1912. }
  1913. ]]></programlisting>
  1914. <para>
  1915. As you can see, we decided to apply the first design by preserving
  1916. the interface of the methods <literal>traceEntry</literal> and
  1917. <literal>traceExit</literal>. But it doesn't matter&mdash;we could
  1918. as easily have applied the second design (the code in the directory
  1919. <filename>examples/tracing/version3</filename> has the second
  1920. design). The point is that the effects of this change in the
  1921. tracing requirements are limited to the
  1922. <classname>Trace</classname> aspect class.
  1923. </para>
  1924. <para>
  1925. One implementation change worth noticing is the specification of
  1926. the pointcuts. They now expose the object. To maintain full
  1927. consistency with the behavior of version 2, we should have included
  1928. tracing for static methods, by defining another pointcut for static
  1929. methods and advising it. We leave that as an exercise.
  1930. </para>
  1931. <para>
  1932. Moreover, we had to exclude the execution join point of the method
  1933. <filename>toString</filename> from the <literal>methods</literal>
  1934. pointcut. The problem here is that <literal>toString</literal> is
  1935. being called from inside the advice. Therefore if we trace it, we
  1936. will end up in an infinite recursion of calls. This is a subtle
  1937. point, and one that you must be aware when writing advice. If the
  1938. advice calls back to the objects, there is always the possibility
  1939. of recursion. Keep that in mind!
  1940. </para>
  1941. <para>
  1942. In fact, esimply excluding the execution join point may not be
  1943. enough, if there are calls to other traced methods within it -- in
  1944. which case, the restriction should be
  1945. </para>
  1946. <programlisting><![CDATA[
  1947. && !cflow(execution(String toString()))
  1948. ]]></programlisting>
  1949. <para>
  1950. excluding both the execution of toString methods and all join
  1951. points under that execution.
  1952. </para>
  1953. <para>
  1954. In summary, to implement the change in the tracing requirements we
  1955. had to make a couple of changes in the implementation of the
  1956. <classname>Trace</classname> aspect class, including changing the
  1957. specification of the pointcuts. That's only natural. But the
  1958. implementation changes were limited to this aspect. Without
  1959. aspects, we would have to change the implementation of every
  1960. application class.
  1961. </para>
  1962. <para>
  1963. Finally, to run this version of tracing, go to the directory
  1964. <filename>examples</filename> and type:
  1965. </para>
  1966. <programlisting><![CDATA[
  1967. ajc -argfile tracing/tracev3.lst
  1968. ]]></programlisting>
  1969. <para>
  1970. The file tracev3.lst lists the application classes as well as this
  1971. version of the files <filename>Trace.java</filename> and
  1972. <filename>TraceMyClasses.java</filename>. To run the program, type
  1973. </para>
  1974. <programlisting><![CDATA[
  1975. java tracing.version3.TraceMyClasses
  1976. ]]></programlisting>
  1977. <para>The output should be:</para>
  1978. <programlisting><![CDATA[
  1979. --> tracing.TwoDShape(double, double)
  1980. <-- tracing.TwoDShape(double, double)
  1981. --> tracing.Circle(double, double, double)
  1982. <-- tracing.Circle(double, double, double)
  1983. --> tracing.TwoDShape(double, double)
  1984. <-- tracing.TwoDShape(double, double)
  1985. --> tracing.Circle(double, double, double)
  1986. <-- tracing.Circle(double, double, double)
  1987. --> tracing.Circle(double)
  1988. <-- tracing.Circle(double)
  1989. --> tracing.TwoDShape(double, double)
  1990. <-- tracing.TwoDShape(double, double)
  1991. --> tracing.Square(double, double, double)
  1992. <-- tracing.Square(double, double, double)
  1993. --> tracing.Square(double, double)
  1994. <-- tracing.Square(double, double)
  1995. --> double tracing.Circle.perimeter()
  1996. <-- double tracing.Circle.perimeter()
  1997. c1.perimeter() = 12.566370614359172
  1998. --> double tracing.Circle.area()
  1999. <-- double tracing.Circle.area()
  2000. c1.area() = 12.566370614359172
  2001. --> double tracing.Square.perimeter()
  2002. <-- double tracing.Square.perimeter()
  2003. s1.perimeter() = 4.0
  2004. --> double tracing.Square.area()
  2005. <-- double tracing.Square.area()
  2006. s1.area() = 1.0
  2007. --> double tracing.TwoDShape.distance(TwoDShape)
  2008. --> double tracing.TwoDShape.getX()
  2009. <-- double tracing.TwoDShape.getX()
  2010. --> double tracing.TwoDShape.getY()
  2011. <-- double tracing.TwoDShape.getY()
  2012. <-- double tracing.TwoDShape.distance(TwoDShape)
  2013. c2.distance(c1) = 4.242640687119285
  2014. --> double tracing.TwoDShape.distance(TwoDShape)
  2015. --> double tracing.TwoDShape.getX()
  2016. <-- double tracing.TwoDShape.getX()
  2017. --> double tracing.TwoDShape.getY()
  2018. <-- double tracing.TwoDShape.getY()
  2019. <-- double tracing.TwoDShape.distance(TwoDShape)
  2020. s1.distance(c1) = 2.23606797749979
  2021. --> String tracing.Square.toString()
  2022. --> String tracing.TwoDShape.toString()
  2023. <-- String tracing.TwoDShape.toString()
  2024. <-- String tracing.Square.toString()
  2025. s1.toString(): Square side = 1.0 @ (1.0, 2.0)
  2026. ]]></programlisting>
  2027. </sect3>
  2028. </sect2>
  2029. </sect1>
  2030. </chapter>