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

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