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

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