12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304 |
- /* *******************************************************************
- * Copyright (c) 2003 Contributors.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Mik Kersten initial implementation
- * Andy Clement incremental support and switch on/off state
- * ******************************************************************/
-
- package org.aspectj.asm;
-
- import java.io.BufferedWriter;
- import java.io.EOFException;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.FileWriter;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.io.Writer;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Hashtable;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Properties;
- import java.util.Set;
-
- import org.aspectj.asm.internal.AspectJElementHierarchy;
- import org.aspectj.asm.internal.HandleProviderDelimiter;
- import org.aspectj.asm.internal.JDTLikeHandleProvider;
- import org.aspectj.asm.internal.RelationshipMap;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.util.IStructureModel;
-
- /**
- * The Abstract Structure Model (ASM) represents the containment hierarchy and crosscutting structure map for AspectJ programs. It
- * is used by IDE views such as the document outline, and by other tools such as ajdoc to show both AspectJ declarations and
- * crosscutting links, such as which advice affects which join point shadows.
- *
- * @author Mik Kersten
- * @author Andy Clement
- */
- public class AsmManager implements IStructureModel {
-
- // For testing ONLY
- public static boolean recordingLastActiveStructureModel = true;
- public static AsmManager lastActiveStructureModel;
- public static boolean forceSingletonBehaviour = false;
-
- // SECRETAPI asc pull the secret options together into a system API you lazy fool
- public static boolean attemptIncrementalModelRepairs = false;
- // Dumping the model is expensive
- public static boolean dumpModelPostBuild = false;
- // For offline debugging, you can now ask for the AsmManager to
- // dump the model - see the method setReporting()
- private static boolean dumpModel = false;
- private static boolean dumpRelationships = false;
- private static boolean dumpDeltaProcessing = false;
- private static IModelFilter modelFilter = null;
- private static String dumpFilename = "";
- private static boolean reporting = false;
-
- private static boolean completingTypeBindings = false;
-
- private final List<IHierarchyListener> structureListeners = new ArrayList<IHierarchyListener>();
-
- // The model is 'manipulated' by the AjBuildManager.setupModel() code which
- // trashes all the
- // fields when setting up a new model for a batch build.
- // Due to the requirements of incremental compilation we need to tie some of
- // the info
- // below to the AjState for a compilation and recover it if switching
- // between projects.
- protected IHierarchy hierarchy;
-
- /*
- * Map from String > String - it maps absolute paths for inpath dirs/jars to workspace relative paths suitable for handle
- * inclusion
- */
- protected Map<File, String> inpathMap;
- private IRelationshipMap mapper;
- private IElementHandleProvider handleProvider;
-
- private final CanonicalFilePathMap canonicalFilePathMap = new CanonicalFilePathMap();
- // Record the Set<File> for which the model has been modified during the
- // last incremental build
- private final Set<File> lastBuildChanges = new HashSet<File>();
-
- // Record the Set<File> of aspects that wove the files listed in lastBuildChanges
- final Set<File> aspectsWeavingInLastBuild = new HashSet<File>();
-
- // static {
- // setReporting("c:/model.nfo",true,true,true,true);
- // }
-
- private AsmManager() {
- }
-
- public static AsmManager createNewStructureModel(Map<File, String> inpathMap) {
- if (forceSingletonBehaviour && lastActiveStructureModel != null) {
- return lastActiveStructureModel;
- }
- AsmManager asm = new AsmManager();
- asm.inpathMap = inpathMap;
- asm.hierarchy = new AspectJElementHierarchy(asm);
- asm.mapper = new RelationshipMap();
- asm.handleProvider = new JDTLikeHandleProvider(asm);
- // call initialize on the handleProvider when we create a new ASM
- // to give handleProviders the chance to reset any state
- asm.handleProvider.initialize();
- asm.resetDeltaProcessing();
- setLastActiveStructureModel(asm);
- return asm;
- }
-
- public IHierarchy getHierarchy() {
- return hierarchy;
- }
-
- public IRelationshipMap getRelationshipMap() {
- return mapper;
- }
-
- public void fireModelUpdated() {
- notifyListeners();
- if (dumpModelPostBuild && hierarchy.getConfigFile() != null) {
- writeStructureModel(hierarchy.getConfigFile());
- }
- }
-
- /**
- * Constructs map each time it's called.
- */
- public HashMap<Integer, List<IProgramElement>> getInlineAnnotations(String sourceFile, boolean showSubMember,
- boolean showMemberAndType) {
-
- if (!hierarchy.isValid()) {
- return null;
- }
-
- HashMap<Integer, List<IProgramElement>> annotations = new HashMap<Integer, List<IProgramElement>>();
- IProgramElement node = hierarchy.findElementForSourceFile(sourceFile);
- if (node == IHierarchy.NO_STRUCTURE) {
- return null;
- } else {
- IProgramElement fileNode = node;
- ArrayList<IProgramElement> peNodes = new ArrayList<IProgramElement>();
- getAllStructureChildren(fileNode, peNodes, showSubMember, showMemberAndType);
- for (Iterator<IProgramElement> it = peNodes.iterator(); it.hasNext();) {
- IProgramElement peNode = it.next();
- List<IProgramElement> entries = new ArrayList<IProgramElement>();
- entries.add(peNode);
- ISourceLocation sourceLoc = peNode.getSourceLocation();
- if (null != sourceLoc) {
- Integer hash = new Integer(sourceLoc.getLine());
- List<IProgramElement> existingEntry = annotations.get(hash);
- if (existingEntry != null) {
- entries.addAll(existingEntry);
- }
- annotations.put(hash, entries);
- }
- }
- return annotations;
- }
- }
-
- private void getAllStructureChildren(IProgramElement node, List<IProgramElement> result, boolean showSubMember,
- boolean showMemberAndType) {
- List<IProgramElement> children = node.getChildren();
- if (node.getChildren() == null) {
- return;
- }
- for (IProgramElement next : children) {
- List<IRelationship> rels = mapper.get(next);
- if (next != null
- && ((next.getKind() == IProgramElement.Kind.CODE && showSubMember) || (next.getKind() != IProgramElement.Kind.CODE && showMemberAndType))
- && rels != null && rels.size() > 0) {
- result.add(next);
- }
- getAllStructureChildren(next, result, showSubMember, showMemberAndType);
- }
- }
-
- public void addListener(IHierarchyListener listener) {
- structureListeners.add(listener);
- }
-
- public void removeStructureListener(IHierarchyListener listener) {
- structureListeners.remove(listener);
- }
-
- // this shouldn't be needed - but none of the people that add listeners
- // in the test suite ever remove them. AMC added this to be called in
- // setup() so that the test cases would cease leaking listeners and go
- // back to executing at a reasonable speed.
- public void removeAllListeners() {
- structureListeners.clear();
- }
-
- private void notifyListeners() {
- for (IHierarchyListener listener : structureListeners) {
- listener.elementsUpdated(hierarchy);
- }
- }
-
- public IElementHandleProvider getHandleProvider() {
- return handleProvider;
- }
-
- public void setHandleProvider(IElementHandleProvider handleProvider) {
- this.handleProvider = handleProvider;
- }
-
- public void writeStructureModel(String configFilePath) {
- try {
- String filePath = genExternFilePath(configFilePath);
- FileOutputStream fos = new FileOutputStream(filePath);
- ObjectOutputStream s = new ObjectOutputStream(fos);
- s.writeObject(hierarchy); // Store the program element tree
- s.writeObject(mapper); // Store the relationships
- s.flush();
- fos.flush();
- fos.close();
- s.close();
- } catch (IOException e) {
- // System.err.println("AsmManager: Unable to write structure model: "
- // +configFilePath+" because of:");
- // e.printStackTrace();
- }
- }
-
- /**
- * @param configFilePath path to an ".lst" file
- */
- public void readStructureModel(String configFilePath) {
- boolean hierarchyReadOK = false;
- try {
- if (configFilePath == null) {
- hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
- } else {
- String filePath = genExternFilePath(configFilePath);
- FileInputStream in = new FileInputStream(filePath);
- ObjectInputStream s = new ObjectInputStream(in);
- hierarchy = (AspectJElementHierarchy) s.readObject();
- ((AspectJElementHierarchy) hierarchy).setAsmManager(this);
- hierarchyReadOK = true;
- mapper = (RelationshipMap) s.readObject();
- }
- } catch (FileNotFoundException fnfe) {
- // That is OK
- hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
- } catch (EOFException eofe) {
- // Might be an old format sym file that is missing its relationships
- if (!hierarchyReadOK) {
- System.err.println("AsmManager: Unable to read structure model: " + configFilePath + " because of:");
- eofe.printStackTrace();
- hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
- }
- } catch (Exception e) {
- // System.err.println("AsmManager: Unable to read structure model: "+
- // configFilePath+" because of:");
- // e.printStackTrace();
- hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
- } finally {
- notifyListeners();
- }
- }
-
- private String genExternFilePath(String configFilePath) {
- // sometimes don't have ".lst"
- if (configFilePath.lastIndexOf(".lst") != -1) {
- configFilePath = configFilePath.substring(0, configFilePath.lastIndexOf(".lst"));
- }
- return configFilePath + ".ajsym";
- }
-
- public String getCanonicalFilePath(File f) {
- return canonicalFilePathMap.get(f);
- }
-
- public CanonicalFilePathMap getCanonicalFilePathMap() {
- return canonicalFilePathMap;
- }
-
- private static class CanonicalFilePathMap {
- private static final int MAX_SIZE = 4000;
-
- private final Map<String, String> pathMap = new HashMap<String, String>(20);
-
- // // guards to ensure correctness and liveness
- // private boolean cacheInUse = false;
- // private boolean stopRequested = false;
- //
- // private synchronized boolean isCacheInUse() {
- // return cacheInUse;
- // }
- //
- // private synchronized void setCacheInUse(boolean val) {
- // cacheInUse = val;
- // if (val) {
- // notifyAll();
- // }
- // }
- //
- // private synchronized boolean isStopRequested() {
- // return stopRequested;
- // }
- //
- // private synchronized void requestStop() {
- // stopRequested = true;
- // }
- //
- // /**
- // * Begin prepopulating the map by adding an entry from
- // * file.getPath -> file.getCanonicalPath for each file in
- // * the list. Do this on a background thread.
- // * @param files
- // */
- // public void prepopulate(final List files) {
- // stopRequested = false;
- // setCacheInUse(false);
- // if (pathMap.size() > MAX_SIZE) {
- // pathMap.clear();
- // }
- // new Thread() {
- // public void run() {
- // System.out.println("Starting cache population: " +
- // System.currentTimeMillis());
- // Iterator it = files.iterator();
- // while (!isStopRequested() && it.hasNext()) {
- // File f = (File)it.next();
- // if (pathMap.get(f.getPath()) == null) {
- // // may reuse cache across compiles from ides...
- // try {
- // pathMap.put(f.getPath(),f.getCanonicalPath());
- // } catch (IOException ex) {
- // pathMap.put(f.getPath(),f.getPath());
- // }
- // }
- // }
- // System.out.println("Cached " + files.size());
- // setCacheInUse(true);
- // System.out.println("Cache populated: " + System.currentTimeMillis());
- // }
- // }.start();
- // }
- //
- // /**
- // * Stop pre-populating the cache - our customers are ready to use it.
- // * If there are any cache misses from this point on, we'll populate
- // the
- // * cache as we go.
- // * The handover is done this way to ensure that only one thread is
- // ever
- // * accessing the cache, and that we minimize synchronization.
- // */
- // public synchronized void handover() {
- // if (!isCacheInUse()) {
- // requestStop();
- // try {
- // while (!isCacheInUse()) wait();
- // } catch (InterruptedException intEx) { } // just continue
- // }
- // }
-
- public String get(File f) {
- // if (!cacheInUse) { // unsynchronized test - should never be
- // parallel
- // // threads at this point
- // throw new IllegalStateException(
- // "Must take ownership of cache before using by calling " +
- // "handover()");
- // }
- String ret = pathMap.get(f.getPath());
- if (ret == null) {
- try {
- ret = f.getCanonicalPath();
- } catch (IOException ioEx) {
- ret = f.getPath();
- }
- pathMap.put(f.getPath(), ret);
- if (pathMap.size() > MAX_SIZE) {
- pathMap.clear();
- }
- }
- return ret;
- }
- }
-
- // SECRETAPI
- public static void setReporting(String filename, boolean dModel, boolean dRels, boolean dDeltaProcessing, boolean deletefile) {
- reporting = true;
- dumpModel = dModel;
- dumpRelationships = dRels;
- dumpDeltaProcessing = dDeltaProcessing;
- if (deletefile) {
- new File(filename).delete();
- }
- dumpFilename = filename;
- }
-
- public static void setReporting(String filename, boolean dModel, boolean dRels, boolean dDeltaProcessing, boolean deletefile,
- IModelFilter aFilter) {
- setReporting(filename, dModel, dRels, dDeltaProcessing, deletefile);
- modelFilter = aFilter;
- }
-
- public static boolean isReporting() {
- return reporting;
- }
-
- public static void setDontReport() {
- reporting = false;
- dumpDeltaProcessing = false;
- dumpModel = false;
- dumpRelationships = false;
- }
-
- // NB. If the format of this report changes then the model tests
- // (@see org.aspectj.systemtest.model.ModelTestCase) will fail in
- // their comparison. The tests are assuming that both the model
- // and relationship map are reported and as a consequence single
- // testcases test that both the model and relationship map are correct.
- public void reportModelInfo(String reasonForReport) {
- if (!dumpModel && !dumpRelationships) {
- return;
- }
- try {
- FileWriter fw = new FileWriter(dumpFilename, true);
- BufferedWriter bw = new BufferedWriter(fw);
- if (dumpModel) {
- bw.write("=== MODEL STATUS REPORT ========= " + reasonForReport + "\n");
- dumptree(bw, hierarchy.getRoot(), 0);
-
- bw.write("=== END OF MODEL REPORT =========\n");
- }
- if (dumpRelationships) {
- bw.write("=== RELATIONSHIPS REPORT ========= " + reasonForReport + "\n");
- dumprels(bw);
- bw.write("=== END OF RELATIONSHIPS REPORT ==\n");
- }
- Properties p = summarizeModel().getProperties();
- Enumeration<Object> pkeyenum = p.keys();
- bw.write("=== Properties of the model and relationships map =====\n");
- while (pkeyenum.hasMoreElements()) {
- String pkey = (String) pkeyenum.nextElement();
- bw.write(pkey + "=" + p.getProperty(pkey) + "\n");
- }
- bw.flush();
- fw.close();
- } catch (IOException e) {
- System.err.println("InternalError: Unable to report model information:");
- e.printStackTrace();
- }
- }
-
- public static void dumptree(Writer w, IProgramElement node, int indent) throws IOException {
- for (int i = 0; i < indent; i++) {
- w.write(" ");
- }
- String loc = "";
- if (node != null) {
- if (node.getSourceLocation() != null) {
- loc = node.getSourceLocation().toString();
- if (modelFilter != null) {
- loc = modelFilter.processFilelocation(loc);
- }
- }
- }
- w.write(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc + "\n");
- if (node != null) {
- for (IProgramElement child : node.getChildren()) {
- dumptree(w, child, indent + 2);
- }
- }
- }
-
- public static void dumptree(IProgramElement node, int indent) throws IOException {
- for (int i = 0; i < indent; i++) {
- System.out.print(" ");
- }
- String loc = "";
- if (node != null) {
- if (node.getSourceLocation() != null) {
- loc = node.getSourceLocation().toString();
- }
- }
- System.out.println(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc);
- if (node != null) {
- for (IProgramElement child : node.getChildren()) {
- dumptree(child, indent + 2);
- }
- }
- }
-
- public void dumprels(Writer w) throws IOException {
- int ctr = 1;
- Set<String> entries = mapper.getEntries();
- for (String hid : entries) {
- List<IRelationship> rels = mapper.get(hid);
- for (IRelationship ir : rels) {
- List<String> targets = ir.getTargets();
- for (String thid : targets) {
- StringBuffer sb = new StringBuffer();
- if (modelFilter == null || modelFilter.wantsHandleIds()) {
- sb.append("Hid:" + (ctr++) + ":");
- }
- sb.append("(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") " + thid + "\n");
- w.write(sb.toString());
- }
- }
- }
- }
-
- private void dumprelsStderr(String key) {
- System.err.println("Relationships dump follows: " + key);
- int ctr = 1;
- Set<String> entries = mapper.getEntries();
- for (String hid : entries) {
- for (IRelationship ir : mapper.get(hid)) {
- List<String> targets = ir.getTargets();
- for (String thid : targets) {
- System.err.println("Hid:" + (ctr++) + ":(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") "
- + thid);
- }
- }
- }
- System.err.println("End of relationships dump for: " + key);
- }
-
- // ===================== DELTA PROCESSING CODE ============== start
- // ==========//
-
- /**
- * Removes the hierarchy structure for the specified files from the structure model. Returns true if it deleted anything
- */
- public boolean removeStructureModelForFiles(Writer fw, Collection<File> files) throws IOException {
-
- boolean modelModified = false;
-
- Set<String> deletedNodes = new HashSet<String>();
- for (File fileForCompilation : files) {
- String correctedPath = getCanonicalFilePath(fileForCompilation);
- IProgramElement progElem = (IProgramElement) hierarchy.findInFileMap(correctedPath);
- if (progElem != null) {
- // Found it, let's remove it
- if (dumpDeltaProcessing) {
- fw.write("Deleting " + progElem + " node for file " + fileForCompilation + "\n");
- }
- removeNode(progElem);
- lastBuildChanges.add(fileForCompilation);
- deletedNodes.add(getCanonicalFilePath(progElem.getSourceLocation().getSourceFile()));
- if (!hierarchy.removeFromFileMap(correctedPath)) {
- throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: " + correctedPath
- + " from the filemap");
- }
- modelModified = true;
- }
- }
- if (modelModified) {
- hierarchy.updateHandleMap(deletedNodes);
- }
- return modelModified;
- }
-
- public void processDelta(Collection<File> files_tobecompiled, Set<File> files_added, Set<File> files_deleted) {
-
- try {
- Writer fw = null;
-
- // Are we recording this ?
- if (dumpDeltaProcessing) {
- FileWriter filew = new FileWriter(dumpFilename, true);
- fw = new BufferedWriter(filew);
- fw.write("=== Processing delta changes for the model ===\n");
- fw.write("Files for compilation:#" + files_tobecompiled.size() + ":" + files_tobecompiled + "\n");
- fw.write("Files added :#" + files_added.size() + ":" + files_added + "\n");
- fw.write("Files deleted :#" + files_deleted.size() + ":" + files_deleted + "\n");
- }
-
- long stime = System.currentTimeMillis();
-
- // Let's remove all the files that are deleted on this compile
- removeStructureModelForFiles(fw, files_deleted);
- long etime1 = System.currentTimeMillis(); // etime1-stime = time to
- // fix up the model
-
- repairRelationships(fw);
- long etime2 = System.currentTimeMillis(); // etime2-stime = time to
- // repair the
- // relationship map
-
- removeStructureModelForFiles(fw, files_tobecompiled);
-
- if (dumpDeltaProcessing) {
- fw.write("===== Delta Processing timing ==========\n");
- fw.write("Hierarchy=" + (etime1 - stime) + "ms Relationshipmap=" + (etime2 - etime1) + "ms\n");
- fw.write("===== Traversal ========================\n");
- // fw.write("Source handles processed="+srchandlecounter+"\n");
- // fw.write("Target handles processed="+tgthandlecounter+"\n");
- fw.write("========================================\n");
- fw.flush();
- fw.close();
-
- }
- reportModelInfo("After delta processing");
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- private String getTypeNameFromHandle(String handle, Map<String, String> cache) {
- try {
- String typename = cache.get(handle);
- if (typename != null) {
- return typename;
- }
- // inpath handle - but for which type?
- // let's do it the slow way, we can optimize this with a cache perhaps
- int hasPackage = handle.indexOf(HandleProviderDelimiter.PACKAGEFRAGMENT.getDelimiter());
- int typeLocation = handle.indexOf(HandleProviderDelimiter.TYPE.getDelimiter());
- if (typeLocation == -1) {
- typeLocation = handle.indexOf(HandleProviderDelimiter.ASPECT_TYPE.getDelimiter());
- }
- if (typeLocation == -1) {
- // unexpected - time to give up
- return "";
- }
- StringBuffer qualifiedTypeNameFromHandle = new StringBuffer();
- if (hasPackage != -1) {
- int classfileLoc = handle.indexOf(HandleProviderDelimiter.CLASSFILE.getDelimiter(), hasPackage);
- qualifiedTypeNameFromHandle.append(handle.substring(hasPackage + 1, classfileLoc));
- qualifiedTypeNameFromHandle.append('.');
- }
- qualifiedTypeNameFromHandle.append(handle.substring(typeLocation + 1));
- typename = qualifiedTypeNameFromHandle.toString();
- cache.put(handle, typename);
- return typename;
- } catch (StringIndexOutOfBoundsException sioobe) {
- // debug for 330170
- System.err.println("Handle processing problem, the handle is: " + handle);
- sioobe.printStackTrace(System.err);
- return "";
- }
- }
-
- /**
- * two kinds of relationships
- *
- * A affects B B affectedBy A
- *
- * Both of these relationships are added when 'B' is modified. Concrete examples are 'advises/advisedby' or
- * 'annotates/annotatedby'.
- *
- * 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
- * 'affects' relationships where the target is 'B', remove all 'affectedBy' relationships where the source is 'B'.
- *
- */
- public void removeRelationshipsTargettingThisType(String typename) {
- boolean debug = false;
- if (debug) {
- System.err.println(">>removeRelationshipsTargettingThisType " + typename);
- }
- String pkg = null;
- String type = typename;
- int lastSep = typename.lastIndexOf('.');
- if (lastSep != -1) {
- pkg = typename.substring(0, lastSep);
- type = typename.substring(lastSep + 1);
- }
- boolean didsomething = false;
- IProgramElement typeNode = hierarchy.findElementForType(pkg, type);
-
- // Reasons for that being null:
- // 1. the file has fundamental errors and so doesn't exist in the model
- // (-proceedOnError probably forced us to weave)
- if (typeNode == null) {
- return;
- }
-
- Set<String> sourcesToRemove = new HashSet<String>();
- Map<String, String> handleToTypenameCache = new HashMap<String, String>();
- // Iterate over the source handles in the relationships map, the aim
- // here is to remove any 'affected by'
- // relationships where the source of the relationship is the specified
- // type (since it will be readded
- // when the type is woven)
- Set<String> sourcehandlesSet = mapper.getEntries();
- List<IRelationship> relationshipsToRemove = new ArrayList<IRelationship>();
- for (String hid : sourcehandlesSet) {
- if (isPhantomHandle(hid)) {
- // inpath handle - but for which type?
- // TODO promote cache for reuse during one whole model update
- if (!getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
- continue;
- }
- }
- IProgramElement sourceElement = hierarchy.getElement(hid);
- if (sourceElement == null || sameType(hid, sourceElement, typeNode)) {
- // worth continuing as there may be a relationship to remove
- relationshipsToRemove.clear();
- List<IRelationship> relationships = mapper.get(hid);
- for (IRelationship relationship : relationships) {
- if (relationship.getKind() == IRelationship.Kind.USES_POINTCUT) {
- continue; // these relationships are added at compile
- }
- // time, argh
- if (relationship.isAffects()) {
- continue; // we want 'affected by' relationships - (e.g.
- }
- // advised by)
- relationshipsToRemove.add(relationship); // all the relationships can
- // be removed, regardless of
- // the target(s)
- }
- // Now, were any relationships emptied during that processing
- // and so need removing for this source handle
- if (relationshipsToRemove.size() > 0) {
- didsomething = true;
- if (relationshipsToRemove.size() == relationships.size()) {
- sourcesToRemove.add(hid);
- } else {
- for (int i = 0; i < relationshipsToRemove.size(); i++) {
- relationships.remove(relationshipsToRemove.get(i));
- }
- }
- }
- }
- }
- // Remove sources that have no valid relationships any more
- for (String hid : sourcesToRemove) {
- // System.err.println(
- // " source handle: all relationships have gone for "+hid);
- mapper.removeAll(hid);
- IProgramElement ipe = hierarchy.getElement(hid);
- if (ipe != null) {
- // If the relationship was hanging off a 'code' node, delete it.
- if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
- if (debug) {
- System.err.println(" source handle: it was code node, removing that as well... code=" + ipe + " parent="
- + ipe.getParent());
- }
- removeSingleNode(ipe);
- }
- }
- }
-
- if (debug) {
- dumprelsStderr("after processing 'affectedby'");
- }
- if (didsomething) { // did we do anything?
- sourcesToRemove.clear();
- // removing 'affects' relationships
- if (debug) {
- dumprelsStderr("before processing 'affects'");
- }
- // Iterate over the source handles in the relationships map
- sourcehandlesSet = mapper.getEntries();
- for (String hid : sourcehandlesSet) {
- relationshipsToRemove.clear();
- List<IRelationship> relationships = mapper.get(hid);
- for (IRelationship rel : relationships) {
- if (rel.getKind() == IRelationship.Kind.USES_POINTCUT) {
- continue; // these relationships are added at compile
- }
- // time, argh
- if (!rel.isAffects()) {
- continue;
- }
- List<String> targets = rel.getTargets();
- List<String> targetsToRemove = new ArrayList<String>();
-
- // find targets that target the type we are interested in,
- // they need removing
- for (String targethid : targets) {
- if (isPhantomHandle(hid) && !getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
- continue;
- }
- // Does this point to the same type?
- IProgramElement existingTarget = hierarchy.getElement(targethid);
- if (existingTarget == null || sameType(targethid, existingTarget, typeNode)) {
- targetsToRemove.add(targethid);
- }
- }
-
- if (targetsToRemove.size() != 0) {
- if (targetsToRemove.size() == targets.size()) {
- relationshipsToRemove.add(rel);
- } else {
- // Remove all the targets that are no longer valid
- for (String togo : targetsToRemove) {
- targets.remove(togo);
- }
- }
- }
- }
- // Now, were any relationships emptied during that processing
- // and so need removing for this source handle
- if (relationshipsToRemove.size() > 0) {
- // Are we removing *all* of the relationships for this
- // source handle?
- if (relationshipsToRemove.size() == relationships.size()) {
- sourcesToRemove.add(hid);
- } else {
- for (int i = 0; i < relationshipsToRemove.size(); i++) {
- relationships.remove(relationshipsToRemove.get(i));
- }
- }
- }
- }
- // Remove sources that have no valid relationships any more
- for (String hid : sourcesToRemove) {
- // System.err.println(
- // " source handle: all relationships have gone for "+hid);
- mapper.removeAll(hid);
- IProgramElement ipe = hierarchy.getElement(hid);
- if (ipe != null) {
- // If the relationship was hanging off a 'code' node, delete
- // it.
- if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
- if (debug) {
- System.err.println(" source handle: it was code node, removing that as well... code=" + ipe
- + " parent=" + ipe.getParent());
- }
- removeSingleNode(ipe);
- }
- }
- }
- if (debug) {
- dumprelsStderr("after processing 'affects'");
- }
- }
-
- if (debug) {
- System.err.println("<<removeRelationshipsTargettingThisFile");
- }
- }
-
- /**
- * Return true if the target element is in the type specified.
- */
- private boolean sameType(String hid, IProgramElement target, IProgramElement type) {
- IProgramElement containingType = target;
- if (target == null) {
- throw new RuntimeException("target can't be null!");
- }
- if (type == null) {
- throw new RuntimeException("type can't be null!");
- }
- if (target.getKind().isSourceFile() || target.getKind().isFile()) { // isFile() covers pr263487
- // @AJ aspect with broken relationship endpoint - we couldn't find
- // the real
- // endpoint (the declare parents or ITD or similar) so defaulted to
- // the
- // first line of the source file...
-
- // FRAGILE
- // Let's assume the worst, and that it is the same type if the
- // source files
- // are the same. This will break for multiple top level types in a
- // file...
- if (target.getSourceLocation() == null) {
- return false; // these four possibilities should really be FIXED
- }
- // so we don't have this situation
- if (type.getSourceLocation() == null) {
- return false;
- }
- if (target.getSourceLocation().getSourceFile() == null) {
- return false;
- }
- if (type.getSourceLocation().getSourceFile() == null) {
- return false;
- }
- return (target.getSourceLocation().getSourceFile().equals(type.getSourceLocation().getSourceFile()));
- }
- try {
- while (!containingType.getKind().isType()) {
- containingType = containingType.getParent();
- }
- } catch (Throwable t) {
- // Example:
- // java.lang.RuntimeException: Exception whilst walking up from target X.class kind=(file)
- // hid=(=importProb/binaries<x(X.class)
- throw new RuntimeException("Exception whilst walking up from target " + target.toLabelString() + " kind=("
- + target.getKind() + ") hid=(" + target.getHandleIdentifier() + ")", t);
- }
- return (type.equals(containingType));
- }
-
- /**
- * @param handle a JDT like handle, following the form described in AsmRelationshipProvider.findOrFakeUpNode
- * @return true if the handle contains ';' - the char indicating that it is a phantom handle
- */
- private boolean isPhantomHandle(String handle) {
- int phantomMarker = handle.indexOf(HandleProviderDelimiter.PHANTOM.getDelimiter());
- return phantomMarker != -1
- && handle.charAt(phantomMarker - 1) == HandleProviderDelimiter.PACKAGEFRAGMENTROOT.getDelimiter();
- }
-
- /**
- * Go through all the relationships in the model, if any endpoints no longer exist (the node it points to has been deleted from
- * the model) then delete the relationship.
- */
- private void repairRelationships(Writer fw) {
- try {
- // IHierarchy model = AsmManager.getDefault().getHierarchy();
- // TODO Speed this code up by making this assumption:
- // the only piece of the handle that is interesting is the file
- // name. We are working at file granularity, if the
- // file does not exist (i.e. its not in the filemap) then any handle
- // inside that file cannot exist.
- if (dumpDeltaProcessing) {
- fw.write("Repairing relationships map:\n");
- }
-
- // Now sort out the relationships map
- // IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
- Set<String> sourcesToRemove = new HashSet<String>();
- Set<String> nonExistingHandles = new HashSet<String>(); // Cache of handles that we
- // *know* are invalid
- int srchandlecounter = 0;
- int tgthandlecounter = 0;
-
- // Iterate over the source handles in the relationships map
- Set<String> keyset = mapper.getEntries(); // These are source handles
- for (String hid : keyset) {
- srchandlecounter++;
-
- // Do we already know this handle points to nowhere?
- if (nonExistingHandles.contains(hid)) {
- sourcesToRemove.add(hid);
- } else if (!isPhantomHandle(hid)) {
- // We better check if it actually exists
- IProgramElement existingElement = hierarchy.getElement(hid);
- if (dumpDeltaProcessing) {
- fw.write("Looking for handle [" + hid + "] in model, found: " + existingElement + "\n");
- }
- // Did we find it?
- if (existingElement == null) {
- // No, so delete this relationship
- sourcesToRemove.add(hid);
- nonExistingHandles.add(hid); // Speed up a bit you swine
- } else {
- // Ok, so the source is valid, what about the targets?
- List<IRelationship> relationships = mapper.get(hid);
- List<IRelationship> relationshipsToRemove = new ArrayList<IRelationship>();
- // Iterate through the relationships against this source
- // handle
- for (Iterator<IRelationship> reliter = relationships.iterator(); reliter.hasNext();) {
- IRelationship rel = reliter.next();
- List<String> targets = rel.getTargets();
- List<String> targetsToRemove = new ArrayList<String>();
-
- // Iterate through the targets for this relationship
- for (Iterator<String> targetIter = targets.iterator(); targetIter.hasNext();) {
- String targethid = targetIter.next();
- tgthandlecounter++;
- // Do we already know it doesn't exist?
- if (nonExistingHandles.contains(targethid)) {
- if (dumpDeltaProcessing) {
- fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel[" + rel.getName()
- + "] does not exist\n");
- }
- targetsToRemove.add(targethid);
- } else if (!isPhantomHandle(targethid)) {
- // We better check
- IProgramElement existingTarget = hierarchy.getElement(targethid);
- if (existingTarget == null) {
- if (dumpDeltaProcessing) {
- fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel["
- + rel.getName() + "] does not exist\n");
- }
- targetsToRemove.add(targethid);
- nonExistingHandles.add(targethid);
- }
- }
- }
-
- // Do we have some targets that need removing?
- if (targetsToRemove.size() != 0) {
- // Are we removing *all* of the targets for this
- // relationship (i.e. removing the relationship)
- if (targetsToRemove.size() == targets.size()) {
- if (dumpDeltaProcessing) {
- fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
- + "]: removing it\n");
- }
- relationshipsToRemove.add(rel);
- } else {
- // Remove all the targets that are no longer
- // valid
- for (String togo : targetsToRemove) {
- targets.remove(togo);
- }
- // Should have already been caught above,
- // but lets double check ...
- if (targets.size() == 0) {
- if (dumpDeltaProcessing) {
- fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
- + "]: removing it\n");
- }
- relationshipsToRemove.add(rel); // TODO
- // Should
- // only
- // remove
- // this
- // relationship
- // for
- // the
- // srchid
- // ?
- }
- }
- }
- }
- // Now, were any relationships emptied during that
- // processing and so need removing for this source
- // handle
- if (relationshipsToRemove.size() > 0) {
- // Are we removing *all* of the relationships for
- // this source handle?
- if (relationshipsToRemove.size() == relationships.size()) {
- // We know they are all going to go, so just
- // delete the source handle.
- sourcesToRemove.add(hid);
- } else {
- // MEMORY LEAK - we don't remove the
- // relationships !!
- for (int i = 0; i < relationshipsToRemove.size(); i++) {
- IRelationship irel = relationshipsToRemove.get(i);
- verifyAssumption(mapper.remove(hid, irel), "Failed to remove relationship " + irel.getName()
- + " for shid " + hid);
- }
- List<IRelationship> rels = mapper.get(hid);
- if (rels == null || rels.size() == 0) {
- sourcesToRemove.add(hid);
- }
- }
- }
- }
- }
- }
- // Remove sources that have no valid relationships any more
- for (Iterator<String> srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
- String hid = srciter.next();
- mapper.removeAll(hid);
- IProgramElement ipe = hierarchy.getElement(hid);
- if (ipe != null) {
- // If the relationship was hanging off a 'code' node, delete
- // it.
- if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
- // System.err.println("Deleting code node");
- removeSingleNode(ipe);
- }
- }
- }
- } catch (IOException ioe) {
- System.err.println("Failed to repair relationships:");
- ioe.printStackTrace();
- }
- }
-
- /**
- * Removes a specified program element from the structure model. We go to the parent of the program element, ask for all its
- * children and remove the node we want to delete from the list of children.
- */
- private void removeSingleNode(IProgramElement progElem) {
- if (progElem == null) {
- throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
- }
- boolean deleteOK = false;
- IProgramElement parent = progElem.getParent();
- List<IProgramElement> kids = parent.getChildren();
- for (int i = 0, max = kids.size(); i < max; i++) {
- if (kids.get(i).equals(progElem)) {
- kids.remove(i);
- deleteOK = true;
- break;
- }
- }
- if (!deleteOK) {
- System.err.println("unexpectedly failed to delete node from model. hid=" + progElem.getHandleIdentifier());
- }
- }
-
- /**
- * Removes a specified program element from the structure model. Two processing stages:
- * <p>
- * 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
- * list of children.
- * <p>
- * 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
- * node, we delete it too.
- */
- private void removeNode(IProgramElement progElem) {
-
- // StringBuffer flightrecorder = new StringBuffer();
- try {
- // flightrecorder.append("In removeNode, about to chuck away: "+
- // progElem+"\n");
- if (progElem == null) {
- throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
- }
- // boolean deleteOK = false;
- IProgramElement parent = progElem.getParent();
- // flightrecorder.append("Parent of it is "+parent+"\n");
- List<IProgramElement> kids = parent.getChildren();
- // flightrecorder.append("Which has "+kids.size()+" kids\n");
- for (int i = 0; i < kids.size(); i++) {
- // flightrecorder.append("Comparing with "+kids.get(i)+"\n");
- if (kids.get(i).equals(progElem)) {
- kids.remove(i);
- // flightrecorder.append("Removing it\n");
- // deleteOK=true;
- break;
- }
- }
- // verifyAssumption(deleteOK,flightrecorder.toString());
- // Are there any kids left for this node?
- if (parent.getChildren().size() == 0
- && parent.getParent() != null
- && (parent.getKind().equals(IProgramElement.Kind.CODE) || parent.getKind().equals(IProgramElement.Kind.PACKAGE))) {
- // 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
- // We should trim if it
- // System.err.println("Deleting parent:"+parent);
- removeNode(parent);
- }
- } catch (NullPointerException npe) {
- // Occurred when commenting out other 2 ras classes in wsif??
- // reproducable?
- // System.err.println(flightrecorder.toString());
- npe.printStackTrace();
- }
- }
-
- public static void verifyAssumption(boolean b, String info) {
- if (!b) {
- System.err.println("=========== ASSERTION IS NOT TRUE =========v");
- System.err.println(info);
- Thread.dumpStack();
- System.err.println("=========== ASSERTION IS NOT TRUE =========^");
- throw new RuntimeException("Assertion is false");
- }
- }
-
- public static void verifyAssumption(boolean b) {
- if (!b) {
- Thread.dumpStack();
- throw new RuntimeException("Assertion is false");
- }
- }
-
- // ===================== DELTA PROCESSING CODE ============== end
- // ==========//
-
- /**
- * A ModelInfo object captures basic information about the structure model. It is used for testing and producing debug info.
- */
- public static class ModelInfo {
- private final Hashtable<String, Integer> nodeTypeCount = new Hashtable<String, Integer>();
- private final Properties extraProperties = new Properties();
-
- private ModelInfo(IHierarchy hierarchy, IRelationshipMap relationshipMap) {
- IProgramElement ipe = hierarchy.getRoot();
- walkModel(ipe);
- recordStat("FileMapSize", new Integer(hierarchy.getFileMapEntrySet().size()).toString());
- recordStat("RelationshipMapSize", new Integer(relationshipMap.getEntries().size()).toString());
- }
-
- private void walkModel(IProgramElement ipe) {
- countNode(ipe);
- for (IProgramElement child : ipe.getChildren()) {
- walkModel(child);
- }
- }
-
- private void countNode(IProgramElement ipe) {
- String node = ipe.getKind().toString();
- Integer ctr = nodeTypeCount.get(node);
- if (ctr == null) {
- nodeTypeCount.put(node, new Integer(1));
- } else {
- ctr = new Integer(ctr.intValue() + 1);
- nodeTypeCount.put(node, ctr);
- }
- }
-
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append("Model node summary:\n");
- Enumeration<String> nodeKeys = nodeTypeCount.keys();
- while (nodeKeys.hasMoreElements()) {
- String key = nodeKeys.nextElement();
- Integer ct = nodeTypeCount.get(key);
- sb.append(key + "=" + ct + "\n");
- }
- sb.append("Model stats:\n");
- Enumeration<Object> ks = extraProperties.keys();
- while (ks.hasMoreElements()) {
- String k = (String) ks.nextElement();
- String v = extraProperties.getProperty(k);
- sb.append(k + "=" + v + "\n");
- }
- return sb.toString();
- }
-
- public Properties getProperties() {
- Properties p = new Properties();
- for (Map.Entry<String, Integer> entry : nodeTypeCount.entrySet()) {
- p.setProperty(entry.getKey(), entry.getValue().toString());
- }
- p.putAll(extraProperties);
- return p;
- }
-
- public void recordStat(String string, String string2) {
- extraProperties.setProperty(string, string2);
- }
-
- }
-
- public ModelInfo summarizeModel() {
- return new ModelInfo(getHierarchy(), getRelationshipMap());
- }
-
- /**
- * Set to indicate whether we are currently building a structure model, should be set up front.
- */
- // public static void setCreatingModel(boolean b) {
- // creatingModel = b;
- // }
- //
- // /**
- // * returns true if we are currently generating a structure model, enables guarding of expensive operations on an empty/null
- // * model.
- // */
- // public static boolean isCreatingModel() {
- // return creatingModel;
- // }
- public static void setCompletingTypeBindings(boolean b) {
- completingTypeBindings = b;
- }
-
- public static boolean isCompletingTypeBindings() {
- return completingTypeBindings;
- }
-
- // public void setRelationshipMap(IRelationshipMap irm) {
- // mapper = irm;
- // }
- //
- // public void setHierarchy(IHierarchy ih) {
- // hierarchy = ih;
- // }
-
- public void resetDeltaProcessing() {
- lastBuildChanges.clear();
- aspectsWeavingInLastBuild.clear();
- }
-
- /**
- * @return the Set of files for which the structure model was modified (they may have been removed or otherwise rebuilt). Set is
- * empty for a full build.
- */
- public Set<File> getModelChangesOnLastBuild() {
- return lastBuildChanges;
- }
-
- /**
- * @return the Set of aspects that wove files on the last build (either incremental or full build)
- */
- public Set<File> getAspectsWeavingFilesOnLastBuild() {
- return aspectsWeavingInLastBuild;
- }
-
- public void addAspectInEffectThisBuild(File f) {
- aspectsWeavingInLastBuild.add(f);
- }
-
- public static void setLastActiveStructureModel(AsmManager structureModel) {
- if (recordingLastActiveStructureModel) {
- lastActiveStructureModel = structureModel;
- }
- }
-
- public String getHandleElementForInpath(String binaryPath) {
- return inpathMap.get(new File(binaryPath));
- }
- }
|