001: package tide.bytecode;
002:
003: import java.io.*;
004: import java.util.*;
005: import java.lang.reflect.Member;
006: import snow.utils.storage.FileUtils;
007: import tide.sources.LibFileItem;
008: import tide.sources.FileItem;
009: import tide.sources.TypeLocator;
010: import tide.editor.MainEditorFrame;
011:
012: /** Called from various places, caches decompiled (disassembled) class contents.
013: * Caches should be cleared when recompiling project sources and libs changes.
014: * Decompiled classes can be used to fetch method and constructor parameter names,
015: * but only if the lib was compiled with "-g". RT.jar
016: * 1.6.0-rc-b104 NO
017: *
018: * => use javadoc if available...
019: */
020: public final class DecompileManager {
021: static DecompileManager instance = null;
022: Map<String, DecompiledClass> decompiledClasses = new WeakHashMap<String, DecompiledClass>();
023: // useful to delete only them...
024: Set<String> foundInSource = new HashSet<String>();
025:
026: Set<String> knownLibsWithNamesInBytecode = new HashSet<String>();
027: Set<String> knownLibsWithoutNamesInBytecode = new HashSet<String>();
028:
029: boolean hasSourcesNamesInBytecode = true;//todo
030:
031: private DecompileManager() {
032: }
033:
034: public static DecompileManager getInstance() {
035: if (instance == null) {
036: instance = new DecompileManager();
037: }
038: return instance;
039: }
040:
041: /** Should be called at each change in the project classes...
042: */
043: public void clear() {
044: decompiledClasses.clear();
045: knownLibsWithNamesInBytecode.clear();
046: knownLibsWithoutNamesInBytecode.clear();
047: }
048:
049: /** Removes only the specified
050: */
051: public void remove(String javaName) {
052: decompiledClasses.remove(javaName);
053: }
054:
055: /** Remove all cached DecompiledClass of sources in the project(not in the libs)
056: * this must be called at each change in the project classes (not libs).
057: */
058: public void removeDecompForSources() {
059: for (String si : foundInSource) {
060: decompiledClasses.remove(si);
061: }
062: foundInSource.clear();
063: }
064:
065: /** Used to inject argument names in the completion.
066: */
067: public DecompiledClass.TMember getDecompiledMember(Member member,
068: boolean nullIfNoNamesInBytecode, boolean withbytecode) {
069: String jn = member.getDeclaringClass().getName();
070: DecompiledClass dc = getDecompiledType(jn,
071: nullIfNoNamesInBytecode, withbytecode);
072: if (dc == null)
073: return null;
074: return dc.getMember(member);
075: }
076:
077: @edu.umd.cs.findbugs.annotations.CheckForNull
078: public DecompiledClass getDecompiledType(String jn,
079: boolean nullIfNoNamesInBytecode, boolean withbytecode) {
080: DecompiledClass dc = decompiledClasses.get(jn);
081: if (dc != null) {
082: return dc;
083: }
084:
085: FileItem fileItem = TypeLocator.locateQuick(jn);
086: if (fileItem != null) {
087: if (fileItem instanceof LibFileItem) {
088: LibFileItem lfi = (LibFileItem) fileItem;
089: if (nullIfNoNamesInBytecode) {
090: if (knownLibsWithoutNamesInBytecode.contains(lfi
091: .getRootArchiveName()))
092: return null;
093: }
094:
095: try {
096: InputStream is = lfi.getRAWContentInputStream();
097: // [May] use system temp (thanks Mike K.)
098: final File temp = new File(System
099: .getProperty("java.io.tmpdir"),
100: "Temp.class");
101: temp.deleteOnExit();
102:
103: FileUtils.writeToFile(is, temp);
104:
105: dc = new DecompiledClass("Temp", temp
106: .getParentFile(), MainEditorFrame.instance
107: .getActualProject().getJavap_TOOL(),
108: withbytecode);
109: decompiledClasses.put(jn, dc);
110: } catch (Exception e) {
111: e.printStackTrace();
112: }
113:
114: // remember lib type
115: if (dc != null) {
116: String arn = lfi.getRootArchiveName();
117: if (dc.hasAnyDefaultNamedArguments) {
118: knownLibsWithoutNamesInBytecode.add(arn);
119: } else {
120: knownLibsWithNamesInBytecode.add(arn);
121: }
122: }
123: }
124: } else {
125: MainEditorFrame
126: .debugOut("DecompileManager: no type found for "
127: + jn);
128: }
129:
130: if (dc == null) {
131: if (MainEditorFrame.instance.getActualProject()
132: .getClasses_Home().exists()) {
133: try {
134: // for the project own classes
135: dc = new DecompiledClass(jn,
136: MainEditorFrame.instance.getActualProject()
137: .getClasses_Home(),
138: MainEditorFrame.instance.getActualProject()
139: .getJavap_TOOL(), withbytecode);
140: decompiledClasses.put(jn, dc);
141: foundInSource.add(jn);
142: } catch (Exception e) {
143: MainEditorFrame.debugOut(e);
144: }
145: }
146:
147: if (dc == null
148: && MainEditorFrame.instance.getActualProject()
149: .getClassesCacheTempFolderForCompletion()
150: .exists()) {
151: // second chance
152: try {
153: // for the project own classes CACHE [March2008]
154: dc = new DecompiledClass(
155: jn,
156: MainEditorFrame.instance
157: .getActualProject()
158: .getClassesCacheTempFolderForCompletion(),
159: MainEditorFrame.instance.getActualProject()
160: .getJavap_TOOL(), withbytecode);
161: decompiledClasses.put(jn, dc);
162: foundInSource.add(jn);
163: } catch (Exception e2) {
164: MainEditorFrame.debugOut(e2);
165: }
166: }
167: }
168:
169: if (dc == null) {
170: MainEditorFrame.debugOut("DecompiledClass not found for "
171: + jn);
172: return null;
173: }
174: return dc;
175: }
176: }
|