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 44KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  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 (Iterator<IProgramElement> it = peNodes.iterator(); it.hasNext();) {
  140. IProgramElement peNode = it.next();
  141. List<IProgramElement> entries = new ArrayList<IProgramElement>();
  142. entries.add(peNode);
  143. ISourceLocation sourceLoc = peNode.getSourceLocation();
  144. if (null != sourceLoc) {
  145. Integer hash = new Integer(sourceLoc.getLine());
  146. List<IProgramElement> existingEntry = annotations.get(hash);
  147. if (existingEntry != null) {
  148. entries.addAll(existingEntry);
  149. }
  150. annotations.put(hash, entries);
  151. }
  152. }
  153. return annotations;
  154. }
  155. }
  156. private void getAllStructureChildren(IProgramElement node, List<IProgramElement> result, boolean showSubMember,
  157. boolean showMemberAndType) {
  158. List<IProgramElement> children = node.getChildren();
  159. if (node.getChildren() == null) {
  160. return;
  161. }
  162. for (IProgramElement next : children) {
  163. List<IRelationship> rels = mapper.get(next);
  164. if (next != null
  165. && ((next.getKind() == IProgramElement.Kind.CODE && showSubMember) || (next.getKind() != IProgramElement.Kind.CODE && showMemberAndType))
  166. && rels != null && rels.size() > 0) {
  167. result.add(next);
  168. }
  169. getAllStructureChildren(next, result, showSubMember, showMemberAndType);
  170. }
  171. }
  172. public void addListener(IHierarchyListener listener) {
  173. structureListeners.add(listener);
  174. }
  175. public void removeStructureListener(IHierarchyListener listener) {
  176. structureListeners.remove(listener);
  177. }
  178. // this shouldn't be needed - but none of the people that add listeners
  179. // in the test suite ever remove them. AMC added this to be called in
  180. // setup() so that the test cases would cease leaking listeners and go
  181. // back to executing at a reasonable speed.
  182. public void removeAllListeners() {
  183. structureListeners.clear();
  184. }
  185. private void notifyListeners() {
  186. for (IHierarchyListener listener : structureListeners) {
  187. listener.elementsUpdated(hierarchy);
  188. }
  189. }
  190. public IElementHandleProvider getHandleProvider() {
  191. return handleProvider;
  192. }
  193. public void setHandleProvider(IElementHandleProvider handleProvider) {
  194. this.handleProvider = handleProvider;
  195. }
  196. public void writeStructureModel(String configFilePath) {
  197. try {
  198. String filePath = genExternFilePath(configFilePath);
  199. FileOutputStream fos = new FileOutputStream(filePath);
  200. ObjectOutputStream s = new ObjectOutputStream(fos);
  201. s.writeObject(hierarchy); // Store the program element tree
  202. s.writeObject(mapper); // Store the relationships
  203. s.flush();
  204. fos.flush();
  205. fos.close();
  206. s.close();
  207. } catch (IOException e) {
  208. // System.err.println("AsmManager: Unable to write structure model: "
  209. // +configFilePath+" because of:");
  210. // e.printStackTrace();
  211. }
  212. }
  213. /**
  214. * @param configFilePath path to an ".lst" file
  215. */
  216. public void readStructureModel(String configFilePath) {
  217. boolean hierarchyReadOK = false;
  218. try {
  219. if (configFilePath == null) {
  220. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  221. } else {
  222. String filePath = genExternFilePath(configFilePath);
  223. FileInputStream in = new FileInputStream(filePath);
  224. ObjectInputStream s = new ObjectInputStream(in);
  225. hierarchy = (AspectJElementHierarchy) s.readObject();
  226. ((AspectJElementHierarchy) hierarchy).setAsmManager(this);
  227. hierarchyReadOK = true;
  228. mapper = (RelationshipMap) s.readObject();
  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 (int i = 0; i < relationshipsToRemove.size(); i++) {
  671. relationships.remove(relationshipsToRemove.get(i));
  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 (int i = 0; i < relationshipsToRemove.size(); i++) {
  750. relationships.remove(relationshipsToRemove.get(i));
  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 (Iterator<IRelationship> reliter = relationships.iterator(); reliter.hasNext();) {
  887. IRelationship rel = reliter.next();
  888. List<String> targets = rel.getTargets();
  889. List<String> targetsToRemove = new ArrayList<String>();
  890. // Iterate through the targets for this relationship
  891. for (Iterator<String> targetIter = targets.iterator(); targetIter.hasNext();) {
  892. String targethid = targetIter.next();
  893. tgthandlecounter++;
  894. // Do we already know it doesn't exist?
  895. if (nonExistingHandles.contains(targethid)) {
  896. if (dumpDeltaProcessing) {
  897. fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel[" + rel.getName()
  898. + "] does not exist\n");
  899. }
  900. targetsToRemove.add(targethid);
  901. } else if (!isPhantomHandle(targethid)) {
  902. // We better check
  903. IProgramElement existingTarget = hierarchy.getElement(targethid);
  904. if (existingTarget == null) {
  905. if (dumpDeltaProcessing) {
  906. fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel["
  907. + rel.getName() + "] does not exist\n");
  908. }
  909. targetsToRemove.add(targethid);
  910. nonExistingHandles.add(targethid);
  911. }
  912. }
  913. }
  914. // Do we have some targets that need removing?
  915. if (targetsToRemove.size() != 0) {
  916. // Are we removing *all* of the targets for this
  917. // relationship (i.e. removing the relationship)
  918. if (targetsToRemove.size() == targets.size()) {
  919. if (dumpDeltaProcessing) {
  920. fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
  921. + "]: removing it\n");
  922. }
  923. relationshipsToRemove.add(rel);
  924. } else {
  925. // Remove all the targets that are no longer
  926. // valid
  927. for (String togo : targetsToRemove) {
  928. targets.remove(togo);
  929. }
  930. // Should have already been caught above,
  931. // but lets double check ...
  932. if (targets.size() == 0) {
  933. if (dumpDeltaProcessing) {
  934. fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
  935. + "]: removing it\n");
  936. }
  937. relationshipsToRemove.add(rel); // TODO
  938. // Should
  939. // only
  940. // remove
  941. // this
  942. // relationship
  943. // for
  944. // the
  945. // srchid
  946. // ?
  947. }
  948. }
  949. }
  950. }
  951. // Now, were any relationships emptied during that
  952. // processing and so need removing for this source
  953. // handle
  954. if (relationshipsToRemove.size() > 0) {
  955. // Are we removing *all* of the relationships for
  956. // this source handle?
  957. if (relationshipsToRemove.size() == relationships.size()) {
  958. // We know they are all going to go, so just
  959. // delete the source handle.
  960. sourcesToRemove.add(hid);
  961. } else {
  962. // MEMORY LEAK - we don't remove the
  963. // relationships !!
  964. for (int i = 0; i < relationshipsToRemove.size(); i++) {
  965. IRelationship irel = relationshipsToRemove.get(i);
  966. verifyAssumption(mapper.remove(hid, irel), "Failed to remove relationship " + irel.getName()
  967. + " for shid " + hid);
  968. }
  969. List<IRelationship> rels = mapper.get(hid);
  970. if (rels == null || rels.size() == 0) {
  971. sourcesToRemove.add(hid);
  972. }
  973. }
  974. }
  975. }
  976. }
  977. }
  978. // Remove sources that have no valid relationships any more
  979. for (Iterator<String> srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
  980. String hid = srciter.next();
  981. mapper.removeAll(hid);
  982. IProgramElement ipe = hierarchy.getElement(hid);
  983. if (ipe != null) {
  984. // If the relationship was hanging off a 'code' node, delete
  985. // it.
  986. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  987. // System.err.println("Deleting code node");
  988. removeSingleNode(ipe);
  989. }
  990. }
  991. }
  992. } catch (IOException ioe) {
  993. System.err.println("Failed to repair relationships:");
  994. ioe.printStackTrace();
  995. }
  996. }
  997. /**
  998. * Removes a specified program element from the structure model. We go to the parent of the program element, ask for all its
  999. * children and remove the node we want to delete from the list of children.
  1000. */
  1001. private void removeSingleNode(IProgramElement progElem) {
  1002. if (progElem == null) {
  1003. throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
  1004. }
  1005. boolean deleteOK = false;
  1006. IProgramElement parent = progElem.getParent();
  1007. List<IProgramElement> kids = parent.getChildren();
  1008. for (int i = 0, max = kids.size(); i < max; i++) {
  1009. if (kids.get(i).equals(progElem)) {
  1010. kids.remove(i);
  1011. deleteOK = true;
  1012. break;
  1013. }
  1014. }
  1015. if (!deleteOK) {
  1016. System.err.println("unexpectedly failed to delete node from model. hid=" + progElem.getHandleIdentifier());
  1017. }
  1018. }
  1019. /**
  1020. * Removes a specified program element from the structure model. Two processing stages:
  1021. * <p>
  1022. * 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
  1023. * list of children.
  1024. * <p>
  1025. * 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
  1026. * node, we delete it too.
  1027. */
  1028. private void removeNode(IProgramElement progElem) {
  1029. // StringBuffer flightrecorder = new StringBuffer();
  1030. try {
  1031. // flightrecorder.append("In removeNode, about to chuck away: "+
  1032. // progElem+"\n");
  1033. if (progElem == null) {
  1034. throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
  1035. }
  1036. // boolean deleteOK = false;
  1037. IProgramElement parent = progElem.getParent();
  1038. // flightrecorder.append("Parent of it is "+parent+"\n");
  1039. List<IProgramElement> kids = parent.getChildren();
  1040. // flightrecorder.append("Which has "+kids.size()+" kids\n");
  1041. for (int i = 0; i < kids.size(); i++) {
  1042. // flightrecorder.append("Comparing with "+kids.get(i)+"\n");
  1043. if (kids.get(i).equals(progElem)) {
  1044. kids.remove(i);
  1045. // flightrecorder.append("Removing it\n");
  1046. // deleteOK=true;
  1047. break;
  1048. }
  1049. }
  1050. // verifyAssumption(deleteOK,flightrecorder.toString());
  1051. // Are there any kids left for this node?
  1052. if (parent.getChildren().size() == 0
  1053. && parent.getParent() != null
  1054. && (parent.getKind().equals(IProgramElement.Kind.CODE) || parent.getKind().equals(IProgramElement.Kind.PACKAGE))) {
  1055. // This node is on its own, we should trim it too *as long as
  1056. // its not a structural node* which we currently check by
  1057. // making sure its a code node
  1058. // We should trim if it
  1059. // System.err.println("Deleting parent:"+parent);
  1060. removeNode(parent);
  1061. }
  1062. } catch (NullPointerException npe) {
  1063. // Occurred when commenting out other 2 ras classes in wsif??
  1064. // reproducable?
  1065. // System.err.println(flightrecorder.toString());
  1066. npe.printStackTrace();
  1067. }
  1068. }
  1069. public static void verifyAssumption(boolean b, String info) {
  1070. if (!b) {
  1071. System.err.println("=========== ASSERTION IS NOT TRUE =========v");
  1072. System.err.println(info);
  1073. Thread.dumpStack();
  1074. System.err.println("=========== ASSERTION IS NOT TRUE =========^");
  1075. throw new RuntimeException("Assertion is false");
  1076. }
  1077. }
  1078. public static void verifyAssumption(boolean b) {
  1079. if (!b) {
  1080. Thread.dumpStack();
  1081. throw new RuntimeException("Assertion is false");
  1082. }
  1083. }
  1084. // ===================== DELTA PROCESSING CODE ============== end
  1085. // ==========//
  1086. /**
  1087. * A ModelInfo object captures basic information about the structure model. It is used for testing and producing debug info.
  1088. */
  1089. public static class ModelInfo {
  1090. private final Hashtable<String, Integer> nodeTypeCount = new Hashtable<String, Integer>();
  1091. private final Properties extraProperties = new Properties();
  1092. private ModelInfo(IHierarchy hierarchy, IRelationshipMap relationshipMap) {
  1093. IProgramElement ipe = hierarchy.getRoot();
  1094. walkModel(ipe);
  1095. recordStat("FileMapSize", new Integer(hierarchy.getFileMapEntrySet().size()).toString());
  1096. recordStat("RelationshipMapSize", new Integer(relationshipMap.getEntries().size()).toString());
  1097. }
  1098. private void walkModel(IProgramElement ipe) {
  1099. countNode(ipe);
  1100. for (IProgramElement child : ipe.getChildren()) {
  1101. walkModel(child);
  1102. }
  1103. }
  1104. private void countNode(IProgramElement ipe) {
  1105. String node = ipe.getKind().toString();
  1106. Integer ctr = nodeTypeCount.get(node);
  1107. if (ctr == null) {
  1108. nodeTypeCount.put(node, new Integer(1));
  1109. } else {
  1110. ctr = new Integer(ctr.intValue() + 1);
  1111. nodeTypeCount.put(node, ctr);
  1112. }
  1113. }
  1114. public String toString() {
  1115. StringBuffer sb = new StringBuffer();
  1116. sb.append("Model node summary:\n");
  1117. Enumeration<String> nodeKeys = nodeTypeCount.keys();
  1118. while (nodeKeys.hasMoreElements()) {
  1119. String key = nodeKeys.nextElement();
  1120. Integer ct = nodeTypeCount.get(key);
  1121. sb.append(key + "=" + ct + "\n");
  1122. }
  1123. sb.append("Model stats:\n");
  1124. Enumeration<Object> ks = extraProperties.keys();
  1125. while (ks.hasMoreElements()) {
  1126. String k = (String) ks.nextElement();
  1127. String v = extraProperties.getProperty(k);
  1128. sb.append(k + "=" + v + "\n");
  1129. }
  1130. return sb.toString();
  1131. }
  1132. public Properties getProperties() {
  1133. Properties p = new Properties();
  1134. for (Map.Entry<String, Integer> entry : nodeTypeCount.entrySet()) {
  1135. p.setProperty(entry.getKey(), entry.getValue().toString());
  1136. }
  1137. p.putAll(extraProperties);
  1138. return p;
  1139. }
  1140. public void recordStat(String string, String string2) {
  1141. extraProperties.setProperty(string, string2);
  1142. }
  1143. }
  1144. public ModelInfo summarizeModel() {
  1145. return new ModelInfo(getHierarchy(), getRelationshipMap());
  1146. }
  1147. /**
  1148. * Set to indicate whether we are currently building a structure model, should be set up front.
  1149. */
  1150. // public static void setCreatingModel(boolean b) {
  1151. // creatingModel = b;
  1152. // }
  1153. //
  1154. // /**
  1155. // * returns true if we are currently generating a structure model, enables guarding of expensive operations on an empty/null
  1156. // * model.
  1157. // */
  1158. // public static boolean isCreatingModel() {
  1159. // return creatingModel;
  1160. // }
  1161. public static void setCompletingTypeBindings(boolean b) {
  1162. completingTypeBindings = b;
  1163. }
  1164. public static boolean isCompletingTypeBindings() {
  1165. return completingTypeBindings;
  1166. }
  1167. // public void setRelationshipMap(IRelationshipMap irm) {
  1168. // mapper = irm;
  1169. // }
  1170. //
  1171. // public void setHierarchy(IHierarchy ih) {
  1172. // hierarchy = ih;
  1173. // }
  1174. public void resetDeltaProcessing() {
  1175. lastBuildChanges.clear();
  1176. aspectsWeavingInLastBuild.clear();
  1177. }
  1178. /**
  1179. * @return the Set of files for which the structure model was modified (they may have been removed or otherwise rebuilt). Set is
  1180. * empty for a full build.
  1181. */
  1182. public Set<File> getModelChangesOnLastBuild() {
  1183. return lastBuildChanges;
  1184. }
  1185. /**
  1186. * @return the Set of aspects that wove files on the last build (either incremental or full build)
  1187. */
  1188. public Set<File> getAspectsWeavingFilesOnLastBuild() {
  1189. return aspectsWeavingInLastBuild;
  1190. }
  1191. public void addAspectInEffectThisBuild(File f) {
  1192. aspectsWeavingInLastBuild.add(f);
  1193. }
  1194. public static void setLastActiveStructureModel(AsmManager structureModel) {
  1195. if (recordingLastActiveStructureModel) {
  1196. lastActiveStructureModel = structureModel;
  1197. }
  1198. }
  1199. public String getHandleElementForInpath(String binaryPath) {
  1200. return inpathMap.get(new File(binaryPath));
  1201. }
  1202. }