001: package tide.classsyntax;
002:
003: import snow.utils.gui.*;
004: import snow.utils.storage.FileUtils;
005: import tide.project.*;
006: import snow.texteditor.*;
007: import tide.editor.MainEditorFrame;
008:
009: import java.util.*;
010: import java.io.*;
011: import java.util.jar.*;
012: import java.util.zip.*;
013: import java.lang.reflect.*;
014:
015: /** Loads single classes.
016: * TODO: catch UnsupportedClassVersionError and show them in the tide tab to warn the user that he should
017: * run tide with a jvm ov version greater or equal as the one used to develop.
018: */
019: public final class SingleClassLoader extends ClassLoader {
020: final private ClassFilesManager cfm;
021: //final WeakHashMap<String, Class> alreadyLoaded = new WeakHashMap<String, Class>();
022: final Map<String, Class> alreadyLoaded = new HashMap<String, Class>(); // Weak are not good here, => duplicate class def otherwise !!!
023:
024: private SingleClassLoader(ClassFilesManager cfm) {
025: this (cfm, true);
026: }
027:
028: private SingleClassLoader(ClassFilesManager cfm, boolean enableDebug) {
029: this .enableDebug = enableDebug;
030: this .cfm = cfm;
031: this .clearAssertionStatus();
032:
033: debugOut("\n======= new SingleClassLoader instance created ======");
034: }
035:
036: boolean enableDebug = false;
037:
038: private void debugOut(String line) {
039: if (enableDebug) {
040: MainEditorFrame.debugOut(line);
041: }
042: }
043:
044: /** Call this when no more used.
045: */
046: public void terminate() {
047: //debugOut("Terminate SCL");
048: alreadyLoaded.clear();
049: }
050:
051: /** Recreates a new class loader. Call this when classes changed.
052: * can be shared until next compilation...
053: */
054: public static SingleClassLoader createSingleClassLoader() {
055: return createSingleClassLoader(MainEditorFrame.debug);
056: }
057:
058: /** Recreates a new class loader. Call this when classes changed.
059: * can be shared until next compilation...
060: */
061: public static SingleClassLoader createSingleClassLoader(
062: boolean debugOut) {
063: ClassFilesManager cfm = MainEditorFrame.instance
064: .getActualProject().getClassFilesManager();
065: SingleClassLoader scl = new SingleClassLoader(cfm, debugOut);
066: return scl;
067: }
068:
069: /** Loads the class with the given name.
070: * DIFFICULT: must load 1.5 classes when running under 1.6 (and inverse ??)
071: * only "good" solution: take asm to inspect classes.
072: *
073: * Actually: the IDE must have a class version >= of the runned project classes !
074: */
075: @Override
076: public Class findClass(String name) {
077: if (name == null)
078: throw new IllegalArgumentException("null name passed");
079: //System.out.println("SCL.findClass "+name);
080: // without this, we receive sometimes DuplicateClassDef errors !
081: if (alreadyLoaded.containsKey(name)) {
082: //debugOut("SingleClassLoader: found already loaded class "+name);
083: return alreadyLoaded.get(name);
084: }
085:
086: //System.out.println("SingleClassLoader: Loading class "+name);
087: try {
088: // exact matching here
089: final ProjClass pc = cfm.getClassExact(name);
090:
091: if (pc == null) {
092: // new Throwable("Can't find1 class "+name).printStackTrace(); //debug
093: debugOut("SCL: Can't find1 class " + name);
094: return null;
095: }
096:
097: //try first system load...
098:
099: if (true || name.startsWith("java.")
100: || name.startsWith("javax.")
101: || name.startsWith("com.sun.") // [June2007]
102: || name.startsWith("sun.")) {
103: // problem: if we don't include "javax.*" we receive verify errors because of mixed versions, one 1.5, one 1.6
104: //
105:
106: // java 1.6
107: // problem: "java.*" classes are not accepted ! (changing name is not a solution...)
108: // tide> java.lang.SecurityException: Prohibited package name: java.lang
109: // tide> at java.lang.ClassLoader.preDefineClass(ClassLoader.java:479)
110:
111: // Class c = defineClass(null, b, 0, b.length); // must be null !!
112: // return c;
113: //classLoader.
114: //Utils.lookAtSource(name); // signatures, ...
115:
116: try {
117: Class c = getSystemClassLoader().loadClass(name); // load (find is protected)
118: // [June2007]: don't store the ones loaded using system...
119: //alreadyLoaded.put(c.getName(), c);
120: return c;
121: } catch (Exception e) {
122: debugOut("cannot system load1 " + name);
123: } catch (Error e) {
124: debugOut("cannot system load2 " + name);
125: }
126: }
127:
128: // try direct load
129:
130: try {
131: byte[] b = getByteContent(pc.getClassContent());
132: Class c = defineClass(null, b, 0, b.length); // why not also null instead of "name".
133: // sometimes throw java.lang.LinkageError: duplicate class definition: tide/editor/OutputPanels
134: alreadyLoaded.put(c.getName(), c);
135: return c;
136: } catch (Exception ex3) {
137: /* // [Sep2006]: yet another try !
138: Class c = getSystemClassLoader().loadClass(name); // load (find is protected)
139: alreadyLoaded.put(c.getName(), c);
140: return c; */
141: throw ex3;
142: }
143:
144: } catch (Error e) // really occurs: LinkageError, duplicate class def
145: {
146: //e.printStackTrace();
147: debugOut("Can't find2 class " + name + ": "
148: + e.getMessage());
149: return null;
150: } catch (Exception e) {
151: //e.printStackTrace();
152: debugOut("Can't find3 class " + name + ": "
153: + e.getMessage());
154: return null;
155: }
156: }
157:
158: public static byte[] getByteContent(InputStream fis)
159: throws Exception {
160: ByteArrayOutputStream baos = new ByteArrayOutputStream();
161: try {
162: byte[] buf = new byte[256];
163: int read = -1;
164: while ((read = fis.read(buf)) != -1) {
165: baos.write(buf, 0, read);
166: }
167: baos.flush();
168: baos.close();
169: return baos.toByteArray();
170: } catch (Exception e) {
171: throw e;
172: } finally {
173: FileUtils.closeIgnoringExceptions(fis);
174: }
175: }
176:
177: public ClassLoader getClassLoader() {
178: return null;
179: }
180:
181: /*test public static void main(String[] args)
182: {
183: ClassFilesManager cf = new ClassFilesManager(new Vector<File>(), new File("c:/classes/tide"));
184: SingleClassLoader scl = new SingleClassLoader(cf);
185: Class c = scl.findClass("tide.classsyntax.SingleClassLoader");
186: System.out.println("scl: "+c);
187: }*/
188:
189: }
|