11
11
* Andy Clement incremental support and switch on/off state
12
12
* ******************************************************************/
15
14
package org.aspectj.asm;
16
import java.io.BufferedWriter;
17
import java.io.EOFException;
19
import java.io.FileInputStream;
20
import java.io.FileNotFoundException;
21
import java.io.FileOutputStream;
22
import java.io.FileWriter;
23
import java.io.IOException;
24
import java.io.ObjectInputStream;
25
import java.io.ObjectOutputStream;
26
import java.io.Writer;
27
import java.util.ArrayList;
28
import java.util.Collection;
29
import java.util.Enumeration;
30
import java.util.HashMap;
31
import java.util.HashSet;
32
import java.util.Hashtable;
33
import java.util.Iterator;
34
import java.util.List;
36
import java.util.Properties;
20
import org.aspectj.asm.internal.*;
39
import org.aspectj.asm.internal.AspectJElementHierarchy;
40
import org.aspectj.asm.internal.HandleProviderDelimiter;
41
import org.aspectj.asm.internal.JDTLikeHandleProvider;
42
import org.aspectj.asm.internal.RelationshipMap;
21
43
import org.aspectj.bridge.ISourceLocation;
44
import org.aspectj.util.IStructureModel;
24
* The Abstract Structure Model (ASM) represents the containment hierarchy and crossccutting
25
* structure map for AspectJ programs. It is used by IDE views such as the document outline,
26
* and by other tools such as ajdoc to show both AspectJ declarations and crosscutting links,
27
* such as which advice affects which join point shadows.
47
* The Abstract Structure Model (ASM) represents the containment hierarchy and crosscutting structure map for AspectJ programs. It
48
* is used by IDE views such as the document outline, and by other tools such as ajdoc to show both AspectJ declarations and
49
* crosscutting links, such as which advice affects which join point shadows.
29
51
* @author Mik Kersten
52
* @author Andy Clement
31
public class AsmManager {
34
* @deprecated use getDefault() method instead
36
private static AsmManager INSTANCE = new AsmManager();
39
private IElementHandleProvider handleProvider;
40
private List structureListeners = new ArrayList();
41
// private boolean shouldSaveModel = true;
44
public void setRelationshipMap(IRelationshipMap irm) { mapper = irm;}
45
public void setHierarchy(IHierarchy ih) { hierarchy=ih;}
47
// The model is 'manipulated' by the AjBuildManager.setupModel() code which trashes all the
48
// fields when setting up a new model for a batch build.
49
// Due to the requirements of incremental compilation we need to tie some of the info
50
// below to the AjState for a compilation and recover it if switching between projects.
51
protected IHierarchy hierarchy;
52
private IRelationshipMap mapper;
54
private static boolean creatingModel = false;
55
public static boolean dumpModelPostBuild = false; // Dumping the model is expensive
54
public class AsmManager implements IStructureModel {
57
public static boolean recordingLastActiveStructureModel = true;
58
public static AsmManager lastActiveStructureModel;
59
public static boolean forceSingletonBehaviour = false;
56
61
// SECRETAPI asc pull the secret options together into a system API you lazy fool
57
public static boolean attemptIncrementalModelRepairs = false;
59
// For offline debugging, you can now ask for the AsmManager to
60
// dump the model - see the method setReporting()
62
public static boolean attemptIncrementalModelRepairs = false;
63
// Dumping the model is expensive
64
public static boolean dumpModelPostBuild = false;
65
// For offline debugging, you can now ask for the AsmManager to
66
// dump the model - see the method setReporting()
61
67
private static boolean dumpModel = false;
62
68
private static boolean dumpRelationships = false;
63
69
private static boolean dumpDeltaProcessing = false;
64
70
private static IModelFilter modelFilter = null;
65
private static String dumpFilename = "";
71
private static String dumpFilename = "";
66
72
private static boolean reporting = false;
68
74
private static boolean completingTypeBindings = false;
71
// setReporting("c:/model.nfo",true,true,true,true);
74
protected AsmManager() {
75
handleProvider = new JDTLikeHandleProvider();
79
public void createNewASM() {
80
hierarchy = new AspectJElementHierarchy();
81
mapper = new RelationshipMap(hierarchy);
76
private final List structureListeners = new ArrayList();
78
// The model is 'manipulated' by the AjBuildManager.setupModel() code which
80
// fields when setting up a new model for a batch build.
81
// Due to the requirements of incremental compilation we need to tie some of
83
// below to the AjState for a compilation and recover it if switching
85
protected IHierarchy hierarchy;
88
* Map from String > String - it maps absolute paths for inpath dirs/jars to workspace relative paths suitable for handle
91
protected Map inpathMap;
92
private IRelationshipMap mapper;
93
private IElementHandleProvider handleProvider;
95
private final CanonicalFilePathMap canonicalFilePathMap = new CanonicalFilePathMap();
96
// Record the Set<File> for which the model has been modified during the
97
// last incremental build
98
private final Set lastBuildChanges = new HashSet();
100
// Record the Set<File> of aspects that wove the files listed in lastBuildChanges
101
final Set aspectsWeavingInLastBuild = new HashSet();
104
// setReporting("c:/model.nfo",true,true,true,true);
107
private AsmManager() {
110
public static AsmManager createNewStructureModel(Map inpathMap) {
111
if (forceSingletonBehaviour && lastActiveStructureModel != null) {
112
return lastActiveStructureModel;
114
AsmManager asm = new AsmManager();
115
asm.inpathMap = inpathMap;
116
asm.hierarchy = new AspectJElementHierarchy(asm);
117
asm.mapper = new RelationshipMap(asm.hierarchy);
118
asm.handleProvider = new JDTLikeHandleProvider(asm);
82
119
// call initialize on the handleProvider when we create a new ASM
83
120
// to give handleProviders the chance to reset any state
84
handleProvider.initialize();
87
public IHierarchy getHierarchy() {
91
public static AsmManager getDefault() {
121
asm.handleProvider.initialize();
122
asm.resetDeltaProcessing();
123
setLastActiveStructureModel(asm);
127
public IHierarchy getHierarchy() {
95
131
public IRelationshipMap getRelationshipMap() {
99
135
public void fireModelUpdated() {
101
137
if (dumpModelPostBuild && hierarchy.getConfigFile() != null) {
102
138
writeStructureModel(hierarchy.getConfigFile());
107
* Constructs map each time it's called.
109
public HashMap getInlineAnnotations(
111
boolean showSubMember,
112
boolean showMemberAndType) {
114
if (!hierarchy.isValid()) return null;
116
HashMap annotations = new HashMap();
117
IProgramElement node = hierarchy.findElementForSourceFile(sourceFile);
118
if (node == IHierarchy.NO_STRUCTURE) {
121
IProgramElement fileNode = (IProgramElement)node;
122
ArrayList peNodes = new ArrayList();
123
getAllStructureChildren(fileNode, peNodes, showSubMember, showMemberAndType);
124
for (Iterator it = peNodes.iterator(); it.hasNext(); ) {
125
IProgramElement peNode = (IProgramElement)it.next();
126
List entries = new ArrayList();
128
ISourceLocation sourceLoc = peNode.getSourceLocation();
129
if (null != sourceLoc) {
130
Integer hash = new Integer(sourceLoc.getLine());
131
List existingEntry = (List)annotations.get(hash);
132
if (existingEntry != null) {
133
entries.addAll(existingEntry);
135
annotations.put(hash, entries);
142
private void getAllStructureChildren(IProgramElement node, List result, boolean showSubMember, boolean showMemberAndType) {
143
List children = node.getChildren();
144
if (node.getChildren() == null) return;
145
for (Iterator it = children.iterator(); it.hasNext(); ) {
146
IProgramElement next = (IProgramElement)it.next();
147
List rels = AsmManager.getDefault().getRelationshipMap().get(next);
149
&& ((next.getKind() == IProgramElement.Kind.CODE && showSubMember)
150
|| (next.getKind() != IProgramElement.Kind.CODE && showMemberAndType))
152
&& rels.size() > 0) {
155
getAllStructureChildren((IProgramElement)next, result, showSubMember, showMemberAndType);
159
public void addListener(IHierarchyListener listener) {
160
structureListeners.add(listener);
163
public void removeStructureListener(IHierarchyListener listener) {
164
structureListeners.remove(listener);
143
* Constructs map each time it's called.
145
public HashMap getInlineAnnotations(String sourceFile, boolean showSubMember, boolean showMemberAndType) {
147
if (!hierarchy.isValid())
150
HashMap annotations = new HashMap();
151
IProgramElement node = hierarchy.findElementForSourceFile(sourceFile);
152
if (node == IHierarchy.NO_STRUCTURE) {
155
IProgramElement fileNode = node;
156
ArrayList peNodes = new ArrayList();
157
getAllStructureChildren(fileNode, peNodes, showSubMember, showMemberAndType);
158
for (Iterator it = peNodes.iterator(); it.hasNext();) {
159
IProgramElement peNode = (IProgramElement) it.next();
160
List entries = new ArrayList();
162
ISourceLocation sourceLoc = peNode.getSourceLocation();
163
if (null != sourceLoc) {
164
Integer hash = new Integer(sourceLoc.getLine());
165
List existingEntry = (List) annotations.get(hash);
166
if (existingEntry != null) {
167
entries.addAll(existingEntry);
169
annotations.put(hash, entries);
176
private void getAllStructureChildren(IProgramElement node, List result, boolean showSubMember, boolean showMemberAndType) {
177
List children = node.getChildren();
178
if (node.getChildren() == null)
180
for (Iterator it = children.iterator(); it.hasNext();) {
181
IProgramElement next = (IProgramElement) it.next();
182
List rels = mapper.get(next);
184
&& ((next.getKind() == IProgramElement.Kind.CODE && showSubMember) || (next.getKind() != IProgramElement.Kind.CODE && showMemberAndType))
185
&& rels != null && rels.size() > 0) {
188
getAllStructureChildren(next, result, showSubMember, showMemberAndType);
192
public void addListener(IHierarchyListener listener) {
193
structureListeners.add(listener);
196
public void removeStructureListener(IHierarchyListener listener) {
197
structureListeners.remove(listener);
167
200
// this shouldn't be needed - but none of the people that add listeners
168
201
// in the test suite ever remove them. AMC added this to be called in
169
// setup() so that the test cases would cease leaking listeners and go
202
// setup() so that the test cases would cease leaking listeners and go
170
203
// back to executing at a reasonable speed.
171
204
public void removeAllListeners() {
172
205
structureListeners.clear();
175
private void notifyListeners() {
176
for (Iterator it = structureListeners.iterator(); it.hasNext(); ) {
177
((IHierarchyListener)it.next()).elementsUpdated(hierarchy);
181
public IElementHandleProvider getHandleProvider() {
182
return handleProvider;
185
public void setHandleProvider(IElementHandleProvider handleProvider) {
186
this.handleProvider = handleProvider;
208
private void notifyListeners() {
209
for (Iterator it = structureListeners.iterator(); it.hasNext();) {
210
((IHierarchyListener) it.next()).elementsUpdated(hierarchy);
214
public IElementHandleProvider getHandleProvider() {
215
return handleProvider;
218
public void setHandleProvider(IElementHandleProvider handleProvider) {
219
this.handleProvider = handleProvider;
222
public void writeStructureModel(String configFilePath) {
224
String filePath = genExternFilePath(configFilePath);
225
FileOutputStream fos = new FileOutputStream(filePath);
226
ObjectOutputStream s = new ObjectOutputStream(fos);
227
s.writeObject(hierarchy); // Store the program element tree
228
s.writeObject(mapper); // Store the relationships
233
} catch (IOException e) {
234
// System.err.println("AsmManager: Unable to write structure model: "
235
// +configFilePath+" because of:");
236
// e.printStackTrace();
241
* @param configFilePath path to an ".lst" file
192
public void writeStructureModel(String configFilePath) {
194
String filePath = genExternFilePath(configFilePath);
195
FileOutputStream fos = new FileOutputStream(filePath);
196
ObjectOutputStream s = new ObjectOutputStream(fos);
197
s.writeObject(hierarchy); // Store the program element tree
198
s.writeObject(mapper); // Store the relationships
203
} catch (Exception e) {
204
// System.err.println("AsmManager: Unable to write structure model: "+configFilePath+" because of:");
205
// e.printStackTrace();
210
* @todo add proper handling of bad paths/suffixes/etc
211
* @param configFilePath path to an ".lst" file
213
public void readStructureModel(String configFilePath) {
214
boolean hierarchyReadOK = false;
216
if (configFilePath == null) {
217
hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
219
String filePath = genExternFilePath(configFilePath);
220
FileInputStream in = new FileInputStream(filePath);
221
ObjectInputStream s = new ObjectInputStream(in);
222
hierarchy = (AspectJElementHierarchy)s.readObject();
223
hierarchyReadOK = true;
224
mapper = (RelationshipMap)s.readObject();
225
((RelationshipMap)mapper).setHierarchy(hierarchy);
227
} catch (FileNotFoundException fnfe) {
243
public void readStructureModel(String configFilePath) {
244
boolean hierarchyReadOK = false;
246
if (configFilePath == null) {
247
hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
249
String filePath = genExternFilePath(configFilePath);
250
FileInputStream in = new FileInputStream(filePath);
251
ObjectInputStream s = new ObjectInputStream(in);
252
hierarchy = (AspectJElementHierarchy) s.readObject();
253
((AspectJElementHierarchy) hierarchy).setAsmManager(this);
254
hierarchyReadOK = true;
255
mapper = (RelationshipMap) s.readObject();
256
((RelationshipMap) mapper).setHierarchy(hierarchy);
258
} catch (FileNotFoundException fnfe) {
229
260
hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
230
261
} catch (EOFException eofe) {
231
262
// Might be an old format sym file that is missing its relationships
232
263
if (!hierarchyReadOK) {
233
System.err.println("AsmManager: Unable to read structure model: "+configFilePath+" because of:");
264
System.err.println("AsmManager: Unable to read structure model: " + configFilePath + " because of:");
234
265
eofe.printStackTrace();
235
266
hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
237
} catch (Exception e) {
238
// System.err.println("AsmManager: Unable to read structure model: "+configFilePath+" because of:");
239
// e.printStackTrace();
240
hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
246
private String genExternFilePath(String configFilePath) {
247
// sometimes don't have ".lst"
248
if (configFilePath.lastIndexOf(".lst") != -1) {
249
configFilePath = configFilePath.substring(0,configFilePath.lastIndexOf(".lst"));
251
return configFilePath + ".ajsym";
254
// public void setShouldSaveModel(boolean shouldSaveModel) {
255
// this.shouldSaveModel = shouldSaveModel;
258
// ==== implementation of canonical file path map and accessors ==============
260
// a more sophisticated optimisation is left here commented out as the
261
// performance gains don't justify the disturbance this close to a release...
262
// can't call prepareForWeave until preparedForCompilation has completed...
263
// public synchronized void prepareForCompilation(List files) {
264
// canonicalFilePathMap.prepopulate(files);
267
// public synchronized void prepareForWeave() {
268
// canonicalFilePathMap.handover();
268
} catch (Exception e) {
269
// System.err.println("AsmManager: Unable to read structure model: "+
270
// configFilePath+" because of:");
271
// e.printStackTrace();
272
hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
278
private String genExternFilePath(String configFilePath) {
279
// sometimes don't have ".lst"
280
if (configFilePath.lastIndexOf(".lst") != -1) {
281
configFilePath = configFilePath.substring(0, configFilePath.lastIndexOf(".lst"));
283
return configFilePath + ".ajsym";
271
286
public String getCanonicalFilePath(File f) {
272
287
return canonicalFilePathMap.get(f);
275
private CanonicalFilePathMap canonicalFilePathMap = new CanonicalFilePathMap();
277
290
private static class CanonicalFilePathMap {
278
291
private static final int MAX_SIZE = 4000;
280
private Map pathMap = new HashMap(20);
282
// // guards to ensure correctness and liveness
283
// private boolean cacheInUse = false;
284
// private boolean stopRequested = false;
286
// private synchronized boolean isCacheInUse() {
287
// return cacheInUse;
290
// private synchronized void setCacheInUse(boolean val) {
297
// private synchronized boolean isStopRequested() {
298
// return stopRequested;
301
// private synchronized void requestStop() {
302
// stopRequested = true;
306
// * Begin prepopulating the map by adding an entry from
307
// * file.getPath -> file.getCanonicalPath for each file in
308
// * the list. Do this on a background thread.
311
// public void prepopulate(final List files) {
312
// stopRequested = false;
313
// setCacheInUse(false);
314
// if (pathMap.size() > MAX_SIZE) {
318
// public void run() {
319
// System.out.println("Starting cache population: " + System.currentTimeMillis());
320
// Iterator it = files.iterator();
321
// while (!isStopRequested() && it.hasNext()) {
322
// File f = (File)it.next();
323
// if (pathMap.get(f.getPath()) == null) {
324
// // may reuse cache across compiles from ides...
326
// pathMap.put(f.getPath(),f.getCanonicalPath());
327
// } catch (IOException ex) {
328
// pathMap.put(f.getPath(),f.getPath());
332
// System.out.println("Cached " + files.size());
333
// setCacheInUse(true);
334
// System.out.println("Cache populated: " + System.currentTimeMillis());
340
// * Stop pre-populating the cache - our customers are ready to use it.
341
// * If there are any cache misses from this point on, we'll populate the
343
// * The handover is done this way to ensure that only one thread is ever
344
// * accessing the cache, and that we minimize synchronization.
346
// public synchronized void handover() {
347
// if (!isCacheInUse()) {
350
// while (!isCacheInUse()) wait();
351
// } catch (InterruptedException intEx) { } // just continue
293
private final Map pathMap = new HashMap(20);
295
// // guards to ensure correctness and liveness
296
// private boolean cacheInUse = false;
297
// private boolean stopRequested = false;
299
// private synchronized boolean isCacheInUse() {
300
// return cacheInUse;
303
// private synchronized void setCacheInUse(boolean val) {
310
// private synchronized boolean isStopRequested() {
311
// return stopRequested;
314
// private synchronized void requestStop() {
315
// stopRequested = true;
319
// * Begin prepopulating the map by adding an entry from
320
// * file.getPath -> file.getCanonicalPath for each file in
321
// * the list. Do this on a background thread.
324
// public void prepopulate(final List files) {
325
// stopRequested = false;
326
// setCacheInUse(false);
327
// if (pathMap.size() > MAX_SIZE) {
331
// public void run() {
332
// System.out.println("Starting cache population: " +
333
// System.currentTimeMillis());
334
// Iterator it = files.iterator();
335
// while (!isStopRequested() && it.hasNext()) {
336
// File f = (File)it.next();
337
// if (pathMap.get(f.getPath()) == null) {
338
// // may reuse cache across compiles from ides...
340
// pathMap.put(f.getPath(),f.getCanonicalPath());
341
// } catch (IOException ex) {
342
// pathMap.put(f.getPath(),f.getPath());
346
// System.out.println("Cached " + files.size());
347
// setCacheInUse(true);
348
// System.out.println("Cache populated: " + System.currentTimeMillis());
354
// * Stop pre-populating the cache - our customers are ready to use it.
355
// * If there are any cache misses from this point on, we'll populate
358
// * The handover is done this way to ensure that only one thread is
360
// * accessing the cache, and that we minimize synchronization.
362
// public synchronized void handover() {
363
// if (!isCacheInUse()) {
366
// while (!isCacheInUse()) wait();
367
// } catch (InterruptedException intEx) { } // just continue
355
371
public String get(File f) {
356
// if (!cacheInUse) { // unsynchronized test - should never be parallel
357
// // threads at this point
358
// throw new IllegalStateException(
359
// "Must take ownership of cache before using by calling " +
372
// if (!cacheInUse) { // unsynchronized test - should never be
374
// // threads at this point
375
// throw new IllegalStateException(
376
// "Must take ownership of cache before using by calling " +
362
379
String ret = (String) pathMap.get(f.getPath());
363
380
if (ret == null) {
437
456
e.printStackTrace();
442
public static void dumptree(Writer w,IProgramElement node,int indent) throws IOException {
443
for (int i =0 ;i<indent;i++) w.write(" ");
446
if (node.getSourceLocation()!=null) {
447
loc = node.getSourceLocation().toString();
448
if (modelFilter!=null) loc = modelFilter.processFilelocation(loc);
451
w.write(node+" ["+(node==null?"null":node.getKind().toString())+"] "+loc+"\n");
453
for (Iterator i = node.getChildren().iterator();i.hasNext();) {
454
dumptree(w,(IProgramElement)i.next(),indent+2);
458
public static void dumptree(IProgramElement node,int indent) throws IOException {
459
for (int i =0 ;i<indent;i++) System.out.print(" ");
462
if (node.getSourceLocation()!=null)
463
loc = node.getSourceLocation().toString();
465
System.out.println(node+" ["+(node==null?"null":node.getKind().toString())+"] "+loc);
467
for (Iterator i = node.getChildren().iterator();i.hasNext();) {
468
dumptree((IProgramElement)i.next(),indent+2);
472
private void dumprels(Writer w) throws IOException {
473
IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
460
public static void dumptree(Writer w, IProgramElement node, int indent) throws IOException {
461
for (int i = 0; i < indent; i++)
465
if (node.getSourceLocation() != null) {
466
loc = node.getSourceLocation().toString();
467
if (modelFilter != null)
468
loc = modelFilter.processFilelocation(loc);
471
w.write(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc + "\n");
473
for (Iterator i = node.getChildren().iterator(); i.hasNext();) {
474
dumptree(w, (IProgramElement) i.next(), indent + 2);
478
public static void dumptree(IProgramElement node, int indent) throws IOException {
479
for (int i = 0; i < indent; i++)
480
System.out.print(" ");
483
if (node.getSourceLocation() != null)
484
loc = node.getSourceLocation().toString();
486
System.out.println(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc);
488
for (Iterator i = node.getChildren().iterator(); i.hasNext();) {
489
dumptree((IProgramElement) i.next(), indent + 2);
493
public void dumprels(Writer w) throws IOException {
475
Set entries = irm.getEntries();
495
Set entries = mapper.getEntries();
476
496
for (Iterator iter = entries.iterator(); iter.hasNext();) {
477
497
String hid = (String) iter.next();
478
List rels = irm.get(hid);
498
List rels = mapper.get(hid);
479
499
for (Iterator iterator = rels.iterator(); iterator.hasNext();) {
480
500
IRelationship ir = (IRelationship) iterator.next();
481
501
List targets = ir.getTargets();
482
for (Iterator iterator2 = targets.iterator();
502
for (Iterator iterator2 = targets.iterator(); iterator2.hasNext();) {
485
503
String thid = (String) iterator2.next();
486
504
StringBuffer sb = new StringBuffer();
487
if (modelFilter==null || modelFilter.wantsHandleIds()) sb.append("Hid:"+(ctr++)+":");
488
sb.append("(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid+"\n");
505
if (modelFilter == null || modelFilter.wantsHandleIds())
506
sb.append("Hid:" + (ctr++) + ":");
507
sb.append("(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") " + thid + "\n");
489
508
w.write(sb.toString());
495
514
private void dumprelsStderr(String key) {
496
System.err.println("Relationships dump follows: "+key);
497
IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
515
System.err.println("Relationships dump follows: " + key);
499
Set entries = irm.getEntries();
517
Set entries = mapper.getEntries();
500
518
for (Iterator iter = entries.iterator(); iter.hasNext();) {
501
519
String hid = (String) iter.next();
502
List rels = irm.get(hid);
520
List rels = mapper.get(hid);
503
521
for (Iterator iterator = rels.iterator(); iterator.hasNext();) {
504
522
IRelationship ir = (IRelationship) iterator.next();
505
523
List targets = ir.getTargets();
506
for (Iterator iterator2 = targets.iterator();
524
for (Iterator iterator2 = targets.iterator(); iterator2.hasNext();) {
509
525
String thid = (String) iterator2.next();
510
System.err.println("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid);
526
System.err.println("Hid:" + (ctr++) + ":(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") "
514
System.err.println("End of relationships dump for: "+key);
531
System.err.println("End of relationships dump for: " + key);
517
//===================== DELTA PROCESSING CODE ============== start ==========//
534
// ===================== DELTA PROCESSING CODE ============== start
520
* Removes the hierarchy structure for the specified files from the structure model.
521
* Returns true if it deleted anything
538
* Removes the hierarchy structure for the specified files from the structure model. Returns true if it deleted anything
523
public boolean removeStructureModelForFiles(Writer fw,Collection files) throws IOException {
540
public boolean removeStructureModelForFiles(Writer fw, Collection files) throws IOException {
525
IHierarchy model = AsmManager.getDefault().getHierarchy();
527
542
boolean modelModified = false;
529
544
Set deletedNodes = new HashSet();
530
545
for (Iterator iter = files.iterator(); iter.hasNext();) {
531
546
File fileForCompilation = (File) iter.next();
532
String correctedPath = AsmManager.getDefault().getCanonicalFilePath(fileForCompilation);
533
IProgramElement progElem = (IProgramElement)model.findInFileMap(correctedPath);
534
if (progElem!=null) {
547
String correctedPath = getCanonicalFilePath(fileForCompilation);
548
IProgramElement progElem = (IProgramElement) hierarchy.findInFileMap(correctedPath);
549
if (progElem != null) {
535
550
// Found it, let's remove it
536
551
if (dumpDeltaProcessing) {
537
fw.write("Deleting "+progElem+" node for file "+fileForCompilation+"\n");
552
fw.write("Deleting " + progElem + " node for file " + fileForCompilation + "\n");
539
554
removeNode(progElem);
555
lastBuildChanges.add(fileForCompilation);
540
556
deletedNodes.add(getCanonicalFilePath(progElem.getSourceLocation().getSourceFile()));
541
if (!model.removeFromFileMap(correctedPath.toString()))
542
throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: "+correctedPath.toString()+" from the filemap");
557
if (!hierarchy.removeFromFileMap(correctedPath))
558
throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: " + correctedPath
559
+ " from the filemap");
543
560
modelModified = true;
546
if (modelModified) model.updateHandleMap(deletedNodes);
564
hierarchy.updateHandleMap(deletedNodes);
547
566
return modelModified;
550
private void flushModelCache() {
551
IHierarchy model = AsmManager.getDefault().getHierarchy();
552
model.flushTypeMap();
555
569
// This code is *SLOW* but it isnt worth fixing until we address the
556
570
// bugs in binary weaving.
557
public void fixupStructureModel(Writer fw,List filesToBeCompiled,Set files_added,Set files_deleted) throws IOException {
571
public void fixupStructureModel(Writer fw, List filesToBeCompiled, Set files_added, Set files_deleted) throws IOException {
558
572
// Three kinds of things to worry about:
559
573
// 1. New files have been added since the last compile
560
574
// 2. Files have been deleted since the last compile
561
// 3. Files have 'changed' since the last compile (really just those in config.getFiles())
563
// List files = config.getFiles();
564
IHierarchy model = AsmManager.getDefault().getHierarchy();
575
// 3. Files have 'changed' since the last compile (really just those in
576
// config.getFiles())
578
// List files = config.getFiles();
566
580
boolean modelModified = false;
567
// Files to delete are: those to be compiled + those that have been deleted
581
// Files to delete are: those to be compiled + those that have been
569
584
Set filesToRemoveFromStructureModel = new HashSet(filesToBeCompiled);
570
585
filesToRemoveFromStructureModel.addAll(files_deleted);
571
586
Set deletedNodes = new HashSet();
572
587
for (Iterator iter = filesToRemoveFromStructureModel.iterator(); iter.hasNext();) {
573
588
File fileForCompilation = (File) iter.next();
574
String correctedPath = AsmManager.getDefault().getCanonicalFilePath(fileForCompilation);
575
IProgramElement progElem = (IProgramElement)model.findInFileMap(correctedPath);
576
if (progElem!=null) {
589
String correctedPath = getCanonicalFilePath(fileForCompilation);
590
IProgramElement progElem = (IProgramElement) hierarchy.findInFileMap(correctedPath);
591
if (progElem != null) {
577
592
// Found it, let's remove it
578
593
if (dumpDeltaProcessing) {
579
fw.write("Deleting "+progElem+" node for file "+fileForCompilation+"\n");
594
fw.write("Deleting " + progElem + " node for file " + fileForCompilation + "\n");
581
596
removeNode(progElem);
582
597
deletedNodes.add(getCanonicalFilePath(progElem.getSourceLocation().getSourceFile()));
583
if (!model.removeFromFileMap(correctedPath.toString()))
584
throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: "+correctedPath.toString()+" from the filemap");
598
if (!hierarchy.removeFromFileMap(correctedPath))
599
throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: " + correctedPath
600
+ " from the filemap");
585
601
modelModified = true;
588
604
if (modelModified) {
589
model.flushTypeMap();
590
model.updateHandleMap(deletedNodes);
605
hierarchy.flushTypeMap();
606
hierarchy.updateHandleMap(deletedNodes);
595
public void processDelta(List files_tobecompiled,Set files_added,Set files_deleted) {
610
public void processDelta(Collection files_tobecompiled, Set files_added, Set files_deleted) {
598
613
Writer fw = null;
600
615
// Are we recording this ?
601
616
if (dumpDeltaProcessing) {
602
FileWriter filew = new FileWriter(dumpFilename,true);
617
FileWriter filew = new FileWriter(dumpFilename, true);
603
618
fw = new BufferedWriter(filew);
604
619
fw.write("=== Processing delta changes for the model ===\n");
605
fw.write("Files for compilation:#"+files_tobecompiled.size()+":"+files_tobecompiled+"\n");
606
fw.write("Files added :#"+files_added.size()+":"+files_added+"\n");
607
fw.write("Files deleted :#"+files_deleted.size()+":"+files_deleted+"\n");
620
fw.write("Files for compilation:#" + files_tobecompiled.size() + ":" + files_tobecompiled + "\n");
621
fw.write("Files added :#" + files_added.size() + ":" + files_added + "\n");
622
fw.write("Files deleted :#" + files_deleted.size() + ":" + files_deleted + "\n");
610
625
long stime = System.currentTimeMillis();
612
boolean modificationOccurred = false;
614
//fixupStructureModel(fw,filesToBeCompiled,files_added,files_deleted);
627
// fixupStructureModel(fw,filesToBeCompiled,files_added,files_deleted
615
629
// Let's remove all the files that are deleted on this compile
616
modificationOccurred =
617
removeStructureModelForFiles(fw,files_deleted) |
618
modificationOccurred;
619
long etime1 = System.currentTimeMillis(); // etime1-stime = time to fix up the model
621
repairRelationships(fw);
622
long etime2 = System.currentTimeMillis(); // etime2-stime = time to repair the relationship map
624
modificationOccurred =
625
removeStructureModelForFiles(fw,files_tobecompiled) |
626
modificationOccurred;
630
removeStructureModelForFiles(fw, files_deleted);
631
long etime1 = System.currentTimeMillis(); // etime1-stime = time to
634
repairRelationships(fw);
635
long etime2 = System.currentTimeMillis(); // etime2-stime = time to
639
removeStructureModelForFiles(fw, files_tobecompiled);
628
641
if (dumpDeltaProcessing) {
629
642
fw.write("===== Delta Processing timing ==========\n");
630
fw.write("Hierarchy="+(etime1-stime)+"ms Relationshipmap="+(etime2-etime1)+"ms\n");
643
fw.write("Hierarchy=" + (etime1 - stime) + "ms Relationshipmap=" + (etime2 - etime1) + "ms\n");
631
644
fw.write("===== Traversal ========================\n");
632
// fw.write("Source handles processed="+srchandlecounter+"\n");
633
// fw.write("Target handles processed="+tgthandlecounter+"\n");
645
// fw.write("Source handles processed="+srchandlecounter+"\n");
646
// fw.write("Target handles processed="+tgthandlecounter+"\n");
634
647
fw.write("========================================\n");
635
fw.flush();fw.close();
638
652
reportModelInfo("After delta processing");
639
653
} catch (IOException e) {
640
654
e.printStackTrace();
659
private String getTypeNameFromHandle(String handle, Map cache) {
660
String typename = (String) cache.get(handle);
661
if (typename != null) {
664
// inpath handle - but for which type?
665
// let's do it the slow way, we can optimize this with a cache perhaps
666
int hasPackage = handle.indexOf('<');
667
int typeLocation = handle.indexOf('[');
668
if (typeLocation == -1) {
669
typeLocation = handle.indexOf('}');
671
if (typeLocation == -1) {
672
// unexpected - time to give up
675
StringBuffer qualifiedTypeNameFromHandle = new StringBuffer();
676
if (hasPackage != -1) {
677
qualifiedTypeNameFromHandle.append(handle.substring(hasPackage + 1, handle.indexOf('(', hasPackage)));
678
qualifiedTypeNameFromHandle.append('.');
680
qualifiedTypeNameFromHandle.append(handle.substring(typeLocation + 1));
681
typename = qualifiedTypeNameFromHandle.toString();
682
cache.put(handle, typename);
646
687
* two kinds of relationships
651
* Both of these relationships are added when 'B' is modified. Concrete examples are
652
* 'advises/advisedby' or 'annotates/annotatedby'.
654
* What we need to do is when 'B' is going to be woven, remove all relationships that may
655
* reoccur when it is woven.
656
* So - remove 'affects' relationships where the target is 'B', remove all 'affectedBy'
657
* relationships where the source is 'B'.
689
* A affects B B affectedBy A
691
* Both of these relationships are added when 'B' is modified. Concrete examples are 'advises/advisedby' or
692
* 'annotates/annotatedby'.
694
* 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
695
* 'affects' relationships where the target is 'B', remove all 'affectedBy' relationships where the source is 'B'.
660
698
public void removeRelationshipsTargettingThisType(String typename) {
662
if (debug) System.err.println(">>removeRelationshipsTargettingThisType "+typename);
699
boolean debug = false;
701
System.err.println(">>removeRelationshipsTargettingThisType " + typename);
663
702
String pkg = null;
664
String type= typename;
703
String type = typename;
665
704
int lastSep = typename.lastIndexOf('.');
666
705
if (lastSep != -1) {
667
pkg = typename.substring(0,lastSep);
668
type= typename.substring(lastSep+1);
706
pkg = typename.substring(0, lastSep);
707
type = typename.substring(lastSep + 1);
670
boolean didsomething=false;
671
IProgramElement typeNode = hierarchy.findElementForType(pkg,type);
709
boolean didsomething = false;
710
IProgramElement typeNode = hierarchy.findElementForType(pkg, type);
673
712
// Reasons for that being null:
674
// 1. the file has fundamental errors and so doesn't exist in the model (-proceedOnError probably forced us to weave)
675
if (typeNode == null) return;
677
Set sourcesToRemove = new HashSet();
679
// Iterate over the source handles in the relationships map, the aim here is to remove any 'affected by'
680
// relationships where the source of the relationship is the specified type (since it will be readded
713
// 1. the file has fundamental errors and so doesn't exist in the model
714
// (-proceedOnError probably forced us to weave)
715
if (typeNode == null)
718
Set sourcesToRemove = new HashSet();
719
Map handleToTypenameCache = new HashMap();
720
// Iterate over the source handles in the relationships map, the aim
721
// here is to remove any 'affected by'
722
// relationships where the source of the relationship is the specified
723
// type (since it will be readded
681
724
// when the type is woven)
682
725
Set sourcehandlesSet = mapper.getEntries();
683
726
List relationshipsToRemove = new ArrayList();
684
727
for (Iterator keyiter = sourcehandlesSet.iterator(); keyiter.hasNext();) {
685
String hid = (String) keyiter.next();
686
IProgramElement sourceElement = hierarchy.getElement(hid);
687
if (sourceElement == null || sameType(hid,sourceElement,typeNode)) {
688
// worth continuing as there may be a relationship to remove
689
relationshipsToRemove.clear();
690
List relationships = mapper.get(hid);
691
for (Iterator reliter = relationships.iterator();reliter.hasNext();) {
728
String hid = (String) keyiter.next();
729
if (isPhantomHandle(hid)) {
730
// inpath handle - but for which type?
731
// TODO promote cache for reuse during one whole model update
732
if (!getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
736
IProgramElement sourceElement = hierarchy.getElement(hid);
737
if (sourceElement == null || sameType(hid, sourceElement, typeNode)) {
738
// worth continuing as there may be a relationship to remove
739
relationshipsToRemove.clear();
740
List relationships = mapper.get(hid);
741
for (Iterator reliter = relationships.iterator(); reliter.hasNext();) {
692
742
IRelationship rel = (IRelationship) reliter.next();
693
if (rel.getKind()==IRelationship.Kind.USES_POINTCUT) continue; // these relationships are added at compile time, argh
694
if (rel.isAffects()) continue; // we want 'affected by' relationships - (e.g. advised by)
695
relationshipsToRemove.add(rel); // all the relationships can be removed, regardless of the target(s)
743
if (rel.getKind() == IRelationship.Kind.USES_POINTCUT)
744
continue; // these relationships are added at compile
747
continue; // we want 'affected by' relationships - (e.g.
749
relationshipsToRemove.add(rel); // all the relationships can
750
// be removed, regardless of
697
// Now, were any relationships emptied during that processing and so need removing for this source handle
698
if (relationshipsToRemove.size()>0) {
700
if (relationshipsToRemove.size() == relationships.size()) sourcesToRemove.add(hid);
753
// Now, were any relationships emptied during that processing
754
// and so need removing for this source handle
755
if (relationshipsToRemove.size() > 0) {
757
if (relationshipsToRemove.size() == relationships.size())
758
sourcesToRemove.add(hid);
702
for (int i = 0 ;i<relationshipsToRemove.size();i++)
760
for (int i = 0; i < relationshipsToRemove.size(); i++)
703
761
relationships.remove(relationshipsToRemove.get(i));
708
// Remove sources that have no valid relationships any more
766
// Remove sources that have no valid relationships any more
709
767
for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
710
768
String hid = (String) srciter.next();
711
// System.err.println(" source handle: all relationships have gone for "+hid);
769
// System.err.println(
770
// " source handle: all relationships have gone for "+hid);
712
771
mapper.removeAll(hid);
713
772
IProgramElement ipe = hierarchy.getElement(hid);
715
774
// If the relationship was hanging off a 'code' node, delete it.
716
775
if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
717
if (debug) System.err.println(" source handle: it was code node, removing that as well... code="+ipe+" parent="+ipe.getParent());
777
System.err.println(" source handle: it was code node, removing that as well... code=" + ipe + " parent="
718
779
removeSingleNode(ipe);
723
if (debug) dumprelsStderr("after processing 'affectedby'");
724
if (didsomething) { // did we do anything?
725
sourcesToRemove.clear();
785
dumprelsStderr("after processing 'affectedby'");
786
if (didsomething) { // did we do anything?
787
sourcesToRemove.clear();
726
788
// removing 'affects' relationships
727
if (debug) dumprelsStderr("before processing 'affects'");
790
dumprelsStderr("before processing 'affects'");
728
791
// Iterate over the source handles in the relationships map
729
792
sourcehandlesSet = mapper.getEntries();
730
793
for (Iterator keyiter = sourcehandlesSet.iterator(); keyiter.hasNext();) {
731
String hid = (String) keyiter.next();
732
IProgramElement sourceElement = hierarchy.getElement(hid);
734
relationshipsToRemove.clear();
735
List relationships = mapper.get(hid);
736
for (Iterator reliter = relationships.iterator();reliter.hasNext();) {
794
String hid = (String) keyiter.next();
795
relationshipsToRemove.clear();
796
List relationships = mapper.get(hid);
797
for (Iterator reliter = relationships.iterator(); reliter.hasNext();) {
737
798
IRelationship rel = (IRelationship) reliter.next();
738
if (rel.getKind()==IRelationship.Kind.USES_POINTCUT) continue; // these relationships are added at compile time, argh
739
if (!rel.isAffects()) continue;
799
if (rel.getKind() == IRelationship.Kind.USES_POINTCUT)
800
continue; // these relationships are added at compile
802
if (!rel.isAffects())
740
804
List targets = rel.getTargets();
741
805
List targetsToRemove = new ArrayList();
743
// find targets that target the type we are interested in, they need removing
807
// find targets that target the type we are interested in,
808
// they need removing
744
809
for (Iterator targetsIter = targets.iterator(); targetsIter.hasNext();) {
745
String targethid = (String) targetsIter.next();
810
String targethid = (String) targetsIter.next();
811
if (isPhantomHandle(hid) && !getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
746
814
// Does this point to the same type?
747
815
IProgramElement existingTarget = hierarchy.getElement(targethid);
748
if (existingTarget == null || sameType(targethid,existingTarget,typeNode)) targetsToRemove.add(targethid);
816
if (existingTarget == null || sameType(targethid, existingTarget, typeNode))
817
targetsToRemove.add(targethid);
751
if (targetsToRemove.size()!=0) {
752
if (targetsToRemove.size()==targets.size()) relationshipsToRemove.add(rel);
820
if (targetsToRemove.size() != 0) {
821
if (targetsToRemove.size() == targets.size())
822
relationshipsToRemove.add(rel);
754
824
// Remove all the targets that are no longer valid
755
for (Iterator targsIter = targetsToRemove.iterator();targsIter.hasNext();) {
756
String togo = (String) targsIter.next();
757
targets.remove(togo);
825
for (Iterator targsIter = targetsToRemove.iterator(); targsIter.hasNext();) {
826
String togo = (String) targsIter.next();
827
targets.remove(togo);
762
// Now, were any relationships emptied during that processing and so need removing for this source handle
763
if (relationshipsToRemove.size()>0) {
764
// Are we removing *all* of the relationships for this source handle?
765
if (relationshipsToRemove.size() == relationships.size()) sourcesToRemove.add(hid);
832
// Now, were any relationships emptied during that processing
833
// and so need removing for this source handle
834
if (relationshipsToRemove.size() > 0) {
835
// Are we removing *all* of the relationships for this
837
if (relationshipsToRemove.size() == relationships.size())
838
sourcesToRemove.add(hid);
767
for (int i = 0 ;i<relationshipsToRemove.size();i++)
840
for (int i = 0; i < relationshipsToRemove.size(); i++)
768
841
relationships.remove(relationshipsToRemove.get(i));
772
845
// Remove sources that have no valid relationships any more
773
846
for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
774
847
String hid = (String) srciter.next();
775
// System.err.println(" source handle: all relationships have gone for "+hid);
848
// System.err.println(
849
// " source handle: all relationships have gone for "+hid);
776
850
mapper.removeAll(hid);
777
851
IProgramElement ipe = hierarchy.getElement(hid);
779
// If the relationship was hanging off a 'code' node, delete it.
853
// If the relationship was hanging off a 'code' node, delete
780
855
if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
781
if (debug) System.err.println(" source handle: it was code node, removing that as well... code="+ipe+" parent="+ipe.getParent());
857
System.err.println(" source handle: it was code node, removing that as well... code=" + ipe
858
+ " parent=" + ipe.getParent());
782
859
removeSingleNode(ipe);
786
if (debug) dumprelsStderr("after processing 'affects'");
789
if (debug) System.err.println("<<removeRelationshipsTargettingThisFile");
864
dumprelsStderr("after processing 'affects'");
868
System.err.println("<<removeRelationshipsTargettingThisFile");
793
872
* Return true if the target element is in the type specified.
795
private boolean sameType(String hid,IProgramElement target, IProgramElement type) {
874
private boolean sameType(String hid, IProgramElement target, IProgramElement type) {
796
875
IProgramElement containingType = target;
798
877
throw new RuntimeException("target can't be null!");
800
879
throw new RuntimeException("type can't be null!");
801
if (target.getKind().isSourceFile()) {
802
// @AJ aspect with broken relationship endpoint - we couldn't find the real
803
// endpoint (the declare parents or ITD or similar) so defaulted to the
880
if (target.getKind().isSourceFile() || target.getKind().isFile()) { // isFile() covers pr263487
881
// @AJ aspect with broken relationship endpoint - we couldn't find
883
// endpoint (the declare parents or ITD or similar) so defaulted to
804
885
// first line of the source file...
807
// Let's assume the worst, and that it is the same type if the source files
808
// are the same. This will break for multiple top level types in a file...
809
if (target.getSourceLocation()==null) return false; // these four possibilities should really be FIXED so we don't have this situation
810
if (type.getSourceLocation()==null) return false;
811
if (target.getSourceLocation().getSourceFile()==null) return false;
812
if (type.getSourceLocation().getSourceFile()==null) return false;
888
// Let's assume the worst, and that it is the same type if the
890
// are the same. This will break for multiple top level types in a
892
if (target.getSourceLocation() == null)
893
return false; // these four possibilities should really be FIXED
894
// so we don't have this situation
895
if (type.getSourceLocation() == null)
897
if (target.getSourceLocation().getSourceFile() == null)
899
if (type.getSourceLocation().getSourceFile() == null)
813
901
return (target.getSourceLocation().getSourceFile().equals(type.getSourceLocation().getSourceFile()));
815
while (!containingType.getKind().isType()) {
816
// System.err.println("Checked: "+containingType.getKind()+" "+containingType);
817
containingType = containingType.getParent();
904
while (!containingType.getKind().isType()) {
905
containingType = containingType.getParent();
907
} catch (Throwable t) {
909
// java.lang.RuntimeException: Exception whilst walking up from target X.class kind=(file)
910
// hid=(=importProb/binaries<x(X.class)
911
throw new RuntimeException("Exception whilst walking up from target " + target.toLabelString() + " kind=("
912
+ target.getKind() + ") hid=(" + target.getHandleIdentifier() + ")", t);
819
914
return (type.equals(containingType));
823
* Go through all the relationships in the model, if any endpoints no longer exist (the node it
824
* points to has been deleted from the model) then delete the relationship.
918
* @param handle a JDT like handle, following the form described in AsmRelationshipProvider.findOrFakeUpNode
919
* @return true if the handle contains ';' - the char indicating that it is a phantom handle
921
private boolean isPhantomHandle(String handle) {
922
return handle.indexOf(HandleProviderDelimiter.PHANTOM.getDelimiter()) != -1;
926
* Go through all the relationships in the model, if any endpoints no longer exist (the node it points to has been deleted from
927
* the model) then delete the relationship.
826
929
private void repairRelationships(Writer fw) {
828
IHierarchy model = AsmManager.getDefault().getHierarchy();
829
//TODO Speed this code up by making this assumption:
830
// the only piece of the handle that is interesting is the file name. We are working at file granularity, if the
831
// file does not exist (i.e. its not in the filemap) then any handle inside that file cannot exist.
832
if (dumpDeltaProcessing) fw.write("Repairing relationships map:\n");
834
// Now sort out the relationships map
835
IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
836
Set sourcesToRemove = new HashSet();
837
Set nonExistingHandles = new HashSet(); // Cache of handles that we *know* are invalid
838
int srchandlecounter = 0;
839
int tgthandlecounter = 0;
841
// Iterate over the source handles in the relationships map
842
Set keyset = irm.getEntries(); // These are source handles
843
for (Iterator keyiter = keyset.iterator(); keyiter.hasNext();) {
844
String hid = (String) keyiter.next();
847
// Do we already know this handle points to nowhere?
848
if (nonExistingHandles.contains(hid)) {
849
sourcesToRemove.add(hid);
851
// We better check if it actually exists
852
IProgramElement existingElement = model.getElement(hid);
853
if (dumpDeltaProcessing) fw.write("Looking for handle ["+hid+"] in model, found: "+existingElement+"\n");
856
if (existingElement == null) {
857
// No, so delete this relationship
931
// IHierarchy model = AsmManager.getDefault().getHierarchy();
932
// TODO Speed this code up by making this assumption:
933
// the only piece of the handle that is interesting is the file
934
// name. We are working at file granularity, if the
935
// file does not exist (i.e. its not in the filemap) then any handle
936
// inside that file cannot exist.
937
if (dumpDeltaProcessing)
938
fw.write("Repairing relationships map:\n");
940
// Now sort out the relationships map
941
// IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
942
Set sourcesToRemove = new HashSet();
943
Set nonExistingHandles = new HashSet(); // Cache of handles that we
944
// *know* are invalid
945
int srchandlecounter = 0;
946
int tgthandlecounter = 0;
948
// Iterate over the source handles in the relationships map
949
Set keyset = mapper.getEntries(); // These are source handles
950
for (Iterator keyiter = keyset.iterator(); keyiter.hasNext();) {
951
String hid = (String) keyiter.next();
954
// Do we already know this handle points to nowhere?
955
if (nonExistingHandles.contains(hid)) {
858
956
sourcesToRemove.add(hid);
859
nonExistingHandles.add(hid); // Speed up a bit you swine
861
// Ok, so the source is valid, what about the targets?
862
List relationships = irm.get(hid);
863
List relationshipsToRemove = new ArrayList();
864
// Iterate through the relationships against this source handle
865
for (Iterator reliter = relationships.iterator();reliter.hasNext();) {
866
IRelationship rel = (IRelationship) reliter.next();
867
List targets = rel.getTargets();
868
List targetsToRemove = new ArrayList();
870
// Iterate through the targets for this relationship
871
for (Iterator targetIter = targets.iterator();targetIter.hasNext();) {
872
String targethid = (String) targetIter.next();
874
// Do we already know it doesn't exist?
875
if (nonExistingHandles.contains(targethid)) {
876
if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n");
877
targetsToRemove.add(targethid);
880
IProgramElement existingTarget = model.getElement(targethid);
881
if (existingTarget == null) {
882
if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n");
957
} else if (!isPhantomHandle(hid)) {
958
// We better check if it actually exists
959
IProgramElement existingElement = hierarchy.getElement(hid);
960
if (dumpDeltaProcessing) {
961
fw.write("Looking for handle [" + hid + "] in model, found: " + existingElement + "\n");
964
if (existingElement == null) {
965
// No, so delete this relationship
966
sourcesToRemove.add(hid);
967
nonExistingHandles.add(hid); // Speed up a bit you swine
969
// Ok, so the source is valid, what about the targets?
970
List relationships = mapper.get(hid);
971
List relationshipsToRemove = new ArrayList();
972
// Iterate through the relationships against this source
974
for (Iterator reliter = relationships.iterator(); reliter.hasNext();) {
975
IRelationship rel = (IRelationship) reliter.next();
976
List targets = rel.getTargets();
977
List targetsToRemove = new ArrayList();
979
// Iterate through the targets for this relationship
980
for (Iterator targetIter = targets.iterator(); targetIter.hasNext();) {
981
String targethid = (String) targetIter.next();
983
// Do we already know it doesn't exist?
984
if (nonExistingHandles.contains(targethid)) {
985
if (dumpDeltaProcessing)
986
fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel[" + rel.getName()
987
+ "] does not exist\n");
883
988
targetsToRemove.add(targethid);
884
nonExistingHandles.add(targethid);
989
} else if (!isPhantomHandle(targethid)) {
991
IProgramElement existingTarget = hierarchy.getElement(targethid);
992
if (existingTarget == null) {
993
if (dumpDeltaProcessing)
994
fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel["
995
+ rel.getName() + "] does not exist\n");
996
targetsToRemove.add(targethid);
997
nonExistingHandles.add(targethid);
1002
// Do we have some targets that need removing?
1003
if (targetsToRemove.size() != 0) {
1004
// Are we removing *all* of the targets for this
1005
// relationship (i.e. removing the relationship)
1006
if (targetsToRemove.size() == targets.size()) {
1007
if (dumpDeltaProcessing)
1008
fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
1009
+ "]: removing it\n");
1010
relationshipsToRemove.add(rel);
1012
// Remove all the targets that are no longer
1014
for (Iterator targsIter = targetsToRemove.iterator(); targsIter.hasNext();) {
1015
String togo = (String) targsIter.next();
1016
targets.remove(togo);
1018
// Should have already been caught above,
1019
// but lets double check ...
1020
if (targets.size() == 0) {
1021
if (dumpDeltaProcessing)
1022
fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
1023
+ "]: removing it\n");
1024
relationshipsToRemove.add(rel); // TODO
889
// Do we have some targets that need removing?
890
if (targetsToRemove.size()!=0) {
891
// Are we removing *all* of the targets for this relationship (i.e. removing the relationship)
892
if (targetsToRemove.size()==targets.size()) {
893
if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n");
894
relationshipsToRemove.add(rel);
1038
// Now, were any relationships emptied during that
1039
// processing and so need removing for this source
1041
if (relationshipsToRemove.size() > 0) {
1042
// Are we removing *all* of the relationships for
1043
// this source handle?
1044
if (relationshipsToRemove.size() == relationships.size()) {
1045
// We know they are all going to go, so just
1046
// delete the source handle.
1047
sourcesToRemove.add(hid);
896
// Remove all the targets that are no longer valid
897
for (Iterator targsIter = targetsToRemove.iterator();targsIter.hasNext();) {
898
String togo = (String) targsIter.next();
899
targets.remove(togo);
901
// Should have already been caught above, but lets double check ...
902
if (targets.size()==0) {
903
if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n");
904
relationshipsToRemove.add(rel); // TODO Should only remove this relationship for the srchid?
909
// Now, were any relationships emptied during that processing and so need removing for this source handle
910
if (relationshipsToRemove.size()>0) {
911
// Are we removing *all* of the relationships for this source handle?
912
if (relationshipsToRemove.size() == relationships.size()) {
913
// We know they are all going to go, so just delete the source handle.
914
sourcesToRemove.add(hid);
916
// MEMORY LEAK - we don't remove the relationships !!
917
for (int i = 0 ;i<relationshipsToRemove.size();i++) {
918
IRelationship irel = (IRelationship)relationshipsToRemove.get(i);
919
verifyAssumption(irm.remove(hid,irel),"Failed to remove relationship "+irel.getName()+" for shid "+hid);
921
List rels = irm.get(hid);
922
if (rels==null || rels.size()==0) sourcesToRemove.add(hid);
928
// Remove sources that have no valid relationships any more
929
for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
930
String hid = (String) srciter.next();
932
IProgramElement ipe = model.getElement(hid);
934
// If the relationship was hanging off a 'code' node, delete it.
935
if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
936
//System.err.println("Deleting code node");
937
removeSingleNode(ipe);
1049
// MEMORY LEAK - we don't remove the
1051
for (int i = 0; i < relationshipsToRemove.size(); i++) {
1052
IRelationship irel = (IRelationship) relationshipsToRemove.get(i);
1053
verifyAssumption(mapper.remove(hid, irel), "Failed to remove relationship " + irel.getName()
1054
+ " for shid " + hid);
1056
List rels = mapper.get(hid);
1057
if (rels == null || rels.size() == 0)
1058
sourcesToRemove.add(hid);
1064
// Remove sources that have no valid relationships any more
1065
for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
1066
String hid = (String) srciter.next();
1067
mapper.removeAll(hid);
1068
IProgramElement ipe = hierarchy.getElement(hid);
1070
// If the relationship was hanging off a 'code' node, delete
1072
if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
1073
// System.err.println("Deleting code node");
1074
removeSingleNode(ipe);
941
1078
} catch (IOException ioe) {
942
1079
System.err.println("Failed to repair relationships:");
943
1080
ioe.printStackTrace();
948
* Removes a specified program element from the structure model.
949
* We go to the parent of the program element, ask for all its children
950
* and remove the node we want to delete from the list of children.
1085
* Removes a specified program element from the structure model. We go to the parent of the program element, ask for all its
1086
* children and remove the node we want to delete from the list of children.
952
1088
private void removeSingleNode(IProgramElement progElem) {
953
verifyAssumption(progElem!=null);
1089
if (progElem == null) {
1090
throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
954
1092
boolean deleteOK = false;
955
1093
IProgramElement parent = progElem.getParent();
956
1094
List kids = parent.getChildren();
957
for (int i =0 ;i<kids.size();i++) {
958
if (kids.get(i).equals(progElem)) {
1095
for (int i = 0; i < kids.size(); i++) {
1096
if (kids.get(i).equals(progElem)) {
964
1102
verifyAssumption(deleteOK);
969
* Removes a specified program element from the structure model.
970
* Two processing stages:
971
* <p>First: We go to the parent of the program element, ask for all its children
972
* and remove the node we want to delete from the list of children.
973
* <p>Second:We check if that parent has any other children. If it has no other
974
* children and it is either a CODE node or a PACKAGE node, we delete it too.
1106
* Removes a specified program element from the structure model. Two processing stages:
1108
* 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
1111
* 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
1112
* node, we delete it too.
976
1114
private void removeNode(IProgramElement progElem) {
978
// StringBuffer flightrecorder = new StringBuffer();
1116
// StringBuffer flightrecorder = new StringBuffer();
980
// flightrecorder.append("In removeNode, about to chuck away: "+progElem+"\n");
982
verifyAssumption(progElem!=null);
983
// boolean deleteOK = false;
1118
// flightrecorder.append("In removeNode, about to chuck away: "+
1120
if (progElem == null) {
1121
throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
1123
// boolean deleteOK = false;
984
1124
IProgramElement parent = progElem.getParent();
985
// flightrecorder.append("Parent of it is "+parent+"\n");
1125
// flightrecorder.append("Parent of it is "+parent+"\n");
986
1126
List kids = parent.getChildren();
987
// flightrecorder.append("Which has "+kids.size()+" kids\n");
988
for (int i =0 ;i<kids.size();i++) {
989
// flightrecorder.append("Comparing with "+kids.get(i)+"\n");
990
if (kids.get(i).equals(progElem)) {
992
// flightrecorder.append("Removing it\n");
1127
// flightrecorder.append("Which has "+kids.size()+" kids\n");
1128
for (int i = 0; i < kids.size(); i++) {
1129
// flightrecorder.append("Comparing with "+kids.get(i)+"\n");
1130
if (kids.get(i).equals(progElem)) {
1132
// flightrecorder.append("Removing it\n");
997
// verifyAssumption(deleteOK,flightrecorder.toString());
1137
// verifyAssumption(deleteOK,flightrecorder.toString());
998
1138
// Are there any kids left for this node?
999
if (parent.getChildren().size()==0 && parent.getParent()!=null &&
1000
(parent.getKind().equals(IProgramElement.Kind.CODE) ||
1001
parent.getKind().equals(IProgramElement.Kind.PACKAGE))) {
1002
// 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
1139
if (parent.getChildren().size() == 0
1140
&& parent.getParent() != null
1141
&& (parent.getKind().equals(IProgramElement.Kind.CODE) || parent.getKind().equals(IProgramElement.Kind.PACKAGE))) {
1142
// This node is on its own, we should trim it too *as long as
1143
// its not a structural node* which we currently check by
1144
// making sure its a code node
1003
1145
// We should trim if it
1004
1146
// System.err.println("Deleting parent:"+parent);
1005
1147
removeNode(parent);
1007
} catch (NullPointerException npe ){
1008
// Occurred when commenting out other 2 ras classes in wsif?? reproducable?
1009
// System.err.println(flightrecorder.toString());
1149
} catch (NullPointerException npe) {
1150
// Occurred when commenting out other 2 ras classes in wsif??
1152
// System.err.println(flightrecorder.toString());
1010
1153
npe.printStackTrace();
1015
public static void verifyAssumption(boolean b,String info) {
1157
public static void verifyAssumption(boolean b, String info) {
1017
1159
System.err.println("=========== ASSERTION IS NOT TRUE =========v");
1018
1160
System.err.println(info);
1019
1161
Thread.dumpStack();
1020
System.err.println("=========== ASSERTION IS NOT TRUE =========^");
1162
System.err.println("=========== ASSERTION IS NOT TRUE =========^");
1021
1163
throw new RuntimeException("Assertion is false");
1025
1167
public static void verifyAssumption(boolean b) {
1027
1169
Thread.dumpStack();
1028
1170
throw new RuntimeException("Assertion is false");
1033
//===================== DELTA PROCESSING CODE ============== end ==========//
1174
// ===================== DELTA PROCESSING CODE ============== end
1036
* A ModelInfo object captures basic information about the structure model.
1037
* It is used for testing and producing debug info.
1178
* A ModelInfo object captures basic information about the structure model. It is used for testing and producing debug info.
1039
1180
public static class ModelInfo {
1040
private Hashtable nodeTypeCount = new Hashtable();
1041
private Properties extraProperties = new Properties();
1043
private ModelInfo(IHierarchy hierarchy,IRelationshipMap relationshipMap) {
1044
IProgramElement ipe = hierarchy.getRoot();
1046
recordStat("FileMapSize",
1047
new Integer(hierarchy.getFileMapEntrySet().size()).toString());
1048
recordStat("RelationshipMapSize",
1049
new Integer(relationshipMap.getEntries().size()).toString());
1181
private final Hashtable nodeTypeCount = new Hashtable();
1182
private final Properties extraProperties = new Properties();
1184
private ModelInfo(IHierarchy hierarchy, IRelationshipMap relationshipMap) {
1185
IProgramElement ipe = hierarchy.getRoot();
1187
recordStat("FileMapSize", new Integer(hierarchy.getFileMapEntrySet().size()).toString());
1188
recordStat("RelationshipMapSize", new Integer(relationshipMap.getEntries().size()).toString());
1052
1191
private void walkModel(IProgramElement ipe) {
1053
1192
countNode(ipe);
1054
1193
List kids = ipe.getChildren();
1057
1196
walkModel(nextElement);
1061
1200
private void countNode(IProgramElement ipe) {
1062
1201
String node = ipe.getKind().toString();
1063
Integer ctr = (Integer)nodeTypeCount.get(node);
1065
nodeTypeCount.put(node,new Integer(1));
1202
Integer ctr = (Integer) nodeTypeCount.get(node);
1204
nodeTypeCount.put(node, new Integer(1));
1067
ctr = new Integer(ctr.intValue()+1);
1068
nodeTypeCount.put(node,ctr);
1206
ctr = new Integer(ctr.intValue() + 1);
1207
nodeTypeCount.put(node, ctr);
1072
1211
public String toString() {
1073
1212
StringBuffer sb = new StringBuffer();
1074
1213
sb.append("Model node summary:\n");
1075
1214
Enumeration nodeKeys = nodeTypeCount.keys();
1076
1215
while (nodeKeys.hasMoreElements()) {
1077
String key = (String)nodeKeys.nextElement();
1078
Integer ct = (Integer)nodeTypeCount.get(key);
1079
sb.append(key+"="+ct+"\n");
1216
String key = (String) nodeKeys.nextElement();
1217
Integer ct = (Integer) nodeTypeCount.get(key);
1218
sb.append(key + "=" + ct + "\n");
1081
1220
sb.append("Model stats:\n");
1082
1221
Enumeration ks = extraProperties.keys();
1083
1222
while (ks.hasMoreElements()) {
1084
String k = (String)ks.nextElement();
1223
String k = (String) ks.nextElement();
1085
1224
String v = extraProperties.getProperty(k);
1086
sb.append(k+"="+v+"\n");
1225
sb.append(k + "=" + v + "\n");
1088
1227
return sb.toString();
1091
1230
public Properties getProperties() {
1092
1231
Properties p = new Properties();
1093
1232
Enumeration nodeKeys = nodeTypeCount.keys();
1094
1233
while (nodeKeys.hasMoreElements()) {
1095
String key = (String)nodeKeys.nextElement();
1096
Integer ct = (Integer)nodeTypeCount.get(key);
1097
p.setProperty(key,ct.toString());
1234
String key = (String) nodeKeys.nextElement();
1235
Integer ct = (Integer) nodeTypeCount.get(key);
1236
p.setProperty(key, ct.toString());
1099
1238
p.putAll(extraProperties);
1103
1242
public void recordStat(String string, String string2) {
1104
extraProperties.setProperty(string,string2);
1107
public static ModelInfo summarizeModel() {
1108
return new ModelInfo(AsmManager.getDefault().getHierarchy(),
1109
AsmManager.getDefault().getRelationshipMap());
1115
* Set to indicate whether we are currently building a structure model, should
1118
public static void setCreatingModel(boolean b) {
1123
* returns true if we are currently generating a structure model, enables
1124
* guarding of expensive operations on an empty/null model.
1126
public static boolean isCreatingModel() { return creatingModel;}
1243
extraProperties.setProperty(string, string2);
1248
public ModelInfo summarizeModel() {
1249
return new ModelInfo(getHierarchy(), getRelationshipMap());
1253
* Set to indicate whether we are currently building a structure model, should be set up front.
1255
// public static void setCreatingModel(boolean b) {
1256
// creatingModel = b;
1260
// * returns true if we are currently generating a structure model, enables guarding of expensive operations on an empty/null
1263
// public static boolean isCreatingModel() {
1264
// return creatingModel;
1128
1266
public static void setCompletingTypeBindings(boolean b) {
1129
1267
completingTypeBindings = b;
1132
public static boolean isCompletingTypeBindings() { return completingTypeBindings; }
1270
public static boolean isCompletingTypeBindings() {
1271
return completingTypeBindings;
1274
// public void setRelationshipMap(IRelationshipMap irm) {
1278
// public void setHierarchy(IHierarchy ih) {
1282
public void resetDeltaProcessing() {
1283
lastBuildChanges.clear();
1284
aspectsWeavingInLastBuild.clear();
1288
* @return the Set of files for which the structure model was modified (they may have been removed or otherwise rebuilt). Set is
1289
* empty for a full build.
1291
public Set getModelChangesOnLastBuild() {
1292
return lastBuildChanges;
1296
* @return the Set of aspects that wove files on the last build (either incremental or full build)
1298
public Set getAspectsWeavingFilesOnLastBuild() {
1299
return aspectsWeavingInLastBuild;
1302
public void addAspectInEffectThisBuild(File f) {
1303
aspectsWeavingInLastBuild.add(f);
1306
public static void setLastActiveStructureModel(AsmManager structureModel) {
1307
if (recordingLastActiveStructureModel) {
1308
lastActiveStructureModel = structureModel;
1312
public String getHandleElementForInpath(String binaryPath) {
1313
return (String) inpathMap.get(new File(binaryPath));
1316
private List pieces = new ArrayList();
1318
private Object intern(String substring) {
1320
if ((lastIdx = substring.lastIndexOf('/')) != -1) {
1321
String pkg = substring.substring(0, lastIdx);
1322
String type = substring.substring(lastIdx + 1);
1323
pkg = internOneThing(pkg);
1324
type = internOneThing(type);
1325
return new String[] { pkg, type };
1327
return internOneThing(substring);
1331
private String internOneThing(String substring) {
1333
for (int p = 0, max = pieces.size(); p < max; p++) {
1334
String s = (String) pieces.get(p);
1335
if (s.equals(substring)) {
1339
pieces.add(substring);
1344
* What we can rely on: <br>
1345
* - it is a method signature of the form (La/B;Lc/D;)LFoo;<br>
1346
* - there are no generics<br>
1348
* What we must allow for: - may use primitive refs (single chars rather than L)
1351
public List compress(String s) {
1353
int closeParen = s.indexOf(')');
1355
List compressed = new ArrayList();
1357
while (pos < closeParen) {
1358
char ch = s.charAt(pos);
1360
int idx = s.indexOf(';', pos);
1361
compressed.add(intern(s.substring(pos + 1, idx)));
1363
} else if (ch == '[') {
1365
while (s.charAt(++pos) == '[')
1367
// now pos will point at something not an array
1368
compressed.add(intern(s.substring(x, pos))); // intern the [[[[[[
1369
char ch2 = s.charAt(pos);
1371
int idx = s.indexOf(';', pos);
1372
compressed.add(intern(s.substring(pos + 1, idx)));
1374
} else if (ch2 == 'T') {
1375
int idx = s.indexOf(';');
1376
compressed.add(intern(s.substring(pos, idx + 1))); // should be TT;
1379
compressed.add(toCharacter(s.charAt(pos)));
1383
// it is a primitive ref (SVBCZJ)
1384
compressed.add(toCharacter(ch));
1388
// do the return type
1390
char ch = s.charAt(pos);
1392
int idx = s.indexOf(';', pos);
1393
compressed.add(intern(s.substring(pos, idx)));
1394
} else if (ch == '[') {
1396
while (s.charAt(++pos) == '[')
1398
// now pos will point at something not an array
1399
compressed.add(intern(s.substring(x, pos))); // intern the [[[[[[
1400
char ch2 = s.charAt(pos);
1402
int idx = s.indexOf(';', pos);
1403
compressed.add(intern(s.substring(pos + 1, idx)));
1405
} else if (ch2 == 'T') {
1406
int idx = s.indexOf(';');
1407
compressed.add(intern(s.substring(pos, idx + 1))); // should be TT;
1410
compressed.add(toCharacter(s.charAt(pos)));
1414
// it is a primitive ref (SVBCZJ)
1415
compressed.add(new Character(ch));
1419
// char delimiter = '/';
1421
// List compressed = new ArrayList();
1423
// while ((pos = s.indexOf(delimiter, start)) != -1) {
1424
// String part = s.substring(start, pos);
1425
// int alreadyRecorded = pieces.indexOf(part);
1426
// if (alreadyRecorded != -1) {
1427
// compressed.add(new Integer(alreadyRecorded));
1429
// compressed.add(new Integer(pieces.size()));
1430
// pieces.add(part);
1435
// String part = s.substring(start, s.length());
1436
// int alreadyRecorded = pieces.indexOf(part);
1437
// if (alreadyRecorded != -1) {
1438
// compressed.add(youkirtyounew Integer(alreadyRecorded));
1440
// compressed.add(new Integer(pieces.size()));
1441
// pieces.add(part);
1443
// return compressed;
1446
static final Character charB = new Character('B');
1447
static final Character charS = new Character('S');
1448
static final Character charI = new Character('I');
1449
static final Character charF = new Character('F');
1450
static final Character charD = new Character('D');
1451
static final Character charJ = new Character('J');
1452
static final Character charC = new Character('C');
1453
static final Character charV = new Character('V');
1454
static final Character charZ = new Character('Z');
1456
private Character toCharacter(char ch) {
1477
throw new IllegalStateException(new Character(ch).toString());
1481
public String decompress(List refs, char delimiter) {
1482
StringBuilder result = new StringBuilder();
1484
for (int i = 0, max = refs.size() - 1; i < max; i++) {
1485
result.append(unintern(refs.get(i)));
1488
result.append(unintern(refs.get(refs.size() - 1)));
1489
return result.toString();
1492
private String unintern(Object o) {
1493
if (o instanceof Character) {
1494
return ((Character) o).toString();
1495
} else if (o instanceof String[]) {
1496
String[] strings = (String[]) o;
1497
StringBuilder sb = new StringBuilder();
1499
sb.append(strings[0]).append('/').append(strings[1]);
1501
return sb.toString();
1503
String so = (String) o;
1504
if (so.endsWith(";")) {
1508
StringBuilder sb = new StringBuilder();
1512
return sb.toString();