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.

преди 20 години
преди 18 години
преди 20 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 20 години
преди 18 години
преди 18 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 20 години
преди 20 години
преди 18 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 18 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 18 години
преди 18 години
преди 20 години
преди 20 години
преди 18 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
преди 20 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * Mik Kersten port to AspectJ 1.1+ code base
  13. * ******************************************************************/
  14. package org.aspectj.tools.ajdoc;
  15. import java.io.BufferedReader;
  16. import java.io.DataInputStream;
  17. import java.io.File;
  18. import java.io.FileOutputStream;
  19. import java.io.FileReader;
  20. import java.io.IOException;
  21. import java.io.StringReader;
  22. import java.util.ArrayList;
  23. import java.util.Hashtable;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.StringTokenizer;
  27. import org.aspectj.asm.AsmManager;
  28. import org.aspectj.asm.HierarchyWalker;
  29. import org.aspectj.asm.IProgramElement;
  30. import org.aspectj.asm.IRelationship;
  31. import org.aspectj.util.TypeSafeEnum;
  32. /**
  33. * @author Mik Kersten
  34. */
  35. class HtmlDecorator {
  36. private static final String POINTCUT_DETAIL = "Pointcut Detail";
  37. private static final String ADVICE_DETAIL = "Advice Detail";
  38. private static final String DECLARE_DETAIL = "Declare Detail";
  39. private static final String ADVICE_SUMMARY = "Advice Summary";
  40. private static final String POINTCUT_SUMMARY = "Pointcut Summary";
  41. private static final String DECLARE_SUMMARY = "Declare Summary";
  42. private static final String ITD_METHOD_SUMMARY = "Inter-Type Method Summary";
  43. private static final String ITD_FIELD_SUMMARY = "Inter-Type Field Summary";
  44. private static final String ITD_CONSTRUCTOR_SUMMARY = "Inter-Type Constructor Summary";
  45. static List visibleFileList = new ArrayList();
  46. static Hashtable declIDTable = null;
  47. static File rootDir = null;
  48. static String docVisibilityModifier;
  49. static void decorateHTMLFromInputFiles(Hashtable table,
  50. File newRootDir,
  51. File[] inputFiles,
  52. String docModifier ) throws IOException {
  53. rootDir = newRootDir;
  54. declIDTable = table;
  55. docVisibilityModifier = docModifier;
  56. for (int i = 0; i < inputFiles.length; i++) {
  57. decorateHTMLFromIPEs(getProgramElements(inputFiles[i].getCanonicalPath()),
  58. rootDir.getCanonicalPath() + Config.DIR_SEP_CHAR,
  59. docModifier,
  60. false);
  61. }
  62. }
  63. static void decorateHTMLFromIPEs(IProgramElement[] decls, String base, String docModifier, boolean exceededNestingLevel) throws IOException {
  64. if ( decls != null ) {
  65. for (int i = 0; i < decls.length; i++) {
  66. IProgramElement decl = decls[i];
  67. decorateHTMLFromIPE(decl, base, docModifier, exceededNestingLevel);
  68. }
  69. }
  70. }
  71. /**
  72. * Before attempting to decorate the HTML file we have to verify that it exists,
  73. * which depends on the documentation visibility specified to c.
  74. *
  75. * Depending on docModifier, can document
  76. * - public: only public
  77. * - protected: protected and public (default)
  78. * - package: package protected and public
  79. * - private: everything
  80. */
  81. static void decorateHTMLFromIPE(IProgramElement decl,
  82. String base,
  83. String docModifier,
  84. boolean exceededNestingLevel ) throws IOException {
  85. boolean nestedClass = false;
  86. if ( decl.getKind().isType() ) {
  87. boolean decorateFile = true;
  88. if (isAboveVisibility(decl)) {
  89. visibleFileList.add(decl.toSignatureString());
  90. String packageName = decl.getPackageName();
  91. String filename = "";
  92. if ( packageName != null ) {
  93. int index1 = base.lastIndexOf(Config.DIR_SEP_CHAR);
  94. int index2 = base.lastIndexOf(".");
  95. String currFileClass = "";
  96. if (index1 > -1 && index2 > 0 && index1 < index2) {
  97. currFileClass = base.substring(index1+1, index2);
  98. }
  99. // XXX only one level of nexting
  100. if (currFileClass.equals(decl.getDeclaringType())) {
  101. nestedClass = true;
  102. packageName = packageName.replace( '.','/' );
  103. String newBase = "";
  104. if ( base.lastIndexOf(Config.DIR_SEP_CHAR) > 0 ) {
  105. newBase = base.substring(0, base.lastIndexOf(Config.DIR_SEP_CHAR));
  106. }
  107. String signature = constructNestedTypeName(decl);
  108. filename = newBase + Config.DIR_SEP_CHAR + packageName +
  109. Config.DIR_SEP_CHAR + currFileClass + //"." +
  110. signature + ".html";
  111. } else {
  112. packageName = packageName.replace( '.','/' );
  113. filename = base + packageName + Config.DIR_SEP_CHAR + decl.toSignatureString() + ".html";
  114. }
  115. }
  116. else {
  117. filename = base + decl.toSignatureString() + ".html";
  118. }
  119. if (!exceededNestingLevel) {
  120. decorateHTMLFile(new File(filename));
  121. }
  122. else {
  123. System.out.println("Warning: can not generate documentation for nested " +
  124. "inner class: " + decl.toSignatureString() );
  125. }
  126. }
  127. }
  128. }
  129. private static String constructNestedTypeName(IProgramElement node) {
  130. if (node.getParent().getKind().isSourceFile()) {
  131. return node.getName();
  132. } else {
  133. String nodeName = "";
  134. if (node.getKind().isType()) nodeName += '.' + node.getName();
  135. return constructNestedTypeName(node.getParent()) + nodeName;
  136. }
  137. }
  138. /**
  139. * Skips files that are public in the model but not public in the source,
  140. * e.g. nested aspects.
  141. */
  142. static void decorateHTMLFile(File file) throws IOException {
  143. if (!file.exists()) return;
  144. System.out.println( "> Decorating " + file.getCanonicalPath() + "..." );
  145. BufferedReader reader = new BufferedReader(new FileReader(file));
  146. StringBuffer fileContents = new StringBuffer();
  147. String line = reader.readLine();
  148. while( line != null ) {
  149. fileContents.append(line + "\n");
  150. line = reader.readLine();
  151. }
  152. boolean isSecond = false;
  153. int index = 0;
  154. IProgramElement decl;
  155. while ( true ) {
  156. //---this next part is an inlined procedure that returns two values---
  157. //---the next declaration and the index at which that declaration's---
  158. //---DeclID sits in the .html file ---
  159. String contents = fileContents.toString();
  160. int start = contents.indexOf( Config.DECL_ID_STRING, index);
  161. int end = contents.indexOf( Config.DECL_ID_TERMINATOR, index );
  162. if ( start == -1 )
  163. decl = null;
  164. else if ( end == -1 )
  165. throw new Error("Malformed DeclID.");
  166. else {
  167. String tid = contents.substring(start + Config.DECL_ID_STRING.length(), end);
  168. decl = (IProgramElement)declIDTable.get(tid);
  169. index = start;
  170. }
  171. //--- ---
  172. //--- ---
  173. if ( decl == null ) break;
  174. fileContents.delete(start, end + Config.DECL_ID_TERMINATOR.length());
  175. if ( decl.getKind().isType() ) {
  176. isSecond = true;
  177. String fullname = "";
  178. if (decl.getParent().getKind().equals(IProgramElement.Kind.ASPECT)
  179. || decl.getParent().getKind().equals(IProgramElement.Kind.CLASS)) {
  180. fullname += decl.getParent().toSignatureString().concat(".").concat(decl.toSignatureString());
  181. } else {
  182. fullname += decl.toSignatureString();
  183. }
  184. // only add aspect documentation if we're in the correct
  185. // file for the given IProgramElement
  186. if (file.getName().indexOf(fullname + ".html") != -1) {
  187. addAspectDocumentation(decl, fileContents, index);
  188. }
  189. }
  190. else {
  191. decorateMemberDocumentation(decl, fileContents, index);
  192. }
  193. // Change "Class" to "Aspect"
  194. // moved this here because then can use the IProgramElement.Kind
  195. // rather than checking to see if there's advice - this fixes
  196. // the case with an inner aspect not having the title "Aspect"
  197. if(decl.getKind().equals(IProgramElement.Kind.ASPECT)
  198. && file.getName().indexOf(decl.toSignatureString()) != -1) {
  199. // only want to change "Class" to "Aspect" if we're in the
  200. // file corresponding to the IProgramElement
  201. String fullname = "";
  202. if (decl.getParent().getKind().equals(IProgramElement.Kind.ASPECT)
  203. || decl.getParent().getKind().equals(IProgramElement.Kind.CLASS)) {
  204. fullname += decl.getParent().toSignatureString().concat(".").concat(decl.toSignatureString());
  205. } else {
  206. fullname += decl.toSignatureString();
  207. }
  208. if (file.getName().indexOf(fullname + ".html") == -1) {
  209. // we're still in the file for a parent IPE
  210. continue;
  211. }
  212. boolean br = true;
  213. int classStartIndex = fileContents.toString().indexOf("<BR>\nClass ");
  214. if (classStartIndex == -1) {
  215. classStartIndex = fileContents.toString().indexOf("<H2>\nClass ");
  216. br = false;
  217. }
  218. if (classStartIndex != -1) {
  219. int classEndIndex = fileContents.toString().indexOf("</H2>", classStartIndex);
  220. if (classStartIndex != -1 && classEndIndex != -1) {
  221. String classLine = fileContents.toString().substring(classStartIndex, classEndIndex);
  222. String aspectLine = "";
  223. if (br) {
  224. aspectLine += "<BR>\n" + "Aspect " + classLine.substring(11, classLine.length());
  225. } else {
  226. aspectLine += "<H2>\n" + "Aspect " + classLine.substring(11, classLine.length());
  227. }
  228. fileContents.delete(classStartIndex, classEndIndex);
  229. fileContents.insert(classStartIndex, aspectLine);
  230. }
  231. }
  232. int secondClassStartIndex = fileContents.toString().indexOf("class <B>");
  233. if (secondClassStartIndex != -1) {
  234. String name = decl.toSignatureString();
  235. int classEndIndex = fileContents.toString().indexOf(name + "</B><DT>");
  236. if (secondClassStartIndex != -1 && classEndIndex != -1) {
  237. StringBuffer sb = new StringBuffer(fileContents.toString().
  238. substring(secondClassStartIndex,classEndIndex));
  239. sb.replace(0,5,"aspect");
  240. fileContents.delete(secondClassStartIndex, classEndIndex);
  241. fileContents.insert(secondClassStartIndex, sb.toString());
  242. }
  243. }
  244. }
  245. }
  246. file.delete();
  247. FileOutputStream fos = new FileOutputStream( file );
  248. fos.write( fileContents.toString().getBytes() );
  249. reader.close();
  250. fos.close();
  251. }
  252. static void addAspectDocumentation(IProgramElement node, StringBuffer fileBuffer, int index ) {
  253. List pointcuts = new ArrayList();
  254. List advice = new ArrayList();
  255. List declares = new ArrayList();
  256. List methodsDeclaredOn = StructureUtil.getDeclareInterTypeTargets(node, IProgramElement.Kind.INTER_TYPE_METHOD);
  257. if (methodsDeclaredOn != null && !methodsDeclaredOn.isEmpty()) {
  258. insertDeclarationsSummary(fileBuffer,methodsDeclaredOn,ITD_METHOD_SUMMARY,index);
  259. }
  260. List fieldsDeclaredOn = StructureUtil.getDeclareInterTypeTargets(node, IProgramElement.Kind.INTER_TYPE_FIELD);
  261. if (fieldsDeclaredOn != null && !fieldsDeclaredOn.isEmpty()) {
  262. insertDeclarationsSummary(fileBuffer,fieldsDeclaredOn,ITD_FIELD_SUMMARY,index);
  263. }
  264. List constDeclaredOn = StructureUtil.getDeclareInterTypeTargets(node, IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR);
  265. if (fieldsDeclaredOn != null && !constDeclaredOn.isEmpty()) {
  266. insertDeclarationsSummary(fileBuffer,constDeclaredOn,ITD_CONSTRUCTOR_SUMMARY,index);
  267. }
  268. for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) {
  269. IProgramElement member = (IProgramElement)it.next();
  270. if (member.getKind().equals(IProgramElement.Kind.POINTCUT)) {
  271. pointcuts.add(member);
  272. } else if (member.getKind().equals(IProgramElement.Kind.ADVICE)) {
  273. advice.add(member);
  274. } else if (member.getKind().isDeclare() || member.getKind().isInterTypeMember()) {
  275. declares.add(member);
  276. }
  277. }
  278. if (declares.size() > 0) {
  279. insertDeclarationsDetails(fileBuffer, declares, DECLARE_DETAIL, index);
  280. insertDeclarationsSummary(fileBuffer, declares, DECLARE_SUMMARY, index);
  281. }
  282. if (pointcuts.size() > 0) {
  283. insertDeclarationsSummary(fileBuffer, pointcuts, POINTCUT_SUMMARY, index);
  284. insertDeclarationsDetails(fileBuffer, pointcuts, POINTCUT_DETAIL, index);
  285. }
  286. if (advice.size() > 0) {
  287. insertDeclarationsSummary(fileBuffer, advice, ADVICE_SUMMARY, index);
  288. insertDeclarationsDetails(fileBuffer, advice, ADVICE_DETAIL, index);
  289. }
  290. // add the 'aspect declarations' information against the type
  291. List parentsDeclaredOn = StructureUtil.getDeclareInterTypeTargets(node, IProgramElement.Kind.DECLARE_PARENTS);
  292. if (parentsDeclaredOn != null && parentsDeclaredOn.size() > 0) {
  293. decorateDocWithRel(node,fileBuffer,index,parentsDeclaredOn,HtmlRelationshipKind.ASPECT_DECLARATIONS);
  294. }
  295. // add the 'annotated by' information against the type
  296. List annotatedBy = StructureUtil.getTargets(node,IRelationship.Kind.DECLARE_INTER_TYPE,"annotated by");
  297. if (annotatedBy != null && annotatedBy.size() > 0) {
  298. decorateDocWithRel(node,fileBuffer,index,annotatedBy,HtmlRelationshipKind.ANNOTATED_BY);
  299. }
  300. // add the 'advised by' information against the type
  301. List advisedBy = StructureUtil.getTargets(node, IRelationship.Kind.ADVICE);
  302. if (advisedBy != null && advisedBy.size() > 0) {
  303. decorateDocWithRel(node,fileBuffer,index,advisedBy,HtmlRelationshipKind.ADVISED_BY);
  304. }
  305. }
  306. static void insertDeclarationsSummary(StringBuffer fileBuffer,
  307. List decls,
  308. String kind,
  309. int index) {
  310. if (!declsAboveVisibilityExist(decls)) return;
  311. int insertIndex = findSummaryIndex(fileBuffer, index);
  312. // insert the head of the table
  313. String tableHead =
  314. "<!-- ======== " + kind.toUpperCase() + " ======= -->\n\n" +
  315. "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"1\"" +
  316. "CELLSPACING=\"0\"><TR><TD COLSPAN=2 BGCOLOR=\"#CCCCFF\">" +
  317. "<FONT SIZE=\"+2\"><B>" + kind + "</B></FONT></TD></TR>\n";
  318. fileBuffer.insert(insertIndex, tableHead);
  319. insertIndex += tableHead.length();
  320. // insert the body of the table
  321. for ( int i = 0; i < decls.size(); i++ ) {
  322. IProgramElement decl = (IProgramElement)decls.get(i);
  323. if (isAboveVisibility(decl)) {
  324. // insert the table row accordingly
  325. String comment = generateSummaryComment(decl);
  326. String entry = "";
  327. if ( kind.equals( ADVICE_SUMMARY ) ) {
  328. entry +=
  329. "<TR><TD>" +
  330. "<A HREF=\"#" + generateHREFName(decl) + "\">" +
  331. "<TT>" + generateSignatures(decl) +
  332. "</TT></A><BR>&nbsp;";
  333. if (!comment.equals("")) {
  334. entry += comment + "<P>";
  335. }
  336. entry +=
  337. generateAffects(decl) + "</TD>" +
  338. "</TR><TD>\n";
  339. }
  340. else if ( kind.equals( POINTCUT_SUMMARY ) ) {
  341. entry +=
  342. "<TR><TD WIDTH=\"1%\">" +
  343. "<FONT SIZE=-1><TT>" + genAccessibility(decl) + "</TT></FONT>" +
  344. "</TD>\n" +
  345. "<TD>" +
  346. "<TT><A HREF=\"#" + generateHREFName(decl) + "\">" +
  347. decl.toLabelString() + "</A></TT><BR>&nbsp;";
  348. if (!comment.equals("")) {
  349. entry += comment + "<P>";
  350. }
  351. entry +=
  352. "</TR></TD>\n";
  353. }
  354. else if ( kind.equals( DECLARE_SUMMARY ) ) {
  355. entry +=
  356. "<TR><TD WIDTH=\"1%\">" +
  357. "<FONT SIZE=-1><TT>" +
  358. generateModifierInformation(decl,false)
  359. + "</TT></FONT>" +
  360. "</TD>" +
  361. "<TD>" +
  362. "<A HREF=\"#" + generateHREFName(decl) + "\">" +
  363. "<TT>" + decl.toLabelString() + "</TT></A><P>" +
  364. generateAffects(decl);
  365. }
  366. else if ( kind.equals( ITD_FIELD_SUMMARY )
  367. || kind.equals( ITD_METHOD_SUMMARY)) {
  368. entry +=
  369. "<TR><TD WIDTH=\"1%\">" +
  370. "<FONT SIZE=-1><TT>" +
  371. generateModifierInformation(decl,false) +
  372. "</TT></FONT>" +
  373. "</TD>" +
  374. "<TD>" +
  375. "<A HREF=\"#" + generateHREFName(decl) + "\">" +
  376. "<TT>" + decl.toLabelString() + "</TT></A><P>"+
  377. generateDeclaredBy(decl);
  378. }
  379. else if ( kind.equals( ITD_CONSTRUCTOR_SUMMARY ) ) {
  380. entry +="<TD>" +
  381. "<A HREF=\"#" + generateHREFName(decl) + "\">" +
  382. "<TT>" + decl.toLabelString() + "</TT></A><P>"+
  383. generateDeclaredBy(decl);
  384. }
  385. // insert the entry
  386. fileBuffer.insert(insertIndex, entry);
  387. insertIndex += entry.length();
  388. }
  389. }
  390. // insert the end of the table
  391. String tableTail = "</TABLE><P>&nbsp;\n";
  392. fileBuffer.insert(insertIndex, tableTail);
  393. insertIndex += tableTail.length();
  394. }
  395. private static boolean declsAboveVisibilityExist(List decls) {
  396. boolean exist = false;
  397. for (Iterator it = decls.iterator(); it.hasNext();) {
  398. IProgramElement element = (IProgramElement) it.next();
  399. if (isAboveVisibility(element)) exist = true;
  400. }
  401. return exist;
  402. }
  403. private static boolean isAboveVisibility(IProgramElement element) {
  404. IProgramElement.Accessibility acc = element.getAccessibility();
  405. if (docVisibilityModifier.equals("private")) {
  406. // show all classes and members
  407. return true;
  408. } else if (docVisibilityModifier.equals("package")) {
  409. // show package, protected and public classes and members
  410. return acc.equals(IProgramElement.Accessibility.PACKAGE)
  411. || acc.equals(IProgramElement.Accessibility.PROTECTED)
  412. || acc.equals(IProgramElement.Accessibility.PUBLIC);
  413. } else if (docVisibilityModifier.equals("protected")) {
  414. // show protected and public classes and members
  415. return acc.equals(IProgramElement.Accessibility.PROTECTED)
  416. || acc.equals(IProgramElement.Accessibility.PUBLIC);
  417. } else if (docVisibilityModifier.equals("public")){
  418. // show public classes and members
  419. return acc.equals(IProgramElement.Accessibility.PUBLIC);
  420. }
  421. return false;
  422. }
  423. private static String genAccessibility(IProgramElement decl) {
  424. if (decl.getAccessibility().equals(IProgramElement.Accessibility.PACKAGE)) {
  425. return "(package private)";
  426. } else {
  427. return decl.getAccessibility().toString();
  428. }
  429. }
  430. static void insertDeclarationsDetails(StringBuffer fileBuffer,
  431. List decls,
  432. String kind,
  433. int index) {
  434. if (!declsAboveVisibilityExist(decls)) return;
  435. int insertIndex = findDetailsIndex(fileBuffer, index);
  436. // insert the table heading
  437. String detailsHeading
  438. = "<P>&nbsp;\n" +
  439. "<!-- ======== " + kind.toUpperCase() + " SUMMARY ======= -->\n\n" +
  440. "<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" WIDTH=\"100%\">\n" +
  441. "<TR BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">\n" +
  442. "<TD COLSPAN=1><FONT SIZE=\"+2\">\n" +
  443. "<B>" + kind + "</B></FONT></TD>\n" +
  444. "</TR>\n" +
  445. "</TABLE>";
  446. fileBuffer.insert(insertIndex, detailsHeading);
  447. insertIndex += detailsHeading.length();
  448. // insert the details
  449. for ( int i = 0; i < decls.size(); i++ ) {
  450. IProgramElement decl = (IProgramElement)decls.get(i);
  451. if (isAboveVisibility(decl)) {
  452. String entry = "";
  453. // insert the table row accordingly
  454. entry += "<A NAME=\"" + generateHREFName(decl) + "\"><!-- --></A>\n";
  455. if ( kind.equals( ADVICE_DETAIL ) ) {
  456. entry += "<H3>" + decl.getName() + "</H3><P>";
  457. entry +=
  458. "<TT>" +
  459. generateSignatures(decl) + "</TT>\n" + "<P>" +
  460. generateDetailsComment(decl) + "<P>" +
  461. generateAffects(decl);
  462. }
  463. else if (kind.equals(POINTCUT_DETAIL)) {
  464. entry +=
  465. "<H3>" +
  466. decl.toLabelString() +
  467. "</H3><P>" +
  468. generateDetailsComment(decl);
  469. }
  470. else if (kind.equals(DECLARE_DETAIL)) {
  471. entry += "<H3>" + decl.toLabelString() +
  472. "</H3><P>" +
  473. generateModifierInformation(decl,true);
  474. if (!decl.getKind().equals(IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR)) {
  475. entry += "&nbsp;&nbsp;";
  476. }
  477. // if we're not a declare statement then we need to generate the signature.
  478. // If we did this for declare statements we get two repeated lines
  479. if (!decl.getKind().isDeclare()) {
  480. entry += generateSignatures(decl) + "<P>";
  481. }
  482. entry += generateAffects(decl) +
  483. generateDetailsComment(decl);
  484. }
  485. // insert the entry
  486. if (i != decls.size()-1) {
  487. entry += "<P><HR>\n";
  488. }
  489. else {
  490. entry += "<P>";
  491. }
  492. fileBuffer.insert(insertIndex, entry);
  493. insertIndex += entry.length();
  494. }
  495. }
  496. }
  497. /**
  498. * TODO: don't place the summary first.
  499. */
  500. static int findSummaryIndex(StringBuffer fileBuffer, int index) {
  501. String fbs = fileBuffer.toString();
  502. String MARKER_1 = "<!-- =========== FIELD SUMMARY =========== -->";
  503. String MARKER_2 = "<!-- ======== CONSTRUCTOR SUMMARY ======== -->";
  504. int index1 = fbs.indexOf(MARKER_1, index);
  505. int index2 = fbs.indexOf(MARKER_2, index);
  506. if (index1 < index2 && index1 != -1) {
  507. return index1;
  508. } else if (index2 != -1){
  509. return index2;
  510. } else {
  511. return index;
  512. }
  513. }
  514. static int findDetailsIndex(StringBuffer fileBuffer, int index) {
  515. String fbs = fileBuffer.toString();
  516. String MARKER_1 = "<!-- ========= CONSTRUCTOR DETAIL ======== -->";
  517. String MARKER_2 = "<!-- ============ FIELD DETAIL =========== -->";
  518. String MARKER_3 = "<!-- ============ METHOD DETAIL ========== -->";
  519. int index1 = fbs.indexOf(MARKER_1, index);
  520. int index2 = fbs.indexOf(MARKER_2, index);
  521. int index3 = fbs.indexOf(MARKER_3, index);
  522. if (index1 != -1 && index1 < index2 && index1 < index3) {
  523. return index1;
  524. } else if (index2 != -1 && index2 < index1 && index2 < index3) {
  525. return index2;
  526. } else if (index3 != -1) {
  527. return index3;
  528. } else {
  529. return index;
  530. }
  531. }
  532. static void decorateDocWithRel(
  533. IProgramElement node,
  534. StringBuffer fileContentsBuffer,
  535. int index,
  536. List targets,
  537. HtmlRelationshipKind relKind) {
  538. if (targets != null && !targets.isEmpty()) {
  539. String adviceDoc = "<TABLE WIDTH=\"100%\" BGCOLOR=#FFFFFF><TR>" +
  540. "<TD width=\"15%\" bgcolor=\"#FFD8B0\"><B><FONT COLOR=000000>" +
  541. relKind.toString() +
  542. "</font></b></td><td>";
  543. String relativePackagePath =
  544. getRelativePathFromHere(
  545. node.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR);
  546. List addedNames = new ArrayList();
  547. for (Iterator it = targets.iterator(); it.hasNext(); ) {
  548. Object o = it.next();
  549. IProgramElement currDecl = null;
  550. if (o instanceof String) {
  551. String currHandle = (String)o;
  552. currDecl = AsmManager.getDefault().getHierarchy().findElementForHandle(currHandle);
  553. } else if (o instanceof IProgramElement){
  554. currDecl = (IProgramElement)o;
  555. } else {
  556. return;
  557. }
  558. String packagePath = "";
  559. if (currDecl.getPackageName() != null && !currDecl.getPackageName().equals("")) {
  560. packagePath = currDecl.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR;
  561. }
  562. String hrefName = "";
  563. String hrefLink = "";
  564. // Start the hRefLink with the relative path based on where
  565. // *this* type (i.e. the advised) is in the package structure.
  566. hrefLink = relativePackagePath + packagePath;
  567. if (currDecl.getPackageName() != null ) {
  568. hrefName = currDecl.getPackageName().replace('.', '/');
  569. }
  570. // in the case of nested classes, in order for the links to work,
  571. // need to have the correct file name which is something of the
  572. // form parentClass.nestedAspect.html
  573. List names = new ArrayList();
  574. IProgramElement parent = currDecl;
  575. while (parent != null
  576. && parent.getParent() != null
  577. && (!parent.getParent().getKind().equals(IProgramElement.Kind.FILE_JAVA)
  578. && !parent.getParent().getKind().equals(IProgramElement.Kind.FILE_ASPECTJ))) {
  579. parent = parent.getParent();
  580. names.add(parent.toLinkLabelString());
  581. }
  582. StringBuffer sbuff = new StringBuffer();
  583. for (int i = names.size() - 1; i >= 0; i--) {
  584. String element = (String)names.get(i);
  585. if (i == 0) {
  586. sbuff.append(element);
  587. } else {
  588. sbuff.append(element + ".");
  589. }
  590. }
  591. // use the currDecl.toLabelString rather than currDecl.getName()
  592. // because two distinct advice blocks can have the same
  593. // currDecl.getName() and wouldn't both appear in the ajdoc
  594. hrefName += Config.DIR_SEP_CHAR +
  595. sbuff.toString()
  596. + "." + currDecl.toLabelString();
  597. // need to replace " with quot; otherwise the links wont work
  598. // for 'matches declare' relationship
  599. StringBuffer sb = new StringBuffer(currDecl.toLabelString());
  600. int nextQuote = sb.toString().indexOf("\"");
  601. while (nextQuote != -1) {
  602. sb.deleteCharAt(nextQuote);
  603. sb.insert(nextQuote,"quot;");
  604. nextQuote = sb.toString().indexOf("\"");
  605. }
  606. hrefLink += sbuff.toString() + ".html" + "#" + sb.toString();
  607. if (!addedNames.contains(hrefName)) {
  608. adviceDoc = adviceDoc +
  609. "<A HREF=\"" + hrefLink + "\"><tt>"
  610. + hrefName.replace('/', '.') + "</tt></A>";
  611. if (it.hasNext()) adviceDoc += ", ";
  612. addedNames.add(hrefName);
  613. }
  614. }
  615. adviceDoc += "</TR></TD></TABLE>\n";
  616. fileContentsBuffer.insert( index, adviceDoc );
  617. }
  618. }
  619. static void decorateMemberDocumentation(IProgramElement node,
  620. StringBuffer fileContentsBuffer,
  621. int index ) {
  622. List targets = StructureUtil.getTargets(node, IRelationship.Kind.ADVICE);
  623. decorateDocWithRel(node,fileContentsBuffer,index,targets,HtmlRelationshipKind.ADVISED_BY);
  624. List warnings = StructureUtil.getTargets(node,IRelationship.Kind.DECLARE,"matches declare");
  625. decorateDocWithRel(node,fileContentsBuffer,index,warnings,HtmlRelationshipKind.MATCHES_DECLARE);
  626. List softenedBy = StructureUtil.getTargets(node,IRelationship.Kind.DECLARE,"softened by");
  627. decorateDocWithRel(node,fileContentsBuffer,index,softenedBy,HtmlRelationshipKind.SOFTENED_BY);
  628. List annotatedBy = StructureUtil.getTargets(node,IRelationship.Kind.DECLARE_INTER_TYPE,"annotated by");
  629. decorateDocWithRel(node,fileContentsBuffer,index,annotatedBy,HtmlRelationshipKind.ANNOTATED_BY);
  630. }
  631. /**
  632. * pr119453 - adding "declared by" relationship
  633. */
  634. static String generateDeclaredBy(IProgramElement decl) {
  635. String entry = "<TABLE WIDTH=\"100%\" BGCOLOR=#FFFFFF><TR>" +
  636. "<TD width=\"10%\" bgcolor=\"#FFD8B0\"><B><FONT COLOR=000000>" +
  637. "&nbsp;Declared&nbsp;by:</b></font></td><td>";
  638. String relativePackagePath =
  639. getRelativePathFromHere(
  640. decl.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR);
  641. if (decl != null && !StructureUtil.isAnonymous(decl.getParent())) {
  642. String packagePath = "";
  643. if (decl.getPackageName() != null && !decl.getPackageName().equals("")) {
  644. packagePath = decl.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR;
  645. }
  646. String typeSignature = constructNestedTypeName(decl);
  647. String hrefName = packagePath + typeSignature;
  648. // The hrefLink needs to just be the corresponding aspect
  649. String hrefLink =
  650. relativePackagePath
  651. + packagePath
  652. + typeSignature
  653. + ".html";
  654. entry += "<A HREF=\"" + hrefLink +
  655. "\"><tt>" + hrefName.replace('/', '.') + "</tt></A>"; // !!! don't replace
  656. }
  657. entry += "</B></FONT></TD></TR></TABLE>\n</TR></TD>\n";
  658. return entry;
  659. }
  660. /**
  661. * TODO: probably want to make this the same for intros and advice.
  662. */
  663. static String generateAffects(IProgramElement decl) {
  664. List targets = null;
  665. if (decl.getKind().isDeclare() || decl.getKind().isInterTypeMember()) {
  666. targets = StructureUtil.getDeclareTargets(decl);
  667. } else {
  668. targets = StructureUtil.getTargets(decl, IRelationship.Kind.ADVICE);
  669. }
  670. if (targets == null) return "";
  671. String entry = "<TABLE WIDTH=\"100%\" BGCOLOR=#FFFFFF><TR>";
  672. IProgramElement.Kind kind = decl.getKind();
  673. if (kind.equals(IProgramElement.Kind.ADVICE)) {
  674. entry += "<TD width=\"10%\" bgcolor=\"#FFD8B0\"><B><FONT COLOR=000000>" +
  675. HtmlRelationshipKind.ADVISES.toString() +
  676. "</b></font></td><td>";
  677. } else if (kind.equals(IProgramElement.Kind.DECLARE_WARNING)
  678. || kind.equals(IProgramElement.Kind.DECLARE_ERROR)) {
  679. entry += "<TD width=\"10%\" bgcolor=\"#FFD8B0\"><B><FONT COLOR=000000>" +
  680. HtmlRelationshipKind.MATCHED_BY.toString() +
  681. "</b></font></td><td>";
  682. } else if (kind.isDeclareAnnotation()) {
  683. entry += "<TD width=\"10%\" bgcolor=\"#FFD8B0\"><B><FONT COLOR=000000>" +
  684. HtmlRelationshipKind.ANNOTATES.toString() +
  685. "</b></font></td><td>";
  686. } else if (kind.equals(IProgramElement.Kind.DECLARE_SOFT)) {
  687. entry += "<TD width=\"10%\" bgcolor=\"#FFD8B0\"><B><FONT COLOR=000000>" +
  688. HtmlRelationshipKind.SOFTENS.toString() +
  689. "</b></font></td><td>";
  690. } else {
  691. entry += "<TD width=\"10%\" bgcolor=\"#FFD8B0\"><B><FONT COLOR=000000>" +
  692. HtmlRelationshipKind.DECLARED_ON.toString() +
  693. "</b></font></td><td>";
  694. }
  695. String relativePackagePath =
  696. getRelativePathFromHere(
  697. decl.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR);
  698. List addedNames = new ArrayList(); // for ensuring that we don't add duplciates
  699. for (Iterator it = targets.iterator(); it.hasNext(); ) {
  700. String currHandle = (String)it.next();
  701. IProgramElement currDecl = AsmManager.getDefault().getHierarchy().findElementForHandle(currHandle);
  702. if (currDecl.getKind().equals(IProgramElement.Kind.CODE)) {
  703. currDecl = currDecl.getParent(); // promote to enclosing
  704. }
  705. if (currDecl != null && !StructureUtil.isAnonymous(currDecl.getParent())) {
  706. String packagePath = "";
  707. if (currDecl.getPackageName() != null && !currDecl.getPackageName().equals("")) {
  708. packagePath = currDecl.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR;
  709. }
  710. String typeSignature = constructNestedTypeName(currDecl);
  711. String hrefName =
  712. packagePath
  713. + typeSignature;
  714. // Start the hRefLink with the relative path based on where
  715. // *this* type (i.e. the advisor) is in the package structure.
  716. String hrefLink =
  717. relativePackagePath
  718. + packagePath
  719. + typeSignature
  720. + ".html";
  721. if (!currDecl.getKind().isType()) {
  722. hrefName += '.' + currDecl.getName();
  723. hrefLink += "#" + currDecl.toLabelString();
  724. }
  725. if (!addedNames.contains(hrefName)) {
  726. entry += "<A HREF=\"" + hrefLink +
  727. "\"><tt>" + hrefName.replace('/', '.') + "</tt></A>"; // !!! don't replace
  728. if (it.hasNext()) entry += ", ";
  729. addedNames.add(hrefName);
  730. }
  731. }
  732. }
  733. entry += "</B></FONT></TD></TR></TABLE>\n</TR></TD>\n";
  734. return entry;
  735. }
  736. /**
  737. * Generates a relative directory path fragment that can be
  738. * used to navigate "upwards" from the directory location
  739. * implied by the argument.
  740. * @param packagePath
  741. * @return String consisting of multiple "../" parts, one for
  742. * each component part of the input <code>packagePath</code>.
  743. */
  744. private static String getRelativePathFromHere(String packagePath) {
  745. StringBuffer result = new StringBuffer("");
  746. if (packagePath != null && (packagePath.indexOf("/") != -1)) {
  747. StringTokenizer sTok = new StringTokenizer(packagePath, "/", false);
  748. while (sTok.hasMoreTokens()) {
  749. sTok.nextToken(); // don't care about the token value
  750. result.append(".." + Config.DIR_SEP_CHAR);
  751. }// end while
  752. }// end if
  753. return result.toString();
  754. }
  755. /**
  756. * Generate the "public int"-type information about the given IProgramElement.
  757. * Used when dealing with ITDs. To mirror the behaviour of methods and fields
  758. * in classes, if we're generating the summary information we don't want to
  759. * include "public" if the accessibility of the IProgramElement is public.
  760. *
  761. */
  762. private static String generateModifierInformation(IProgramElement decl, boolean isDetails) {
  763. String intro = "";
  764. if (decl.getKind().isDeclare()) {
  765. return intro + "</TT>";
  766. }
  767. if (isDetails ||
  768. !decl.getAccessibility().equals(IProgramElement.Accessibility.PUBLIC)) {
  769. intro += "<TT>" + decl.getAccessibility().toString() + "&nbsp;" ;
  770. }
  771. if (decl.getKind().equals(IProgramElement.Kind.INTER_TYPE_FIELD)) {
  772. return intro + decl.getCorrespondingType() + "</TT>";
  773. } else if (decl.getKind().equals(IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR)
  774. && isDetails) {
  775. return intro + "</TT>";
  776. } else {
  777. return intro + decl.getCorrespondingType(true) + "</TT>";
  778. }
  779. }
  780. static String generateIntroductionSignatures(IProgramElement decl, boolean isDetails) {
  781. return "<not implemented>";
  782. }
  783. static String generateSignatures(IProgramElement decl ) {
  784. return "<B>" + decl.toLabelString() + "</B>";
  785. }
  786. static String generateSummaryComment(IProgramElement decl) {
  787. String COMMENT_INDENT = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"; // !!!
  788. String formattedComment = getFormattedComment(decl);
  789. int periodIndex = formattedComment.indexOf( '.' );
  790. if (formattedComment.equals("")) {
  791. return "";
  792. }
  793. else if ( periodIndex != -1 ) {
  794. return COMMENT_INDENT + formattedComment.substring( 0, periodIndex+1 ) ;
  795. }
  796. else {
  797. return COMMENT_INDENT + formattedComment;
  798. }
  799. }
  800. static String generateDetailsComment(IProgramElement decl) {
  801. return getFormattedComment(decl);
  802. }
  803. static String generateHREFName(IProgramElement decl) {
  804. StringBuffer hrefLinkBuffer = new StringBuffer();
  805. char[] declChars = decl.toLabelString().toCharArray();
  806. for (int i = 0; i < declChars.length; i++) {
  807. if (declChars[i] == '"') {
  808. hrefLinkBuffer.append("quot;");
  809. } else {
  810. hrefLinkBuffer.append(declChars[i]);
  811. }
  812. }
  813. return hrefLinkBuffer.toString();
  814. }
  815. /**
  816. * Figure out the link relative to the package.
  817. */
  818. static String generateAffectsHREFLink(String declaringType) {
  819. String link = rootDir.getAbsolutePath() + "/" + declaringType + ".html";
  820. return link;
  821. }
  822. /**
  823. * This formats a comment according to the rules in the Java Langauge Spec:
  824. * <I>The text of a docuemntation comment consists of the characters between
  825. * the /** that begins the comment and the 'star-slash' that ends it. The text is
  826. * devided into one or more lines. On each of these lines, the leading *
  827. * characters are ignored; for lines other than the first, blanks and
  828. * tabs preceding the initial * characters are also discarded.</I>
  829. *
  830. * TODO: implement formatting or linking for tags.
  831. */
  832. static String getFormattedComment(IProgramElement decl) {
  833. String comment = decl.getFormalComment();
  834. if (comment == null) return "";
  835. String formattedComment = "";
  836. // strip the comment markers
  837. int startIndex = comment.indexOf("/**");
  838. int endIndex = comment.indexOf("*/");
  839. if ( startIndex == -1 ) {
  840. startIndex = 0;
  841. }
  842. else {
  843. startIndex += 3;
  844. }
  845. if ( endIndex == -1 ) {
  846. endIndex = comment.length();
  847. }
  848. comment = comment.substring( startIndex, endIndex );
  849. // string the leading whitespace and '*' characters at the beginning of each line
  850. BufferedReader reader
  851. = new BufferedReader( new StringReader( comment ) );
  852. try {
  853. for (String line = reader.readLine(); line != null; line = reader.readLine()) {
  854. line = line.trim();
  855. for (int i = 0; i < line.length(); i++ ) {
  856. if ( line.charAt(0) == '*' ) {
  857. line = line.substring(1, line.length());
  858. }
  859. else {
  860. break;
  861. }
  862. }
  863. // !!! remove any @see and @link tags from the line
  864. //int seeIndex = line.indexOf("@see");
  865. //int linkIndex = line.indexOf("@link");
  866. //if ( seeIndex != -1 ) {
  867. // line = line.substring(0, seeIndex) + line.substring(seeIndex);
  868. //}
  869. //if ( linkIndex != -1 ) {
  870. // line = line.substring(0, linkIndex) + line.substring(linkIndex);
  871. //}
  872. formattedComment += line;
  873. }
  874. } catch ( IOException ioe ) {
  875. throw new Error( "Couldn't format comment for declaration: " +
  876. decl.getName() );
  877. }
  878. return formattedComment;
  879. }
  880. static public IProgramElement[] getProgramElements(String filename) {
  881. IProgramElement file = (IProgramElement)AsmManager.getDefault().getHierarchy().findElementForSourceFile(filename);
  882. final List nodes = new ArrayList();
  883. HierarchyWalker walker = new HierarchyWalker() {
  884. public void preProcess(IProgramElement node) {
  885. IProgramElement p = (IProgramElement)node;
  886. if (accept(node)) nodes.add(p);
  887. }
  888. };
  889. file.walk(walker);
  890. return (IProgramElement[])nodes.toArray(new IProgramElement[nodes.size()]);
  891. }
  892. /**
  893. * Rejects anonymous kinds by checking if their name is an integer
  894. */
  895. static private boolean accept(IProgramElement node) {
  896. if (node.getKind().isType()) {
  897. boolean isAnonymous = StructureUtil.isAnonymous(node);
  898. return !node.getParent().getKind().equals(IProgramElement.Kind.METHOD)
  899. && !isAnonymous;
  900. } else {
  901. return !node.getKind().equals(IProgramElement.Kind.IMPORT_REFERENCE);
  902. }
  903. }
  904. /**
  905. * TypeSafeEnum for the entries which need to be put in the html doc
  906. */
  907. public static class HtmlRelationshipKind extends TypeSafeEnum {
  908. public HtmlRelationshipKind(String name, int key) {
  909. super(name, key);
  910. }
  911. public static HtmlRelationshipKind read(DataInputStream s) throws IOException {
  912. int key = s.readByte();
  913. switch(key) {
  914. case 1: return ADVISES;
  915. case 2: return ADVISED_BY;
  916. case 3: return MATCHED_BY;
  917. case 4: return MATCHES_DECLARE;
  918. case 5: return DECLARED_ON;
  919. case 6: return ASPECT_DECLARATIONS;
  920. case 7: return SOFTENS;
  921. case 8: return SOFTENED_BY;
  922. case 9: return ANNOTATES;
  923. case 10: return ANNOTATED_BY;
  924. case 11: return USES_POINTCUT;
  925. case 12: return POINTCUT_USED_BY;
  926. }
  927. throw new Error("weird relationship kind " + key);
  928. }
  929. public static final HtmlRelationshipKind ADVISES = new HtmlRelationshipKind("&nbsp;Advises:", 1);
  930. public static final HtmlRelationshipKind ADVISED_BY = new HtmlRelationshipKind("&nbsp;Advised&nbsp;by:", 2);
  931. public static final HtmlRelationshipKind MATCHED_BY = new HtmlRelationshipKind("&nbsp;Matched&nbsp;by:", 3);
  932. public static final HtmlRelationshipKind MATCHES_DECLARE = new HtmlRelationshipKind("&nbsp;Matches&nbsp;declare:", 4);
  933. public static final HtmlRelationshipKind DECLARED_ON = new HtmlRelationshipKind("&nbsp;Declared&nbsp;on:", 5);
  934. public static final HtmlRelationshipKind ASPECT_DECLARATIONS = new HtmlRelationshipKind("&nbsp;Aspect&nbsp;declarations:", 6);
  935. public static final HtmlRelationshipKind SOFTENS = new HtmlRelationshipKind("&nbsp;Softens:", 7);
  936. public static final HtmlRelationshipKind SOFTENED_BY = new HtmlRelationshipKind("&nbsp;Softened&nbsp;by:", 8);
  937. public static final HtmlRelationshipKind ANNOTATES = new HtmlRelationshipKind("&nbsp;Annotates:", 9);
  938. public static final HtmlRelationshipKind ANNOTATED_BY = new HtmlRelationshipKind("&nbsp;Annotated&nbsp;by:", 10);
  939. public static final HtmlRelationshipKind USES_POINTCUT = new HtmlRelationshipKind("&nbsp;Uses&nbsp;pointcut:", 11);
  940. public static final HtmlRelationshipKind POINTCUT_USED_BY = new HtmlRelationshipKind("&nbsp;Pointcut&nbsp;used&nbsp;by:", 12);
  941. }
  942. }