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.

AsmManager.java 43KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300
  1. /* *******************************************************************
  2. * Copyright (c) 2003 Contributors.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Mik Kersten initial implementation
  11. * Andy Clement incremental support and switch on/off state
  12. * ******************************************************************/
  13. package org.aspectj.asm;
  14. import java.io.BufferedWriter;
  15. import java.io.EOFException;
  16. import java.io.File;
  17. import java.io.FileInputStream;
  18. import java.io.FileNotFoundException;
  19. import java.io.FileOutputStream;
  20. import java.io.FileWriter;
  21. import java.io.IOException;
  22. import java.io.ObjectInputStream;
  23. import java.io.ObjectOutputStream;
  24. import java.io.Writer;
  25. import java.util.ArrayList;
  26. import java.util.Collection;
  27. import java.util.Enumeration;
  28. import java.util.HashMap;
  29. import java.util.HashSet;
  30. import java.util.Hashtable;
  31. import java.util.Iterator;
  32. import java.util.List;
  33. import java.util.Map;
  34. import java.util.Properties;
  35. import java.util.Set;
  36. import org.aspectj.asm.internal.AspectJElementHierarchy;
  37. import org.aspectj.asm.internal.HandleProviderDelimiter;
  38. import org.aspectj.asm.internal.JDTLikeHandleProvider;
  39. import org.aspectj.asm.internal.RelationshipMap;
  40. import org.aspectj.bridge.ISourceLocation;
  41. import org.aspectj.util.IStructureModel;
  42. /**
  43. * The Abstract Structure Model (ASM) represents the containment hierarchy and crosscutting structure map for AspectJ programs. It
  44. * is used by IDE views such as the document outline, and by other tools such as ajdoc to show both AspectJ declarations and
  45. * crosscutting links, such as which advice affects which join point shadows.
  46. *
  47. * @author Mik Kersten
  48. * @author Andy Clement
  49. */
  50. public class AsmManager implements IStructureModel {
  51. // For testing ONLY
  52. public static boolean recordingLastActiveStructureModel = true;
  53. public static AsmManager lastActiveStructureModel;
  54. public static boolean forceSingletonBehaviour = false;
  55. // SECRETAPI asc pull the secret options together into a system API you lazy fool
  56. public static boolean attemptIncrementalModelRepairs = false;
  57. // Dumping the model is expensive
  58. public static boolean dumpModelPostBuild = false;
  59. // For offline debugging, you can now ask for the AsmManager to
  60. // dump the model - see the method setReporting()
  61. private static boolean dumpModel = false;
  62. private static boolean dumpRelationships = false;
  63. private static boolean dumpDeltaProcessing = false;
  64. private static IModelFilter modelFilter = null;
  65. private static String dumpFilename = "";
  66. private static boolean reporting = false;
  67. private static boolean completingTypeBindings = false;
  68. private final List<IHierarchyListener> structureListeners = new ArrayList<IHierarchyListener>();
  69. // The model is 'manipulated' by the AjBuildManager.setupModel() code which
  70. // trashes all the
  71. // fields when setting up a new model for a batch build.
  72. // Due to the requirements of incremental compilation we need to tie some of
  73. // the info
  74. // below to the AjState for a compilation and recover it if switching
  75. // between projects.
  76. protected IHierarchy hierarchy;
  77. /*
  78. * Map from String > String - it maps absolute paths for inpath dirs/jars to workspace relative paths suitable for handle
  79. * inclusion
  80. */
  81. protected Map<File, String> inpathMap;
  82. private IRelationshipMap mapper;
  83. private IElementHandleProvider handleProvider;
  84. private final CanonicalFilePathMap canonicalFilePathMap = new CanonicalFilePathMap();
  85. // Record the Set<File> for which the model has been modified during the
  86. // last incremental build
  87. private final Set<File> lastBuildChanges = new HashSet<File>();
  88. // Record the Set<File> of aspects that wove the files listed in lastBuildChanges
  89. final Set<File> aspectsWeavingInLastBuild = new HashSet<File>();
  90. // static {
  91. // setReporting("c:/model.nfo",true,true,true,true);
  92. // }
  93. private AsmManager() {
  94. }
  95. public static AsmManager createNewStructureModel(Map<File, String> inpathMap) {
  96. if (forceSingletonBehaviour && lastActiveStructureModel != null) {
  97. return lastActiveStructureModel;
  98. }
  99. AsmManager asm = new AsmManager();
  100. asm.inpathMap = inpathMap;
  101. asm.hierarchy = new AspectJElementHierarchy(asm);
  102. asm.mapper = new RelationshipMap();
  103. asm.handleProvider = new JDTLikeHandleProvider(asm);
  104. // call initialize on the handleProvider when we create a new ASM
  105. // to give handleProviders the chance to reset any state
  106. asm.handleProvider.initialize();
  107. asm.resetDeltaProcessing();
  108. setLastActiveStructureModel(asm);
  109. return asm;
  110. }
  111. public IHierarchy getHierarchy() {
  112. return hierarchy;
  113. }
  114. public IRelationshipMap getRelationshipMap() {
  115. return mapper;
  116. }
  117. public void fireModelUpdated() {
  118. notifyListeners();
  119. if (dumpModelPostBuild && hierarchy.getConfigFile() != null) {
  120. writeStructureModel(hierarchy.getConfigFile());
  121. }
  122. }
  123. /**
  124. * Constructs map each time it's called.
  125. */
  126. public HashMap<Integer, List<IProgramElement>> getInlineAnnotations(String sourceFile, boolean showSubMember,
  127. boolean showMemberAndType) {
  128. if (!hierarchy.isValid()) {
  129. return null;
  130. }
  131. HashMap<Integer, List<IProgramElement>> annotations = new HashMap<Integer, List<IProgramElement>>();
  132. IProgramElement node = hierarchy.findElementForSourceFile(sourceFile);
  133. if (node == IHierarchy.NO_STRUCTURE) {
  134. return null;
  135. } else {
  136. IProgramElement fileNode = node;
  137. ArrayList<IProgramElement> peNodes = new ArrayList<IProgramElement>();
  138. getAllStructureChildren(fileNode, peNodes, showSubMember, showMemberAndType);
  139. for (IProgramElement peNode : peNodes) {
  140. List<IProgramElement> entries = new ArrayList<IProgramElement>();
  141. entries.add(peNode);
  142. ISourceLocation sourceLoc = peNode.getSourceLocation();
  143. if (null != sourceLoc) {
  144. Integer hash = new Integer(sourceLoc.getLine());
  145. List<IProgramElement> existingEntry = annotations.get(hash);
  146. if (existingEntry != null) {
  147. entries.addAll(existingEntry);
  148. }
  149. annotations.put(hash, entries);
  150. }
  151. }
  152. return annotations;
  153. }
  154. }
  155. private void getAllStructureChildren(IProgramElement node, List<IProgramElement> result, boolean showSubMember,
  156. boolean showMemberAndType) {
  157. List<IProgramElement> children = node.getChildren();
  158. if (node.getChildren() == null) {
  159. return;
  160. }
  161. for (IProgramElement next : children) {
  162. List<IRelationship> rels = mapper.get(next);
  163. if (next != null
  164. && ((next.getKind() == IProgramElement.Kind.CODE && showSubMember) || (next.getKind() != IProgramElement.Kind.CODE && showMemberAndType))
  165. && rels != null && rels.size() > 0) {
  166. result.add(next);
  167. }
  168. getAllStructureChildren(next, result, showSubMember, showMemberAndType);
  169. }
  170. }
  171. public void addListener(IHierarchyListener listener) {
  172. structureListeners.add(listener);
  173. }
  174. public void removeStructureListener(IHierarchyListener listener) {
  175. structureListeners.remove(listener);
  176. }
  177. // this shouldn't be needed - but none of the people that add listeners
  178. // in the test suite ever remove them. AMC added this to be called in
  179. // setup() so that the test cases would cease leaking listeners and go
  180. // back to executing at a reasonable speed.
  181. public void removeAllListeners() {
  182. structureListeners.clear();
  183. }
  184. private void notifyListeners() {
  185. for (IHierarchyListener listener : structureListeners) {
  186. listener.elementsUpdated(hierarchy);
  187. }
  188. }
  189. public IElementHandleProvider getHandleProvider() {
  190. return handleProvider;
  191. }
  192. public void setHandleProvider(IElementHandleProvider handleProvider) {
  193. this.handleProvider = handleProvider;
  194. }
  195. public void writeStructureModel(String configFilePath) {
  196. try {
  197. String filePath = genExternFilePath(configFilePath);
  198. FileOutputStream fos = new FileOutputStream(filePath);
  199. ObjectOutputStream s = new ObjectOutputStream(fos);
  200. s.writeObject(hierarchy); // Store the program element tree
  201. s.writeObject(mapper); // Store the relationships
  202. s.flush();
  203. fos.flush();
  204. fos.close();
  205. s.close();
  206. } catch (IOException e) {
  207. // System.err.println("AsmManager: Unable to write structure model: "
  208. // +configFilePath+" because of:");
  209. // e.printStackTrace();
  210. }
  211. }
  212. /**
  213. * @param configFilePath path to an ".lst" file
  214. */
  215. public void readStructureModel(String configFilePath) {
  216. boolean hierarchyReadOK = false;
  217. try {
  218. if (configFilePath == null) {
  219. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  220. } else {
  221. String filePath = genExternFilePath(configFilePath);
  222. FileInputStream in = new FileInputStream(filePath);
  223. ObjectInputStream s = new ObjectInputStream(in);
  224. hierarchy = (AspectJElementHierarchy) s.readObject();
  225. ((AspectJElementHierarchy) hierarchy).setAsmManager(this);
  226. hierarchyReadOK = true;
  227. mapper = (RelationshipMap) s.readObject();
  228. s.close();
  229. }
  230. } catch (FileNotFoundException fnfe) {
  231. // That is OK
  232. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  233. } catch (EOFException eofe) {
  234. // Might be an old format sym file that is missing its relationships
  235. if (!hierarchyReadOK) {
  236. System.err.println("AsmManager: Unable to read structure model: " + configFilePath + " because of:");
  237. eofe.printStackTrace();
  238. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  239. }
  240. } catch (Exception e) {
  241. // System.err.println("AsmManager: Unable to read structure model: "+
  242. // configFilePath+" because of:");
  243. // e.printStackTrace();
  244. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  245. } finally {
  246. notifyListeners();
  247. }
  248. }
  249. private String genExternFilePath(String configFilePath) {
  250. // sometimes don't have ".lst"
  251. if (configFilePath.lastIndexOf(".lst") != -1) {
  252. configFilePath = configFilePath.substring(0, configFilePath.lastIndexOf(".lst"));
  253. }
  254. return configFilePath + ".ajsym";
  255. }
  256. public String getCanonicalFilePath(File f) {
  257. return canonicalFilePathMap.get(f);
  258. }
  259. public CanonicalFilePathMap getCanonicalFilePathMap() {
  260. return canonicalFilePathMap;
  261. }
  262. private static class CanonicalFilePathMap {
  263. private static final int MAX_SIZE = 4000;
  264. private final Map<String, String> pathMap = new HashMap<String, String>(20);
  265. // // guards to ensure correctness and liveness
  266. // private boolean cacheInUse = false;
  267. // private boolean stopRequested = false;
  268. //
  269. // private synchronized boolean isCacheInUse() {
  270. // return cacheInUse;
  271. // }
  272. //
  273. // private synchronized void setCacheInUse(boolean val) {
  274. // cacheInUse = val;
  275. // if (val) {
  276. // notifyAll();
  277. // }
  278. // }
  279. //
  280. // private synchronized boolean isStopRequested() {
  281. // return stopRequested;
  282. // }
  283. //
  284. // private synchronized void requestStop() {
  285. // stopRequested = true;
  286. // }
  287. //
  288. // /**
  289. // * Begin prepopulating the map by adding an entry from
  290. // * file.getPath -> file.getCanonicalPath for each file in
  291. // * the list. Do this on a background thread.
  292. // * @param files
  293. // */
  294. // public void prepopulate(final List files) {
  295. // stopRequested = false;
  296. // setCacheInUse(false);
  297. // if (pathMap.size() > MAX_SIZE) {
  298. // pathMap.clear();
  299. // }
  300. // new Thread() {
  301. // public void run() {
  302. // System.out.println("Starting cache population: " +
  303. // System.currentTimeMillis());
  304. // Iterator it = files.iterator();
  305. // while (!isStopRequested() && it.hasNext()) {
  306. // File f = (File)it.next();
  307. // if (pathMap.get(f.getPath()) == null) {
  308. // // may reuse cache across compiles from ides...
  309. // try {
  310. // pathMap.put(f.getPath(),f.getCanonicalPath());
  311. // } catch (IOException ex) {
  312. // pathMap.put(f.getPath(),f.getPath());
  313. // }
  314. // }
  315. // }
  316. // System.out.println("Cached " + files.size());
  317. // setCacheInUse(true);
  318. // System.out.println("Cache populated: " + System.currentTimeMillis());
  319. // }
  320. // }.start();
  321. // }
  322. //
  323. // /**
  324. // * Stop pre-populating the cache - our customers are ready to use it.
  325. // * If there are any cache misses from this point on, we'll populate
  326. // the
  327. // * cache as we go.
  328. // * The handover is done this way to ensure that only one thread is
  329. // ever
  330. // * accessing the cache, and that we minimize synchronization.
  331. // */
  332. // public synchronized void handover() {
  333. // if (!isCacheInUse()) {
  334. // requestStop();
  335. // try {
  336. // while (!isCacheInUse()) wait();
  337. // } catch (InterruptedException intEx) { } // just continue
  338. // }
  339. // }
  340. public String get(File f) {
  341. // if (!cacheInUse) { // unsynchronized test - should never be
  342. // parallel
  343. // // threads at this point
  344. // throw new IllegalStateException(
  345. // "Must take ownership of cache before using by calling " +
  346. // "handover()");
  347. // }
  348. String ret = pathMap.get(f.getPath());
  349. if (ret == null) {
  350. try {
  351. ret = f.getCanonicalPath();
  352. } catch (IOException ioEx) {
  353. ret = f.getPath();
  354. }
  355. pathMap.put(f.getPath(), ret);
  356. if (pathMap.size() > MAX_SIZE) {
  357. pathMap.clear();
  358. }
  359. }
  360. return ret;
  361. }
  362. }
  363. // SECRETAPI
  364. public static void setReporting(String filename, boolean dModel, boolean dRels, boolean dDeltaProcessing, boolean deletefile) {
  365. reporting = true;
  366. dumpModel = dModel;
  367. dumpRelationships = dRels;
  368. dumpDeltaProcessing = dDeltaProcessing;
  369. if (deletefile) {
  370. new File(filename).delete();
  371. }
  372. dumpFilename = filename;
  373. }
  374. public static void setReporting(String filename, boolean dModel, boolean dRels, boolean dDeltaProcessing, boolean deletefile,
  375. IModelFilter aFilter) {
  376. setReporting(filename, dModel, dRels, dDeltaProcessing, deletefile);
  377. modelFilter = aFilter;
  378. }
  379. public static boolean isReporting() {
  380. return reporting;
  381. }
  382. public static void setDontReport() {
  383. reporting = false;
  384. dumpDeltaProcessing = false;
  385. dumpModel = false;
  386. dumpRelationships = false;
  387. }
  388. // NB. If the format of this report changes then the model tests
  389. // (@see org.aspectj.systemtest.model.ModelTestCase) will fail in
  390. // their comparison. The tests are assuming that both the model
  391. // and relationship map are reported and as a consequence single
  392. // testcases test that both the model and relationship map are correct.
  393. public void reportModelInfo(String reasonForReport) {
  394. if (!dumpModel && !dumpRelationships) {
  395. return;
  396. }
  397. try {
  398. FileWriter fw = new FileWriter(dumpFilename, true);
  399. BufferedWriter bw = new BufferedWriter(fw);
  400. if (dumpModel) {
  401. bw.write("=== MODEL STATUS REPORT ========= " + reasonForReport + "\n");
  402. dumptree(bw, hierarchy.getRoot(), 0);
  403. bw.write("=== END OF MODEL REPORT =========\n");
  404. }
  405. if (dumpRelationships) {
  406. bw.write("=== RELATIONSHIPS REPORT ========= " + reasonForReport + "\n");
  407. dumprels(bw);
  408. bw.write("=== END OF RELATIONSHIPS REPORT ==\n");
  409. }
  410. Properties p = summarizeModel().getProperties();
  411. Enumeration<Object> pkeyenum = p.keys();
  412. bw.write("=== Properties of the model and relationships map =====\n");
  413. while (pkeyenum.hasMoreElements()) {
  414. String pkey = (String) pkeyenum.nextElement();
  415. bw.write(pkey + "=" + p.getProperty(pkey) + "\n");
  416. }
  417. bw.flush();
  418. fw.close();
  419. } catch (IOException e) {
  420. System.err.println("InternalError: Unable to report model information:");
  421. e.printStackTrace();
  422. }
  423. }
  424. public static void dumptree(Writer w, IProgramElement node, int indent) throws IOException {
  425. for (int i = 0; i < indent; i++) {
  426. w.write(" ");
  427. }
  428. String loc = "";
  429. if (node != null) {
  430. if (node.getSourceLocation() != null) {
  431. loc = node.getSourceLocation().toString();
  432. if (modelFilter != null) {
  433. loc = modelFilter.processFilelocation(loc);
  434. }
  435. }
  436. }
  437. w.write(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc + "\n");
  438. if (node != null) {
  439. for (IProgramElement child : node.getChildren()) {
  440. dumptree(w, child, indent + 2);
  441. }
  442. }
  443. }
  444. public static void dumptree(IProgramElement node, int indent) throws IOException {
  445. for (int i = 0; i < indent; i++) {
  446. System.out.print(" ");
  447. }
  448. String loc = "";
  449. if (node != null) {
  450. if (node.getSourceLocation() != null) {
  451. loc = node.getSourceLocation().toString();
  452. }
  453. }
  454. System.out.println(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc);
  455. if (node != null) {
  456. for (IProgramElement child : node.getChildren()) {
  457. dumptree(child, indent + 2);
  458. }
  459. }
  460. }
  461. public void dumprels(Writer w) throws IOException {
  462. int ctr = 1;
  463. Set<String> entries = mapper.getEntries();
  464. for (String hid : entries) {
  465. List<IRelationship> rels = mapper.get(hid);
  466. for (IRelationship ir : rels) {
  467. List<String> targets = ir.getTargets();
  468. for (String thid : targets) {
  469. StringBuffer sb = new StringBuffer();
  470. if (modelFilter == null || modelFilter.wantsHandleIds()) {
  471. sb.append("Hid:" + (ctr++) + ":");
  472. }
  473. sb.append("(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") " + thid + "\n");
  474. w.write(sb.toString());
  475. }
  476. }
  477. }
  478. }
  479. private void dumprelsStderr(String key) {
  480. System.err.println("Relationships dump follows: " + key);
  481. int ctr = 1;
  482. Set<String> entries = mapper.getEntries();
  483. for (String hid : entries) {
  484. for (IRelationship ir : mapper.get(hid)) {
  485. List<String> targets = ir.getTargets();
  486. for (String thid : targets) {
  487. System.err.println("Hid:" + (ctr++) + ":(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") "
  488. + thid);
  489. }
  490. }
  491. }
  492. System.err.println("End of relationships dump for: " + key);
  493. }
  494. // ===================== DELTA PROCESSING CODE ============== start
  495. // ==========//
  496. /**
  497. * Removes the hierarchy structure for the specified files from the structure model. Returns true if it deleted anything
  498. */
  499. public boolean removeStructureModelForFiles(Writer fw, Collection<File> files) throws IOException {
  500. boolean modelModified = false;
  501. Set<String> deletedNodes = new HashSet<String>();
  502. for (File fileForCompilation : files) {
  503. String correctedPath = getCanonicalFilePath(fileForCompilation);
  504. IProgramElement progElem = (IProgramElement) hierarchy.findInFileMap(correctedPath);
  505. if (progElem != null) {
  506. // Found it, let's remove it
  507. if (dumpDeltaProcessing) {
  508. fw.write("Deleting " + progElem + " node for file " + fileForCompilation + "\n");
  509. }
  510. removeNode(progElem);
  511. lastBuildChanges.add(fileForCompilation);
  512. deletedNodes.add(getCanonicalFilePath(progElem.getSourceLocation().getSourceFile()));
  513. if (!hierarchy.removeFromFileMap(correctedPath)) {
  514. throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: " + correctedPath
  515. + " from the filemap");
  516. }
  517. modelModified = true;
  518. }
  519. }
  520. if (modelModified) {
  521. hierarchy.updateHandleMap(deletedNodes);
  522. }
  523. return modelModified;
  524. }
  525. public void processDelta(Collection<File> files_tobecompiled, Set<File> files_added, Set<File> files_deleted) {
  526. try {
  527. Writer fw = null;
  528. // Are we recording this ?
  529. if (dumpDeltaProcessing) {
  530. FileWriter filew = new FileWriter(dumpFilename, true);
  531. fw = new BufferedWriter(filew);
  532. fw.write("=== Processing delta changes for the model ===\n");
  533. fw.write("Files for compilation:#" + files_tobecompiled.size() + ":" + files_tobecompiled + "\n");
  534. fw.write("Files added :#" + files_added.size() + ":" + files_added + "\n");
  535. fw.write("Files deleted :#" + files_deleted.size() + ":" + files_deleted + "\n");
  536. }
  537. long stime = System.currentTimeMillis();
  538. // Let's remove all the files that are deleted on this compile
  539. removeStructureModelForFiles(fw, files_deleted);
  540. long etime1 = System.currentTimeMillis(); // etime1-stime = time to
  541. // fix up the model
  542. repairRelationships(fw);
  543. long etime2 = System.currentTimeMillis(); // etime2-stime = time to
  544. // repair the
  545. // relationship map
  546. removeStructureModelForFiles(fw, files_tobecompiled);
  547. if (dumpDeltaProcessing) {
  548. fw.write("===== Delta Processing timing ==========\n");
  549. fw.write("Hierarchy=" + (etime1 - stime) + "ms Relationshipmap=" + (etime2 - etime1) + "ms\n");
  550. fw.write("===== Traversal ========================\n");
  551. // fw.write("Source handles processed="+srchandlecounter+"\n");
  552. // fw.write("Target handles processed="+tgthandlecounter+"\n");
  553. fw.write("========================================\n");
  554. fw.flush();
  555. fw.close();
  556. }
  557. reportModelInfo("After delta processing");
  558. } catch (IOException e) {
  559. e.printStackTrace();
  560. }
  561. }
  562. private String getTypeNameFromHandle(String handle, Map<String, String> cache) {
  563. try {
  564. String typename = cache.get(handle);
  565. if (typename != null) {
  566. return typename;
  567. }
  568. // inpath handle - but for which type?
  569. // let's do it the slow way, we can optimize this with a cache perhaps
  570. int hasPackage = handle.indexOf(HandleProviderDelimiter.PACKAGEFRAGMENT.getDelimiter());
  571. int typeLocation = handle.indexOf(HandleProviderDelimiter.TYPE.getDelimiter());
  572. if (typeLocation == -1) {
  573. typeLocation = handle.indexOf(HandleProviderDelimiter.ASPECT_TYPE.getDelimiter());
  574. }
  575. if (typeLocation == -1) {
  576. // unexpected - time to give up
  577. return "";
  578. }
  579. StringBuffer qualifiedTypeNameFromHandle = new StringBuffer();
  580. if (hasPackage != -1) {
  581. int classfileLoc = handle.indexOf(HandleProviderDelimiter.CLASSFILE.getDelimiter(), hasPackage);
  582. qualifiedTypeNameFromHandle.append(handle.substring(hasPackage + 1, classfileLoc));
  583. qualifiedTypeNameFromHandle.append('.');
  584. }
  585. qualifiedTypeNameFromHandle.append(handle.substring(typeLocation + 1));
  586. typename = qualifiedTypeNameFromHandle.toString();
  587. cache.put(handle, typename);
  588. return typename;
  589. } catch (StringIndexOutOfBoundsException sioobe) {
  590. // debug for 330170
  591. System.err.println("Handle processing problem, the handle is: " + handle);
  592. sioobe.printStackTrace(System.err);
  593. return "";
  594. }
  595. }
  596. /**
  597. * two kinds of relationships
  598. *
  599. * A affects B B affectedBy A
  600. *
  601. * Both of these relationships are added when 'B' is modified. Concrete examples are 'advises/advisedby' or
  602. * 'annotates/annotatedby'.
  603. *
  604. * What we need to do is when 'B' is going to be woven, remove all relationships that may reoccur when it is woven. So - remove
  605. * 'affects' relationships where the target is 'B', remove all 'affectedBy' relationships where the source is 'B'.
  606. *
  607. */
  608. public void removeRelationshipsTargettingThisType(String typename) {
  609. boolean debug = false;
  610. if (debug) {
  611. System.err.println(">>removeRelationshipsTargettingThisType " + typename);
  612. }
  613. String pkg = null;
  614. String type = typename;
  615. int lastSep = typename.lastIndexOf('.');
  616. if (lastSep != -1) {
  617. pkg = typename.substring(0, lastSep);
  618. type = typename.substring(lastSep + 1);
  619. }
  620. boolean didsomething = false;
  621. IProgramElement typeNode = hierarchy.findElementForType(pkg, type);
  622. // Reasons for that being null:
  623. // 1. the file has fundamental errors and so doesn't exist in the model
  624. // (-proceedOnError probably forced us to weave)
  625. if (typeNode == null) {
  626. return;
  627. }
  628. Set<String> sourcesToRemove = new HashSet<String>();
  629. Map<String, String> handleToTypenameCache = new HashMap<String, String>();
  630. // Iterate over the source handles in the relationships map, the aim
  631. // here is to remove any 'affected by'
  632. // relationships where the source of the relationship is the specified
  633. // type (since it will be readded
  634. // when the type is woven)
  635. Set<String> sourcehandlesSet = mapper.getEntries();
  636. List<IRelationship> relationshipsToRemove = new ArrayList<IRelationship>();
  637. for (String hid : sourcehandlesSet) {
  638. if (isPhantomHandle(hid)) {
  639. // inpath handle - but for which type?
  640. // TODO promote cache for reuse during one whole model update
  641. if (!getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
  642. continue;
  643. }
  644. }
  645. IProgramElement sourceElement = hierarchy.getElement(hid);
  646. if (sourceElement == null || sameType(hid, sourceElement, typeNode)) {
  647. // worth continuing as there may be a relationship to remove
  648. relationshipsToRemove.clear();
  649. List<IRelationship> relationships = mapper.get(hid);
  650. for (IRelationship relationship : relationships) {
  651. if (relationship.getKind() == IRelationship.Kind.USES_POINTCUT) {
  652. continue; // these relationships are added at compile
  653. }
  654. // time, argh
  655. if (relationship.isAffects()) {
  656. continue; // we want 'affected by' relationships - (e.g.
  657. }
  658. // advised by)
  659. relationshipsToRemove.add(relationship); // all the relationships can
  660. // be removed, regardless of
  661. // the target(s)
  662. }
  663. // Now, were any relationships emptied during that processing
  664. // and so need removing for this source handle
  665. if (relationshipsToRemove.size() > 0) {
  666. didsomething = true;
  667. if (relationshipsToRemove.size() == relationships.size()) {
  668. sourcesToRemove.add(hid);
  669. } else {
  670. for (IRelationship iRelationship : relationshipsToRemove) {
  671. relationships.remove(iRelationship);
  672. }
  673. }
  674. }
  675. }
  676. }
  677. // Remove sources that have no valid relationships any more
  678. for (String hid : sourcesToRemove) {
  679. // System.err.println(
  680. // " source handle: all relationships have gone for "+hid);
  681. mapper.removeAll(hid);
  682. IProgramElement ipe = hierarchy.getElement(hid);
  683. if (ipe != null) {
  684. // If the relationship was hanging off a 'code' node, delete it.
  685. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  686. if (debug) {
  687. System.err.println(" source handle: it was code node, removing that as well... code=" + ipe + " parent="
  688. + ipe.getParent());
  689. }
  690. removeSingleNode(ipe);
  691. }
  692. }
  693. }
  694. if (debug) {
  695. dumprelsStderr("after processing 'affectedby'");
  696. }
  697. if (didsomething) { // did we do anything?
  698. sourcesToRemove.clear();
  699. // removing 'affects' relationships
  700. if (debug) {
  701. dumprelsStderr("before processing 'affects'");
  702. }
  703. // Iterate over the source handles in the relationships map
  704. sourcehandlesSet = mapper.getEntries();
  705. for (String hid : sourcehandlesSet) {
  706. relationshipsToRemove.clear();
  707. List<IRelationship> relationships = mapper.get(hid);
  708. for (IRelationship rel : relationships) {
  709. if (rel.getKind() == IRelationship.Kind.USES_POINTCUT) {
  710. continue; // these relationships are added at compile
  711. }
  712. // time, argh
  713. if (!rel.isAffects()) {
  714. continue;
  715. }
  716. List<String> targets = rel.getTargets();
  717. List<String> targetsToRemove = new ArrayList<String>();
  718. // find targets that target the type we are interested in,
  719. // they need removing
  720. for (String targethid : targets) {
  721. if (isPhantomHandle(hid) && !getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
  722. continue;
  723. }
  724. // Does this point to the same type?
  725. IProgramElement existingTarget = hierarchy.getElement(targethid);
  726. if (existingTarget == null || sameType(targethid, existingTarget, typeNode)) {
  727. targetsToRemove.add(targethid);
  728. }
  729. }
  730. if (targetsToRemove.size() != 0) {
  731. if (targetsToRemove.size() == targets.size()) {
  732. relationshipsToRemove.add(rel);
  733. } else {
  734. // Remove all the targets that are no longer valid
  735. for (String togo : targetsToRemove) {
  736. targets.remove(togo);
  737. }
  738. }
  739. }
  740. }
  741. // Now, were any relationships emptied during that processing
  742. // and so need removing for this source handle
  743. if (relationshipsToRemove.size() > 0) {
  744. // Are we removing *all* of the relationships for this
  745. // source handle?
  746. if (relationshipsToRemove.size() == relationships.size()) {
  747. sourcesToRemove.add(hid);
  748. } else {
  749. for (IRelationship iRelationship : relationshipsToRemove) {
  750. relationships.remove(iRelationship);
  751. }
  752. }
  753. }
  754. }
  755. // Remove sources that have no valid relationships any more
  756. for (String hid : sourcesToRemove) {
  757. // System.err.println(
  758. // " source handle: all relationships have gone for "+hid);
  759. mapper.removeAll(hid);
  760. IProgramElement ipe = hierarchy.getElement(hid);
  761. if (ipe != null) {
  762. // If the relationship was hanging off a 'code' node, delete
  763. // it.
  764. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  765. if (debug) {
  766. System.err.println(" source handle: it was code node, removing that as well... code=" + ipe
  767. + " parent=" + ipe.getParent());
  768. }
  769. removeSingleNode(ipe);
  770. }
  771. }
  772. }
  773. if (debug) {
  774. dumprelsStderr("after processing 'affects'");
  775. }
  776. }
  777. if (debug) {
  778. System.err.println("<<removeRelationshipsTargettingThisFile");
  779. }
  780. }
  781. /**
  782. * Return true if the target element is in the type specified.
  783. */
  784. private boolean sameType(String hid, IProgramElement target, IProgramElement type) {
  785. IProgramElement containingType = target;
  786. if (target == null) {
  787. throw new RuntimeException("target can't be null!");
  788. }
  789. if (type == null) {
  790. throw new RuntimeException("type can't be null!");
  791. }
  792. if (target.getKind().isSourceFile() || target.getKind().isFile()) { // isFile() covers pr263487
  793. // @AJ aspect with broken relationship endpoint - we couldn't find
  794. // the real
  795. // endpoint (the declare parents or ITD or similar) so defaulted to
  796. // the
  797. // first line of the source file...
  798. // FRAGILE
  799. // Let's assume the worst, and that it is the same type if the
  800. // source files
  801. // are the same. This will break for multiple top level types in a
  802. // file...
  803. if (target.getSourceLocation() == null) {
  804. return false; // these four possibilities should really be FIXED
  805. }
  806. // so we don't have this situation
  807. if (type.getSourceLocation() == null) {
  808. return false;
  809. }
  810. if (target.getSourceLocation().getSourceFile() == null) {
  811. return false;
  812. }
  813. if (type.getSourceLocation().getSourceFile() == null) {
  814. return false;
  815. }
  816. return (target.getSourceLocation().getSourceFile().equals(type.getSourceLocation().getSourceFile()));
  817. }
  818. try {
  819. while (!containingType.getKind().isType()) {
  820. containingType = containingType.getParent();
  821. }
  822. } catch (Throwable t) {
  823. // Example:
  824. // java.lang.RuntimeException: Exception whilst walking up from target X.class kind=(file)
  825. // hid=(=importProb/binaries<x(X.class)
  826. throw new RuntimeException("Exception whilst walking up from target " + target.toLabelString() + " kind=("
  827. + target.getKind() + ") hid=(" + target.getHandleIdentifier() + ")", t);
  828. }
  829. return (type.equals(containingType));
  830. }
  831. /**
  832. * @param handle a JDT like handle, following the form described in AsmRelationshipProvider.findOrFakeUpNode
  833. * @return true if the handle contains ';' - the char indicating that it is a phantom handle
  834. */
  835. private boolean isPhantomHandle(String handle) {
  836. int phantomMarker = handle.indexOf(HandleProviderDelimiter.PHANTOM.getDelimiter());
  837. return phantomMarker != -1
  838. && handle.charAt(phantomMarker - 1) == HandleProviderDelimiter.PACKAGEFRAGMENTROOT.getDelimiter();
  839. }
  840. /**
  841. * Go through all the relationships in the model, if any endpoints no longer exist (the node it points to has been deleted from
  842. * the model) then delete the relationship.
  843. */
  844. private void repairRelationships(Writer fw) {
  845. try {
  846. // IHierarchy model = AsmManager.getDefault().getHierarchy();
  847. // TODO Speed this code up by making this assumption:
  848. // the only piece of the handle that is interesting is the file
  849. // name. We are working at file granularity, if the
  850. // file does not exist (i.e. its not in the filemap) then any handle
  851. // inside that file cannot exist.
  852. if (dumpDeltaProcessing) {
  853. fw.write("Repairing relationships map:\n");
  854. }
  855. // Now sort out the relationships map
  856. // IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
  857. Set<String> sourcesToRemove = new HashSet<String>();
  858. Set<String> nonExistingHandles = new HashSet<String>(); // Cache of handles that we
  859. // *know* are invalid
  860. // int srchandlecounter = 0;
  861. // int tgthandlecounter = 0;
  862. // Iterate over the source handles in the relationships map
  863. Set<String> keyset = mapper.getEntries(); // These are source handles
  864. for (String hid : keyset) {
  865. // srchandlecounter++;
  866. // Do we already know this handle points to nowhere?
  867. if (nonExistingHandles.contains(hid)) {
  868. sourcesToRemove.add(hid);
  869. } else if (!isPhantomHandle(hid)) {
  870. // We better check if it actually exists
  871. IProgramElement existingElement = hierarchy.getElement(hid);
  872. if (dumpDeltaProcessing) {
  873. fw.write("Looking for handle [" + hid + "] in model, found: " + existingElement + "\n");
  874. }
  875. // Did we find it?
  876. if (existingElement == null) {
  877. // No, so delete this relationship
  878. sourcesToRemove.add(hid);
  879. nonExistingHandles.add(hid); // Speed up a bit you swine
  880. } else {
  881. // Ok, so the source is valid, what about the targets?
  882. List<IRelationship> relationships = mapper.get(hid);
  883. List<IRelationship> relationshipsToRemove = new ArrayList<IRelationship>();
  884. // Iterate through the relationships against this source
  885. // handle
  886. for (IRelationship rel : relationships) {
  887. List<String> targets = rel.getTargets();
  888. List<String> targetsToRemove = new ArrayList<String>();
  889. // Iterate through the targets for this relationship
  890. for (String targethid : targets) {
  891. // tgthandlecounter++;
  892. // Do we already know it doesn't exist?
  893. if (nonExistingHandles.contains(targethid)) {
  894. if (dumpDeltaProcessing) {
  895. fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel[" + rel.getName()
  896. + "] does not exist\n");
  897. }
  898. targetsToRemove.add(targethid);
  899. } else if (!isPhantomHandle(targethid)) {
  900. // We better check
  901. IProgramElement existingTarget = hierarchy.getElement(targethid);
  902. if (existingTarget == null) {
  903. if (dumpDeltaProcessing) {
  904. fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel["
  905. + rel.getName() + "] does not exist\n");
  906. }
  907. targetsToRemove.add(targethid);
  908. nonExistingHandles.add(targethid);
  909. }
  910. }
  911. }
  912. // Do we have some targets that need removing?
  913. if (targetsToRemove.size() != 0) {
  914. // Are we removing *all* of the targets for this
  915. // relationship (i.e. removing the relationship)
  916. if (targetsToRemove.size() == targets.size()) {
  917. if (dumpDeltaProcessing) {
  918. fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
  919. + "]: removing it\n");
  920. }
  921. relationshipsToRemove.add(rel);
  922. } else {
  923. // Remove all the targets that are no longer
  924. // valid
  925. for (String togo : targetsToRemove) {
  926. targets.remove(togo);
  927. }
  928. // Should have already been caught above,
  929. // but lets double check ...
  930. if (targets.size() == 0) {
  931. if (dumpDeltaProcessing) {
  932. fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
  933. + "]: removing it\n");
  934. }
  935. relationshipsToRemove.add(rel); // TODO
  936. // Should
  937. // only
  938. // remove
  939. // this
  940. // relationship
  941. // for
  942. // the
  943. // srchid
  944. // ?
  945. }
  946. }
  947. }
  948. }
  949. // Now, were any relationships emptied during that
  950. // processing and so need removing for this source
  951. // handle
  952. if (relationshipsToRemove.size() > 0) {
  953. // Are we removing *all* of the relationships for
  954. // this source handle?
  955. if (relationshipsToRemove.size() == relationships.size()) {
  956. // We know they are all going to go, so just
  957. // delete the source handle.
  958. sourcesToRemove.add(hid);
  959. } else {
  960. // MEMORY LEAK - we don't remove the
  961. // relationships !!
  962. for (IRelationship irel : relationshipsToRemove) {
  963. verifyAssumption(mapper.remove(hid, irel), "Failed to remove relationship " + irel.getName()
  964. + " for shid " + hid);
  965. }
  966. List<IRelationship> rels = mapper.get(hid);
  967. if (rels == null || rels.size() == 0) {
  968. sourcesToRemove.add(hid);
  969. }
  970. }
  971. }
  972. }
  973. }
  974. }
  975. // Remove sources that have no valid relationships any more
  976. for (String hid : sourcesToRemove) {
  977. mapper.removeAll(hid);
  978. IProgramElement ipe = hierarchy.getElement(hid);
  979. if (ipe != null) {
  980. // If the relationship was hanging off a 'code' node, delete
  981. // it.
  982. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  983. // System.err.println("Deleting code node");
  984. removeSingleNode(ipe);
  985. }
  986. }
  987. }
  988. } catch (IOException ioe) {
  989. System.err.println("Failed to repair relationships:");
  990. ioe.printStackTrace();
  991. }
  992. }
  993. /**
  994. * Removes a specified program element from the structure model. We go to the parent of the program element, ask for all its
  995. * children and remove the node we want to delete from the list of children.
  996. */
  997. private void removeSingleNode(IProgramElement progElem) {
  998. if (progElem == null) {
  999. throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
  1000. }
  1001. boolean deleteOK = false;
  1002. IProgramElement parent = progElem.getParent();
  1003. List<IProgramElement> kids = parent.getChildren();
  1004. for (int i = 0, max = kids.size(); i < max; i++) {
  1005. if (kids.get(i).equals(progElem)) {
  1006. kids.remove(i);
  1007. deleteOK = true;
  1008. break;
  1009. }
  1010. }
  1011. if (!deleteOK) {
  1012. System.err.println("unexpectedly failed to delete node from model. hid=" + progElem.getHandleIdentifier());
  1013. }
  1014. }
  1015. /**
  1016. * Removes a specified program element from the structure model. Two processing stages:
  1017. * <p>
  1018. * First: We go to the parent of the program element, ask for all its children and remove the node we want to delete from the
  1019. * list of children.
  1020. * <p>
  1021. * Second:We check if that parent has any other children. If it has no other children and it is either a CODE node or a PACKAGE
  1022. * node, we delete it too.
  1023. */
  1024. private void removeNode(IProgramElement progElem) {
  1025. // StringBuffer flightrecorder = new StringBuffer();
  1026. try {
  1027. // flightrecorder.append("In removeNode, about to chuck away: "+
  1028. // progElem+"\n");
  1029. if (progElem == null) {
  1030. throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
  1031. }
  1032. // boolean deleteOK = false;
  1033. IProgramElement parent = progElem.getParent();
  1034. // flightrecorder.append("Parent of it is "+parent+"\n");
  1035. List<IProgramElement> kids = parent.getChildren();
  1036. // flightrecorder.append("Which has "+kids.size()+" kids\n");
  1037. for (int i = 0; i < kids.size(); i++) {
  1038. // flightrecorder.append("Comparing with "+kids.get(i)+"\n");
  1039. if (kids.get(i).equals(progElem)) {
  1040. kids.remove(i);
  1041. // flightrecorder.append("Removing it\n");
  1042. // deleteOK=true;
  1043. break;
  1044. }
  1045. }
  1046. // verifyAssumption(deleteOK,flightrecorder.toString());
  1047. // Are there any kids left for this node?
  1048. if (parent.getChildren().size() == 0
  1049. && parent.getParent() != null
  1050. && (parent.getKind().equals(IProgramElement.Kind.CODE) || parent.getKind().equals(IProgramElement.Kind.PACKAGE))) {
  1051. // This node is on its own, we should trim it too *as long as
  1052. // its not a structural node* which we currently check by
  1053. // making sure its a code node
  1054. // We should trim if it
  1055. // System.err.println("Deleting parent:"+parent);
  1056. removeNode(parent);
  1057. }
  1058. } catch (NullPointerException npe) {
  1059. // Occurred when commenting out other 2 ras classes in wsif??
  1060. // reproducable?
  1061. // System.err.println(flightrecorder.toString());
  1062. npe.printStackTrace();
  1063. }
  1064. }
  1065. public static void verifyAssumption(boolean b, String info) {
  1066. if (!b) {
  1067. System.err.println("=========== ASSERTION IS NOT TRUE =========v");
  1068. System.err.println(info);
  1069. Thread.dumpStack();
  1070. System.err.println("=========== ASSERTION IS NOT TRUE =========^");
  1071. throw new RuntimeException("Assertion is false");
  1072. }
  1073. }
  1074. public static void verifyAssumption(boolean b) {
  1075. if (!b) {
  1076. Thread.dumpStack();
  1077. throw new RuntimeException("Assertion is false");
  1078. }
  1079. }
  1080. // ===================== DELTA PROCESSING CODE ============== end
  1081. // ==========//
  1082. /**
  1083. * A ModelInfo object captures basic information about the structure model. It is used for testing and producing debug info.
  1084. */
  1085. public static class ModelInfo {
  1086. private final Hashtable<String, Integer> nodeTypeCount = new Hashtable<String, Integer>();
  1087. private final Properties extraProperties = new Properties();
  1088. private ModelInfo(IHierarchy hierarchy, IRelationshipMap relationshipMap) {
  1089. IProgramElement ipe = hierarchy.getRoot();
  1090. walkModel(ipe);
  1091. recordStat("FileMapSize", new Integer(hierarchy.getFileMapEntrySet().size()).toString());
  1092. recordStat("RelationshipMapSize", new Integer(relationshipMap.getEntries().size()).toString());
  1093. }
  1094. private void walkModel(IProgramElement ipe) {
  1095. countNode(ipe);
  1096. for (IProgramElement child : ipe.getChildren()) {
  1097. walkModel(child);
  1098. }
  1099. }
  1100. private void countNode(IProgramElement ipe) {
  1101. String node = ipe.getKind().toString();
  1102. Integer ctr = nodeTypeCount.get(node);
  1103. if (ctr == null) {
  1104. nodeTypeCount.put(node, new Integer(1));
  1105. } else {
  1106. ctr = new Integer(ctr.intValue() + 1);
  1107. nodeTypeCount.put(node, ctr);
  1108. }
  1109. }
  1110. public String toString() {
  1111. StringBuffer sb = new StringBuffer();
  1112. sb.append("Model node summary:\n");
  1113. Enumeration<String> nodeKeys = nodeTypeCount.keys();
  1114. while (nodeKeys.hasMoreElements()) {
  1115. String key = nodeKeys.nextElement();
  1116. Integer ct = nodeTypeCount.get(key);
  1117. sb.append(key + "=" + ct + "\n");
  1118. }
  1119. sb.append("Model stats:\n");
  1120. Enumeration<Object> ks = extraProperties.keys();
  1121. while (ks.hasMoreElements()) {
  1122. String k = (String) ks.nextElement();
  1123. String v = extraProperties.getProperty(k);
  1124. sb.append(k + "=" + v + "\n");
  1125. }
  1126. return sb.toString();
  1127. }
  1128. public Properties getProperties() {
  1129. Properties p = new Properties();
  1130. for (Map.Entry<String, Integer> entry : nodeTypeCount.entrySet()) {
  1131. p.setProperty(entry.getKey(), entry.getValue().toString());
  1132. }
  1133. p.putAll(extraProperties);
  1134. return p;
  1135. }
  1136. public void recordStat(String string, String string2) {
  1137. extraProperties.setProperty(string, string2);
  1138. }
  1139. }
  1140. public ModelInfo summarizeModel() {
  1141. return new ModelInfo(getHierarchy(), getRelationshipMap());
  1142. }
  1143. /**
  1144. * Set to indicate whether we are currently building a structure model, should be set up front.
  1145. */
  1146. // public static void setCreatingModel(boolean b) {
  1147. // creatingModel = b;
  1148. // }
  1149. //
  1150. // /**
  1151. // * returns true if we are currently generating a structure model, enables guarding of expensive operations on an empty/null
  1152. // * model.
  1153. // */
  1154. // public static boolean isCreatingModel() {
  1155. // return creatingModel;
  1156. // }
  1157. public static void setCompletingTypeBindings(boolean b) {
  1158. completingTypeBindings = b;
  1159. }
  1160. public static boolean isCompletingTypeBindings() {
  1161. return completingTypeBindings;
  1162. }
  1163. // public void setRelationshipMap(IRelationshipMap irm) {
  1164. // mapper = irm;
  1165. // }
  1166. //
  1167. // public void setHierarchy(IHierarchy ih) {
  1168. // hierarchy = ih;
  1169. // }
  1170. public void resetDeltaProcessing() {
  1171. lastBuildChanges.clear();
  1172. aspectsWeavingInLastBuild.clear();
  1173. }
  1174. /**
  1175. * @return the Set of files for which the structure model was modified (they may have been removed or otherwise rebuilt). Set is
  1176. * empty for a full build.
  1177. */
  1178. public Set<File> getModelChangesOnLastBuild() {
  1179. return lastBuildChanges;
  1180. }
  1181. /**
  1182. * @return the Set of aspects that wove files on the last build (either incremental or full build)
  1183. */
  1184. public Set<File> getAspectsWeavingFilesOnLastBuild() {
  1185. return aspectsWeavingInLastBuild;
  1186. }
  1187. public void addAspectInEffectThisBuild(File f) {
  1188. aspectsWeavingInLastBuild.add(f);
  1189. }
  1190. public static void setLastActiveStructureModel(AsmManager structureModel) {
  1191. if (recordingLastActiveStructureModel) {
  1192. lastActiveStructureModel = structureModel;
  1193. }
  1194. }
  1195. public String getHandleElementForInpath(String binaryPath) {
  1196. return inpathMap.get(new File(binaryPath));
  1197. }
  1198. }