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

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