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

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