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

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