Index: nb_all/core/build.xml =================================================================== RCS file: /cvs/core/build.xml,v retrieving revision 1.54 diff -u -r1.54 build.xml --- nb_all/core/build.xml 29 Jul 2002 10:11:08 -0000 1.54 +++ nb_all/core/build.xml 13 Aug 2002 23:37:51 -0000 @@ -48,18 +48,35 @@ + + + + + + + + - - + + + + + + /** Creates new JarClassLoader */ + public JarClassLoader (List files, ClassLoader[] parents) { + super(parents); + + sources = new Source[files.size()]; + try { + int i=0; + for (Iterator it = files.iterator(); it.hasNext(); i++ ) { + Object act = it.next(); + if (act instanceof File) { + sources[i] = new DirSource((File)act); + } else { + sources[i] = new JarSource((JarFile)act); + } + } + } catch (MalformedURLException exc) { + throw new IllegalArgumentException(exc.getMessage()); + } + + } + + /** Allows to specify the right permissions, OneModuleClassLoader does it differently. + */ + protected PermissionCollection getPermissions( CodeSource cs ) { + return Policy.getPolicy().getPermissions(cs); + } + + + protected Package definePackage(String name, Manifest man, URL url) + throws IllegalArgumentException + { + if (man == null ) { + return definePackage(name, null, null, null, null, null, null, null); + } + + String path = name.replace('.', '/').concat("/"); // NOI18N + Attributes spec = man.getAttributes(path); + Attributes main = man.getMainAttributes(); + + String specTitle = getAttr(spec, main, Name.SPECIFICATION_TITLE); + String implTitle = getAttr(spec, main, Name.IMPLEMENTATION_TITLE); + String specVersion = getAttr(spec, main, Name.SPECIFICATION_VERSION); + String implVersion = getAttr(spec, main, Name.IMPLEMENTATION_VERSION); + String specVendor = getAttr(spec, main, Name.SPECIFICATION_VENDOR); + String implVendor = getAttr(spec, main, Name.IMPLEMENTATION_VENDOR); + String sealed = getAttr(spec, main, Name.SEALED); + + URL sealBase = "true".equalsIgnoreCase(sealed) ? url : null; // NOI18N + return definePackage(name, specTitle, specVersion, specVendor, + implTitle, implVersion, implVendor, sealBase); + } + + private static String getAttr(Attributes spec, Attributes main, Name name) { + String val = null; + if (spec != null) val = spec.getValue (name); + if (val == null && main != null) val = main.getValue (name); + return val; + } + + protected Class simpleFindClass(String name, String path) { + // look up the Sources and return a class based on their content + for( int i=0; i + try { + for (int i = 0; i < sources.length; i++) { + if (sources[i] instanceof JarSource) { + JarFile origJar = ((JarSource)sources[i]).getJarFile(); + File orig = new File(origJar.getName()); + if (!orig.isFile()) { + // Can happen when a test module is deleted: + // the physical JAR has already been deleted + // when the module was disabled. In this case it + // is possible that a classloader request for something + // in the JAR could still come in. Does it matter? + // See comment in Module.cleanup. + continue; + } + String name = orig.getName(); + String prefix, suffix; + int idx = name.lastIndexOf('.'); + if (idx == -1) { + prefix = name; + suffix = null; + } else { + prefix = name.substring(0, idx); + suffix = name.substring(idx); + } + while (prefix.length() < 3) prefix += "x"; // NOI18N + File temp = File.createTempFile(prefix, suffix); + temp.deleteOnExit(); + InputStream is = new FileInputStream(orig); + try { + OutputStream os = new FileOutputStream(temp); + try { + byte[] buf = new byte[4096]; + int j; + while ((j = is.read(buf)) != -1) { + os.write(buf, 0, j); + } + } finally { + os.close(); + } + } finally { + is.close(); + } + // Don't use OPEN_DELETE even though it sounds like a good idea. + // Can cause real problems under 1.4; see Module.java. + JarFile tempJar = new JarFile(temp); + origJar.close(); + forceRelease(orig); + deadJars.add(tempJar); + sources[i] = new JarSource(tempJar); + log("#21114: replacing " + orig + " with " + temp); + } + } + } catch (IOException ioe) { + JarClassLoader.notify(0, ioe); + } + } + + /** Release jar: locks when the classloader is shut down. + * Should help reloading modules with changed resources. + */ + public void destroy() { + super.destroy(); + for (int i = 0; i < sources.length; i++) { + if (sources[i] instanceof JarSource) { + JarFile j = ((JarSource)sources[i]).getJarFile(); + File f = new File(j.getName()); + forceRelease(f); + } + } + } + + /** Delete any temporary JARs we were holding on to. + * Also close any other JARs in our list. + */ + protected void finalize() throws Throwable { + super.finalize(); + for (int i = 0; i < sources.length; i++) { + if (sources[i] instanceof JarSource) { + JarFile j = ((JarSource)sources[i]).getJarFile(); + File f = new File(j.getName()); + j.close(); + forceRelease(f); + if (deadJars != null && deadJars.contains(j)) { + log("#21114: closing and deleting temporary JAR " + f); + if (f.isFile() && !f.delete()) { + log("(but failed to delete it)"); + } + } + } + } + } + + /** Make sure the Java runtime's jar: URL cache is not holding + * onto the specified file. + * Workaround for JDK bug #4646668. + */ + private static void forceRelease(File f) { + if (fileCache == null || factory == null) return; + try { + synchronized (factory) { + Iterator it = fileCache.values().iterator(); + while (it.hasNext()) { + JarFile j = (JarFile)it.next(); + if (f.equals(new File(j.getName()))) { + j.close(); + it.remove(); + log("Removing jar: cache for " + f + " as workaround for JDK #4646668"); + } + } + } + } catch (Exception e) { + JarClassLoader.annotate(e, 0, "Could not remove jar: cache for " + f, null, null, null); + JarClassLoader.notify(0, e); + } + } + private static Object factory = null; + private static HashMap fileCache = null; + static { + try { + Class juc = Class.forName("sun.net.www.protocol.jar.JarURLConnection"); // NOI18N + Field factoryF = juc.getDeclaredField("factory"); // NOI18N + factoryF.setAccessible(true); + factory = factoryF.get(null); + Class jff = Class.forName("sun.net.www.protocol.jar.JarFileFactory"); // NOI18N + if (!jff.isInstance(factory)) throw new ClassCastException(factory.getClass().getName()); + Field fileCacheF = jff.getDeclaredField("fileCache"); // NOI18N + fileCacheF.setAccessible(true); + if (Modifier.isStatic(fileCacheF.getModifiers())) { + // JDK 1.3.1 or 1.4 seems to have it static. + fileCache = (HashMap)fileCacheF.get(null); + } else { + // But in 1.3.0 it appears to be an instance var. + fileCache = (HashMap)fileCacheF.get(factory); + } + log("Workaround for JDK #4646668 active as part of IZ #21114"); + } catch (Exception e) { + JarClassLoader.annotate(e, 0, "Workaround for JDK #4646668 as part of IZ #21114 failed", null, null, null); + JarClassLoader.notify(0, e); + } + } + + abstract class Source { + private URL url; + private ProtectionDomain pd; + + public Source(URL url) { + this.url = url; + CodeSource cs = new CodeSource(url, new Certificate[0]); + pd = new ProtectionDomain(cs, getPermissions(cs)); + } + + public final URL getURL() { + return url; + } + + public final ProtectionDomain getProtectionDomain() { + return pd; + } + + public final URL getResource(String name) { + try { + return doGetResource(name); + } catch (MalformedURLException e) { + log(e.toString()); + } + return null; + } + + protected abstract URL doGetResource(String name) throws MalformedURLException; + + public final byte[] getClassData(String name, String path) { + try { + return readClass(name, path); + } catch (IOException e) { + log(e.toString()); + } + return null; + } + + protected abstract byte[] readClass(String name, String path) throws IOException; + + public Manifest getManifest() { + return null; + } + } + + class JarSource extends Source { + JarFile src; + + public JarSource(JarFile file) throws MalformedURLException { + super(new URL("file:" + file.getName())); + src = file; + } + + public Manifest getManifest() { + try { + return src.getManifest(); + } catch (IOException e) { + return null; + } + } + + JarFile getJarFile() { + return src; + } + + protected URL doGetResource(String name) throws MalformedURLException { + ZipEntry ze = src.getEntry(name); + return ze == null ? null : new URL("jar:file:" + src.getName() + "!/" + ze.getName()); // NOI18N + } + + protected byte[] readClass(String name, String path) throws IOException { + ZipEntry ze = src.getEntry(path); + if (ze == null) return null; + + int len = (int)ze.getSize(); + byte[] data = new byte[len]; + InputStream is = src.getInputStream(ze); + int count = 0; + while (count < len) { + count += is.read(data, count, len-count); + } + return data; + } + } + + class DirSource extends Source { + File dir; + + public DirSource(File file) throws MalformedURLException { + super(file.toURL()); + dir = file; + } + + protected URL doGetResource(String name) throws MalformedURLException { + File resFile = new File(dir, name); + return resFile.exists() ? resFile.toURL() : null; + } + + protected byte[] readClass(String name, String path) throws IOException { + File clsFile = new File(dir, path.replace('/', File.separatorChar)); + if (!clsFile.exists()) return null; + + int len = (int)clsFile.length(); + byte[] data = new byte[len]; + InputStream is = new FileInputStream(clsFile); + int count = 0; + while (count < len) { + count += is.read(data, count, len-count); + } + return data; + } + + } + + + // + // ErrorManager's methods + // + + static void log (String msg) { + System.err.println(msg); + } + + static Throwable annotate ( + Throwable t, int x, String s, Object o1, Object o2, Object o3 + ) { + System.err.println("annotated: " + t.getMessage () + " - " + s); + return t; + } + + static void notify (int x, Throwable t) { + t.printStackTrace(); + } +} Index: nb_all/core/src/org/netbeans/Main.java =================================================================== RCS file: /cvs/core/src/org/netbeans/Main.java,v retrieving revision 1.14 diff -u -r1.14 Main.java --- nb_all/core/src/org/netbeans/Main.java 29 Jul 2002 10:11:12 -0000 1.14 +++ nb_all/core/src/org/netbeans/Main.java 13 Aug 2002 23:37:52 -0000 @@ -13,6 +13,13 @@ package org.netbeans; +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.lang.reflect.Method; +import java.util.Collection; import org.netbeans.core.perftool.StartLog; /** The Corona's main class. Starts up the IDE. @@ -23,8 +30,78 @@ /** Starts the IDE. * @param args the command line arguments */ - public static void main (String args[]) { - StartLog.logStart( "Forwarding to topThreadGroup" ); // NOI18N - org.netbeans.core.Main.start(args); + public static void main (String args[]) throws Exception { + ArrayList list = new ArrayList (); + + String user = System.getProperty("netbeans.user"); // NOI18N + if (user != null) { + build_cp (new File (user), list); + } + + String home = System.getProperty ("netbeans.home"); // NOI18N + if (home != null) { + build_cp (new File (home), list); + } + + java.util.ListIterator it = list.listIterator(); + while (it.hasNext()) { + File f = (File)it.next(); + it.set(new java.util.jar.JarFile (f)); + } + + + ClassLoader loader = new JarClassLoader (list, new ClassLoader[] { + Main.class.getClassLoader() + }); + + String className = System.getProperty( + "netbeans.mainclass", "org.netbeans.core.Main" // NOI18N + ); + + Class c = loader.loadClass(className); + Method m = c.getMethod ("main", new Class[] { String[].class }); // NOI18N + + Thread.currentThread().setContextClassLoader (loader); + m.invoke (null, new Object[] { args }); + } + + + private static void append_jars_to_cp (File dir, Collection toAdd) { + /* + for ex in jar zip ; do + if [ "`echo "${dir}"/*.$ex`" != "${dir}/*.$ex" ] ; then + for x in "${dir}"/*.$ex ; do + # XXX also filter out lib/locale/updater*.jar to make Japanese startup faster + # (and put it back in below when building ${updatercp} + if [ "$x" != "$idehome/lib/updater.jar" -a "$x" != "$userdir/lib/updater.jar" ] ; then + if [ ! -z "$cp" ] ; then cp="$cp:" ; fi + cp="$cp$x" + fi + done + fi + done + */ + + if (!dir.isDirectory()) return; + + File[] arr = dir.listFiles(); + for (int i = 0; i < arr.length; i++) { + String n = arr[i].getName (); + if (n.endsWith("jar") || n.endsWith ("zip")) { // NOI18N + toAdd.add (arr[i]); + } + } + } + + + private static void build_cp(File base, Collection toAdd) { + append_jars_to_cp (new File (base, "lib/patches/locale"), toAdd); + append_jars_to_cp (new File (base, "lib/patches"), toAdd); + + append_jars_to_cp (new File (base, "lib/locale"), toAdd); + append_jars_to_cp (new File (base, "lib"), toAdd); + + //append_jars_to_cp (new File (base, "lib/ext/locale"), toAdd); + //append_jars_to_cp (new File (base, "lib/ext"), toAdd); } } Index: nb_all/core/src/org/netbeans/PatchByteCode.java =================================================================== RCS file: nb_all/core/src/org/netbeans/PatchByteCode.java diff -N nb_all/core/src/org/netbeans/PatchByteCode.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/core/src/org/netbeans/PatchByteCode.java 13 Aug 2002 23:37:52 -0000 @@ -0,0 +1,805 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans; + +import java.io.*; +import java.util.HashMap; + +/** Class that can enhance bytecode with information about alternative + * superclass and access modifiers. It can also extract this information + * later when the class is about to be loaded into the VM. + *

+ * The additional information is added to attributes of the classfile (global attributes + * and also member attributes) and as such the class remain compatible and + * understandable for any VM. But if loaded by classloader that before defining + * the class invokes: + *

+ *  byte[] arr = ...;
+ *  arr = PatchByteCode.patch (arr); 
+ * 
+ * The class is altered in its superclass and/or access modifiers. + *

+ * The patching mechanism uses two attributes. ATTR_SUPERCLASS can be just + * in global attributes pool (and only once), is of length 2 and contains index + * into constant pool that contains definition of a Class that should become + * the alternate superclass. Attribute ATTR_MEMBER can appear in global + * attribute set and also in set of each member (field or method). It is of + * length 2 and contains alternate value for access flags of the class or of + * the field. + *

+ * For purposes for speed, each patched class file has to end with bytes "nb". + * This is achieved by finishing the patching process by adding third attribute + * "org.netbeans.enhanced" with value "nb". As such the PatchByteCode.patch + * can quickly check the byte array and process just those that need processing. + * + * @author Jaroslav Tulach + */ +public final class PatchByteCode { + private static final String ATTR_SUPERCLASS = "org.netbeans.superclass"; // NOI18N + private static final byte[] BYTE_SUPERCLASS; + static { + try { + BYTE_SUPERCLASS = ATTR_SUPERCLASS.getBytes("utf-8"); // NOI18N + } catch (java.io.UnsupportedEncodingException ex) { + throw new IllegalStateException (ex.getMessage()); + } + } + private static final String ATTR_MEMBER = "org.netbeans.member"; // NOI18N + private static final byte[] BYTE_MEMBER; + static { + try { + BYTE_MEMBER = ATTR_MEMBER.getBytes("utf-8"); // NOI18N + } catch (java.io.UnsupportedEncodingException ex) { + throw new IllegalStateException (ex.getMessage()); + } + } + + private static final String ATTR_INIT = ""; // NOI18N + private static final byte[] BYTE_INIT; + static { + try { + BYTE_INIT = ATTR_INIT.getBytes("utf-8"); // NOI18N + } catch (java.io.UnsupportedEncodingException ex) { + throw new IllegalStateException (ex.getMessage()); + } + } + + private static final String ATTR_INIT_TYPE = "()V"; // NOI18N + private static final byte[] BYTE_INIT_TYPE; + static { + try { + BYTE_INIT_TYPE = ATTR_INIT_TYPE.getBytes("utf-8"); // NOI18N + } catch (java.io.UnsupportedEncodingException ex) { + throw new IllegalStateException (ex.getMessage()); + } + } + + private byte[] arr; + + private int cpCount; + private int cpEnd; + private int atCount; + private int atEnd; + + /** the index of a string that matches the searched attribute */ + private int superClassNameIndex; + /** the possiton of found attribute */ + private int superClassNameAttr; + /** the index of a string to patch members of a field */ + private int memberNameIndex = -1; + /** position of attribute the change the access rights of the class */ + private int memberClassAttr = -1; + /** index of UTF8 in constant pool*/ + private int initIndex = -1; + /** index of ()V UTF8 in constant pool */ + private int initIndexType = -1; + /** index of CONSTANT_NameAndType index for and ()V in pool */ + private int initNameTypeIndex = -1; + /** position of the method */ + private int initAttr = -1; + + /** map that maps names of fields to their position in constant pool (String, int[1]) */ + private HashMap nameIndexes; + + /** Creates a new instance of PatchByteCode + * + * @param nameIndexes hashmap from (String -> int[1]) + */ + private PatchByteCode(byte[] arr, HashMap nameIndexes) { + this.arr = arr; + this.nameIndexes = nameIndexes; + + // scan twice because of back references + scan (); + scan (); + } + + + /** Generates patch attribute into the classfile to + * allow method patch to modify the superclass of this + * class. + * + * @param arr the bytecode to change + * @param superClass name of the new superclass like java/awt/Button + * @return new version of the bytecode if changed, otherwise null to signal that + * no change has been made + */ + public static byte[] enhance (byte[] arr, String superClass) { + return enhance (arr, superClass, null); + } + + /** Generates patch attribute into the classfile to + * allow method patch to modify the superclass of this + * class. + * + * @param arr the bytecode to change + * @param superClass name of the new superclass like java/awt/Button + * @param methods array of names of methods to make public + * @return new version of the bytecode if changed, otherwise null to signal that + * no change has been made + */ + public static byte[] enhance (byte[] arr, String superClass, String[] methods) { + if (isPatched (arr)) { + // already patched + return null; + } + + HashMap m; + if (methods != null) { + m = new HashMap (); + for (int i = 0; i < methods.length; i++) { + m.put (methods[i], new int[1]); + } + } else { + m = null; + } + + + PatchByteCode pc = new PatchByteCode (arr, m); + boolean patched = false; + + if (superClass != null) { + int x = pc.addClass (superClass); + + byte[] sup = new byte[2]; + writeU2 (sup, 0, x); + pc.addAttribute (ATTR_SUPERCLASS, sup); + + patched = true; + } + + if (!pc.isPublic ()) { + // will need patching + pc.markPublic (); + patched = true; + } + + if (methods != null) { + for (int i = 0; i < methods.length; i++) { + patched |= pc.markMemberPublic (methods[i]); + } + } + + if (patched) { + byte[] patch = { + 'n', 'b' // identification at the end of class file + }; + + pc.addAttribute ("org.netbeans.enhanced", patch); + } else { + return null; + } + + + + // otherwise do the patching + return pc.getClassFile (); + } + + /** Checks if the class has previously been enhanced by the + * change of superclass attribute and if so, changes the bytecode + * to reflect the change. + * + * @param arr the bytecode + * @return the enhanced bytecode + */ + public static byte[] patch (byte[] arr) { + if (!isPatched (arr)) return arr; + + PatchByteCode pc = new PatchByteCode (arr, null); + if (pc.superClassNameAttr > 0) { + // let's patch + int classindex = pc.readU2 (pc.superClassNameAttr + 6); + + writeU2 (pc.getClassFile(), pc.cpEnd + 4, classindex); + + if (pc.initAttr != -1) { + // patch also CONSTANT_Methodref to superclass's + writeU2 (pc.getClassFile (), pc.initAttr + 1, classindex); + } + } + + if (pc.memberClassAttr > 0) { + // change the access rights of the class itself + if (pc.readU4 (pc.memberClassAttr + 2) != 2) { + throw new IllegalArgumentException ("Size of a attribute " + ATTR_MEMBER + " should be 2"); // NOI18N + } + + // alternate access rights + int access = pc.readU2 (pc.memberClassAttr + 6); + + int now = pc.readU2 (pc.cpEnd); + + writeU2 (pc.getClassFile (), pc.cpEnd, access); + + } + + if (pc.memberNameIndex > 0) { + // change access rights of fields + pc.applyMemberAccessChanges (); + } + + return pc.getClassFile (); + } + + + /** Check if the byte code is patched. + * @param arr the bytecode + * @return true if patched + */ + private static boolean isPatched (byte[] arr) { + if (arr == null || arr.length < 2) return false; + + int base = arr.length - 2; + if (arr[base + 1] != 'b') return false; + if (arr[base + 0] != 'n') return false; + + // + // ok, looks like enhanced byte code + // + return true; + } + + + + + + + + /** Gets the current byte array of the actual class file. + * @return bytes of the class file + */ + private byte[] getClassFile () { + return arr; + } + + /** Creates new contant pool entry representing given class. + * @param c name of the class + * @return index of the entry + */ + private int addClass (String s) { + int x = addConstant (s); + + byte[] t = { 7, 0, 0 }; + writeU2 (t, 1, x); + + return addPool (t); + } + + /** Adds a new string constant to the constant pool. + * @param s the string to add + * @return index of the constant + */ + private int addConstant (String s) { + byte[] t; + + try { + t = s.getBytes("utf-8"); // NOI18N + } catch (java.io.UnsupportedEncodingException ex) { + throw new IllegalStateException ("UTF-8 shall be always supported"); // NOI18N + } + + byte[] add = new byte[t.length + 3]; + System.arraycopy (t, 0, add, 3, t.length); + add[0] = 1; // UTF8 contant + writeU2 (add, 1, t.length); + + return addPool (add); + } + + /** Adds this array of bytes as another entry into the constant pool */ + private int addPool (byte[] add) { + byte[] res = new byte[arr.length + add.length]; + + System.arraycopy (arr, 0, res, 0, cpEnd); + // increments number of objects in contant pool + int index = readU2 (cpCount); + writeU2 (res, cpCount, index + 1); + + // adds the content + System.arraycopy (add, 0, res, cpEnd, add.length); + + // and now add the rest of the original array + System.arraycopy (arr, cpEnd, res, cpEnd + add.length, arr.length - cpEnd); + + arr = res; + + cpEnd += add.length; + atCount += add.length; + atEnd += add.length; + + // the index + return index; + } + + /** Checks whether the code is public. + */ + private boolean isPublic () { + int x = readU2 (cpEnd); + + if ((x & 0x0001) != 0) { + return true; + } else { + return false; + } + } + + /** Ensures that the class is public + * @return true if really patched, false if not + */ + private boolean markPublic () { + if (isPublic ()) { + return false; + } + + // make sure ATTR_MEMBER is in constant pool + if (memberNameIndex == -1) { + memberNameIndex = addConstant (ATTR_MEMBER); + } + + int x = readU2 (cpEnd) | 0x0001; // make it public + + byte[] sup = new byte[2]; + writeU2 (sup, 0, x); + addAttribute (ATTR_MEMBER, sup); + + return true; + } + + /** Makes method of field public and non final. + * @param name name of the method to make public + * @return true if really changed, false if it already was public + */ + private boolean markMemberPublic (String name) { + int constantPoolIndex = ((int[])nameIndexes.get (name))[0]; + int patchCount = 0; + boolean modified = false; + + // make sure ATTR_MEMBER is in constant pool + if (memberNameIndex == -1) { + memberNameIndex = addConstant (ATTR_MEMBER); + } + + int pos = cpEnd; + + pos += 6; + // now add interfaces + pos += 2 * readU2 (pos); + // to add also the integer with interfaces + pos += 2; + + for (int fieldsAndMethods = 0; fieldsAndMethods < 2; fieldsAndMethods++) { + // fields and then methods + int fieldsOrMethods = readU2 (pos); + pos += 2; + + while (fieldsOrMethods-- > 0) { + // check the name + int nameIndex = readU2 (pos + 2); + if (nameIndex == constantPoolIndex) { + // let's patch + int access = readU2 (pos); + if ((access & 0x0001) == 0 || (access & 0x0010) != 0) { + // is not public or is final + access = (access | 0x0001) & ~(0x0010 | 0x0002 | 0x0004); + + + // increment the attributes count + int cnt = readU2 (pos + 6) + 1; + + // + byte[] res = new byte[arr.length + 2 + 6]; + + // copy the array before + System.arraycopy(arr, 0, res, 0, pos + 6); + // write the new count of attributes + writeU2 (res, pos + 6, cnt); + + // write the attribute itself + writeU2 (res, pos + 8, memberNameIndex); // name of attribute + writeU4 (res, pos + 10, 2); // length + writeU2 (res, pos + 14, access); // data - the "NetBeans" member modifier + + // copy the rest + System.arraycopy(arr, pos + 8, res, pos + 8 + 6 + 2, arr.length - pos - 8); + + atEnd += 2 + 6; + atCount += 2 + 6; + + + arr = res; + + modified = true; + } + + patchCount++; + } + + pos += memberSize (pos, null); + } + } + + if (patchCount == 0) { + throw new IllegalArgumentException ("Member " + name + " not found!"); + } + + return modified; + } + + + /** Checks all members of the class to find out whether they need patching + * of access rights. If so, patches them. + */ + private void applyMemberAccessChanges () { + int[] result = new int[1]; + + int pos = cpEnd; + + pos += 6; + // now add interfaces + pos += 2 * readU2 (pos); + // to add also the integer with interfaces + pos += 2; + + for (int fieldsAndMethods = 0; fieldsAndMethods < 2; fieldsAndMethods++) { + // fields and then methods + int fieldsOrMethods = readU2 (pos); + pos += 2; + + while (fieldsOrMethods-- > 0) { + result[0] = -1; + int size = memberSize(pos, result); + if (result[0] != -1) { + // we will do patching + + if (readU4 (result[0] + 2) != 2) { + throw new IllegalArgumentException ("Size of a attribute " + ATTR_MEMBER + " should be 2"); // NOI18N + } + + // alternate access rights + int access = readU2 (result[0] + 6); + writeU2 (arr, pos, access); + } + + pos += size; + } + } + } + + /** Adds an attribute to the class file. + * @param name name of the attribute to add + * @param b the bytes representing the attribute + */ + private void addAttribute (String name, byte[] b) { + int index = -1; + if (ATTR_SUPERCLASS.equals (name) && superClassNameIndex > 0) { + index = superClassNameIndex; + } + + if (ATTR_MEMBER.equals (name) && memberNameIndex > 0) { + index = memberNameIndex; + } + + if (index == -1) { + // register new attribute + index = addConstant (name); + } + + byte[] res = new byte[arr.length + b.length + 6]; + + System.arraycopy(arr, 0, res, 0, arr.length); + + writeU2 (res, arr.length, index); + writeU4 (res, arr.length + 2, b.length); + + int begin = arr.length + 6; + System.arraycopy(b, 0, res, begin, b.length); + + atEnd += b.length + 6; + + writeU2 (res, atCount, readU2 (atCount) + 1); + + arr = res; + } + + + /** Gets i-th element from the array. + */ + private int get (int pos) { + if (pos >= arr.length) { + throw new ArrayIndexOutOfBoundsException ("Size: " + arr.length + " index: " + pos); + } + + int x = arr[pos]; + return x >= 0 ? x : 256 + x; + } + + /** Scans the file to find out important possitions + * @return size of the bytecode + */ + private void scan () { + if (get (0) != 0xCA && get (1) != 0xFE && get (2) != 0xBA && get (3) != 0xBE) { + throw new IllegalStateException ("Not a class file!"); // NOI18N + } + + int pos = 10; + // count of items in CP is here + cpCount = 8; + + int cp = readU2 (8); + for (int[] i = { 1 }; i[0] < cp; i[0]++) { + // i[0] can be incremented in constantPoolSize + int len = constantPoolSize (pos, i); + pos += len; + } + + // list item in constant pool + cpEnd = pos; + + pos += 6; + // now add interfaces + pos += 2 * readU2 (pos); + // to add also the integer with interfaces + pos += 2; + + // fields + int fields = readU2 (pos); + pos += 2; + while (fields-- > 0) { + pos += memberSize (pos, null); + } + + int methods = readU2 (pos); + pos += 2; + while (methods-- > 0) { + pos += memberSize (pos, null); + } + + // count of items in Attributes is here + + int[] memberAccess = { -1 }; + + atCount = pos; + int attrs = readU2 (pos); + pos += 2; + while (attrs-- > 0) { + pos += attributeSize (pos, memberAccess); + } + + if (memberAccess[0] != -1) { + // we need to update the name of class + memberClassAttr = memberAccess[0]; + } + + // end of attributes + atEnd = pos; + } + + private int readU2 (int pos) { + int b1 = get (pos); + int b2 = get (pos + 1); + + return b1 * 256 + b2; + } + + private int readU4 (int pos) { + return readU2 (pos) * 256 * 256 + readU2 (pos + 2); + } + + private static void writeU2 (byte[] arr, int pos, int value) { + int v1 = (value & 0xff00) >> 8; + int v2 = value & 0xff; + + if (v1 < 0) v1 += 256; + if (v2 < 0) v2 += 256; + + arr[pos] = (byte)v1; + arr[pos + 1] = (byte)v2; + } + + private static void writeU4 (byte[] arr, int pos, int value) { + writeU2 (arr, pos, (value & 0xff00) >> 16); + writeU2 (arr, pos + 2, value & 0x00ff); + } + + /** @param pos position to read from + * @param cnt[0] index in the pool that we are now reading + */ + private int constantPoolSize (int pos, int[] cnt) { + switch (get (pos)) { + case 7: // CONSTANT_Class + case 8: // CONSTANT_String + return 3; + + case 12: // CONSTANT_NameAndType + // check for and ()V invocation + int nameIndex = readU2 (pos + 1); + if (nameIndex == initIndex) { + int descriptorIndex = readU2 (pos + 3); + if (descriptorIndex == initIndexType) { + if (initNameTypeIndex > 0 && initNameTypeIndex != cnt[0]) { + throw new IllegalArgumentException ("Second initialization of name type index"); // NOI18N + } + initNameTypeIndex = cnt[0]; + } + } + return 5; + + case 10: // CONSTANT_Methodref + // special check for invocation + int classname = readU2 (pos + 1); + int nameAndType = readU2 (pos + 3); + if (nameAndType == initNameTypeIndex) { + // found call to + int superclass = readU2 (cpEnd + 4); + + if (superclass == classname) { + // it is call to our superclass + if (initAttr > 0 && initAttr != pos) { + throw new IllegalStateException ("Second initialization of position of invocation"); // NOI18N + } + initAttr = pos; + } + } + return 5; + + case 9: // CONSTANT_Fieldref + case 11: // CONSTANT_InterfaceMethodref + case 3: // CONSTANT_Integer + case 4: // CONSTANT_Float + return 5; + + case 5: // CONSTANT_Long + case 6: // CONSTANT_Double + // after long and double the next entry in CP is unusable + cnt[0]++; + return 9; + case 1: // CONSTANT_Utf8 + int len = readU2 (pos + 1); + + if (compareUtfEntry (BYTE_INIT, pos)) { + if (initIndex > 0 && initIndex != cnt[0]) { + throw new IllegalArgumentException ("Second initialization of " + ATTR_INIT); // NOI18N + } + initIndex = cnt[0]; + } + + if (compareUtfEntry (BYTE_INIT_TYPE, pos)) { + if (initIndexType > 0 && initIndexType != cnt[0]) { + throw new IllegalArgumentException ("Second initialization of " + ATTR_INIT_TYPE); // NOI18N + } + initIndexType = cnt[0]; + } + + if (compareUtfEntry (BYTE_SUPERCLASS, pos)) { + // we have found the attribute + if (superClassNameIndex > 0 && superClassNameIndex != cnt[0]) { + throw new IllegalStateException (ATTR_SUPERCLASS + " registered for the second time!"); // NOI18N + } + + superClassNameIndex = cnt[0]; + } + + if (compareUtfEntry (BYTE_MEMBER, pos)) { + // we have found the attribute + if (memberNameIndex > 0 && memberNameIndex != cnt[0]) { + throw new IllegalStateException (ATTR_MEMBER + " registered for the second time!"); // NOI18N + } + + memberNameIndex = cnt[0]; + } + + if (nameIndexes != null) { + // check the name in the table + String s; + try { + s = new String (arr, pos + 3, len, "utf-8"); // NOI18N + } catch (UnsupportedEncodingException ex) { + throw new IllegalStateException ("utf-8 is always supported"); // NOI18N + } + + int[] index = (int[])nameIndexes.get (s); + if (index != null) { + index[0] = cnt[0]; + } + } + + // ok, exit + return len + 3; + default: + throw new IllegalStateException ("Unknown pool type: " + get (pos)); // NOI18N + } + } + + private int memberSize (int pos, int[] containsPatchAttribute) { + int s = 8; + int name = readU2 (pos + 2); + + int cnt = readU2 (pos + 6); + + while (cnt-- > 0) { + s += attributeSize (pos + s, containsPatchAttribute); + } + return s; + } + + /** Into the containsPatchAttribute (if not null) it adds the + * index of structure of attribute ATTR_MEMBER. + */ + private int attributeSize (int pos, int[] containsPatchAttribute) { + // index to the name attr + int name = readU2 (pos); + + if (name == superClassNameIndex) { + if (superClassNameAttr > 0 && superClassNameAttr != pos) { + throw new IllegalStateException ("Two attributes with name " + ATTR_SUPERCLASS); // NOI18N + } + + // we found the attribute + superClassNameAttr = pos; + } + + if (name == memberNameIndex && containsPatchAttribute != null) { + if (containsPatchAttribute[0] != -1) { + throw new IllegalStateException ("Second attribute " + ATTR_MEMBER); // NOI18N + } + containsPatchAttribute[0] = pos; + } + + int len = readU4 (pos + 2); + return len + 6; + } + + + /** Compares arrays. + */ + private boolean compareUtfEntry (byte[] pattern, int pos) { + int len = readU2 (pos + 1); + + if (pattern.length != len) { + return false; + } + + int base = pos + 3; + // we are searching for an attribute with given name + for (int i = 0; i < len; i++) { + if (pattern[i] != arr[base + i]) { + // regular exit + return false; + } + } + + return true; + } +} Index: nb_all/core/src/org/netbeans/ProxyClassLoader.java =================================================================== RCS file: nb_all/core/src/org/netbeans/ProxyClassLoader.java diff -N nb_all/core/src/org/netbeans/ProxyClassLoader.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/core/src/org/netbeans/ProxyClassLoader.java 13 Aug 2002 23:37:52 -0000 @@ -0,0 +1,608 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans; + +import java.util.*; +import java.net.URL; +import java.io.IOException; + +/** + * A class loader that has multiple parents and uses them for loading + * classes and resources. It can be used in tree hierarchy, where it + * can exploit its capability to not throw ClassNotFoundException when + * communicating with other ProxyClassLoader. + * It itself doesn't load classes or resources, but allows subclasses + * to add such functionality. + * + * @author Petr Nejedly, Jesse Glick + */ +public class ProxyClassLoader extends ClassLoader { + /** empty enumeration */ + private static final Enumeration EMPTY = new ArrayEnumeration (new Object[0]); + + + // Map + // packages are given in format "org/netbeans/modules/foo/" + private final Map domainsByPackage = new HashMap(); + // Map + private HashMap packages = new HashMap(); + + // All parentf of this classloader, including their parents recursively + private ClassLoader[] parents; + + /** if true, we have been destroyed */ + private boolean dead = false; + + /** Create a multi-parented classloader. + * @param parents list of parent classloaders. + * @throws IllegalArgumentException if there are any nulls or duplicate + * parent loaders or cycles. + */ + public ProxyClassLoader( ClassLoader[] parents ) { + if (parents.length == 0) { + throw new IllegalArgumentException ("ProxyClassLoader must have a parent"); // NOI18N + } + + Set check = new HashSet(Arrays.asList(parents)); // Set + if (check.size() < parents.length) throw new IllegalArgumentException("duplicate parents"); // NOI18N + if (check.contains(null)) throw new IllegalArgumentException("null parent"); // NOI18N + + this.parents = coalesceParents(parents); + } + + // this is used only by system classloader, maybe we can redesign it a bit + // to live without this functionality, then destroy may also go away + /** Add new parents dynamically. + * @param parents the new parents to add (append to list) + * @throws IllegalArgumentException in case of a null or cyclic parent (duplicate OK) + */ + public synchronized void append(ClassLoader[] nueparents) throws IllegalArgumentException { + // XXX should this be synchronized? + if (nueparents == null) throw new IllegalArgumentException("null parents array"); // NOI18N + for (int i = 0; i < nueparents.length; i++) { + if (nueparents[i] == null) throw new IllegalArgumentException("null parent"); // NOI18N + } + + parents = coalesceAppend(parents, nueparents); + } + + + + /** Try to destroy this classloader. + * Subsequent attempts to use it will log an error (at most one though). + */ + public void destroy() { + dead = true; + } + + private void zombieCheck(String hint) { + if (dead) { + IllegalStateException ise = new IllegalStateException("WARNING - attempting to use a zombie classloader " + this + " on " + hint + ". This means classes from a disabled module are still active. May or may not be a problem."); // NOI18N + JarClassLoader.notify(0, ise); + // don't warn again for same loader... this was enough + dead = false; + } + } + + /** + * Loads the class with the specified name. The implementation of + * this method searches for classes in the following order:

+ *

    + *
  1. Calls {@link #findLoadedClass(String)} to check if the class has + * already been loaded. + *
  2. Checks the caches whether another class from the same package + * was already loaded and uses the same classloader + *
  3. Tries to find the class using parent loaders in their order. + *
  4. Calls the {@link #simpleFindClass(String,String)} method to find + * the class using this class loader. + *
+ * + * @param name the name of the class + * @param resolve if true then resolve the class + * @return the resulting Class object + * @exception ClassNotFoundException if the class could not be found + */ + protected synchronized final Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + zombieCheck(name); + // XXX this section is a candidate for local optimization: + String filename = name.replace('.', '/').concat(".class"); // NOI18N + int idx = filename.lastIndexOf('/'); // NOI18N + if (idx == -1) throw new ClassNotFoundException("Will not load classes from default package"); // NOI18N + String pkg = filename.substring(0, idx + 1); // "org/netbeans/modules/foo/" + Class c = smartLoadClass(name, filename, pkg); + if(c == null) throw new ClassNotFoundException(name); + if (resolve) resolveClass(c); + return c; + } + + /** This ClassLoader can't load anything itself. Subclasses + * may override this method to do some class loading themselves. The + * implementation should not throw any exception, just return + * null if it can't load required class. + * + * @param name the name of the class + * @param fileName the expected filename of the classfile, like + * java/lang/Object.class for java.lang.Object + * The ClassLoader implementation may or may not use it, depending + * whether it is usefull to it. + * @return the resulting Class object or null + */ + protected Class simpleFindClass(String name, String fileName) { + return null; + } + + + /** + * Finds the resource with the given name. The implementation of + * this method searches for resources in the following order:

+ *

    + *
  1. Checks the caches whether another resource or class from the same + * package was already loaded and uses the same classloader. + *
  2. Tries to find the resources using parent loaders in their order. + *
  3. Calls the {@link #findResource(String)} method to find + * the resources using this class loader. + *
+ * + * @param name a "/"-separated path name that identifies the resource. + * @return a URL for reading the resource, or null if + * the resource could not be found. + * @see #findResource(String) + */ + public final URL getResource(final String name) { + zombieCheck(name); + + final int slashIdx = name.lastIndexOf('/'); + if (slashIdx == -1) return null; // won't load from the default package + final String pkg = name.substring(0, slashIdx + 1); + + if (isSpecialResource(pkg)) { + // Disable domain cache for this one, do a simple check. + for (int i = 0; i < parents.length; i++) { + if (!shouldDelegateResource(pkg, parents[i])) continue; + URL u; + if (parents[i] instanceof ProxyClassLoader) { + u = ((ProxyClassLoader)parents[i]).findResource(name); + } else { + u = parents[i].getResource(name); + } + if (u != null) return u; + } + return findResource(name); + } + + ClassLoader owner = (ClassLoader)domainsByPackage.get(pkg); + + if (owner != null) { // known package + // Note that shouldDelegateResource should already be true for this! + if (owner instanceof ProxyClassLoader) { + return ((ProxyClassLoader)owner).findResource(name); // we have its parents, skip them + } else { + return owner.getResource(name); // know nothing about this loader and his structure + } + } + + // virgin package + URL retVal = null; + for (int i = 0; i < parents.length; i++) { + owner = parents[i]; + if (!shouldDelegateResource(pkg, owner)) continue; + if (owner instanceof ProxyClassLoader) { + retVal = ((ProxyClassLoader)owner).findResource(name); // skip parents (checked already) + } else { + retVal = owner.getResource(name); // know nothing about this loader and his structure + } + if (retVal != null) { + domainsByPackage.put(pkg, owner); + return retVal; + } + } + + // try it ourself + retVal = findResource(name); + if (retVal != null) { + domainsByPackage.put(pkg, this); + } + return retVal; + } + + /** This ClassLoader can't load anything itself. Subclasses + * may override this method to do some resource loading themselves. + * + * @param name the resource name + * @return a URL for reading the resource, or null + * if the resource could not be found. + */ + protected URL findResource(String name) { + return null; + } + + /** + * Finds all the resource with the given name. The implementation of + * this method uses the {@link #simpleFindResources(String)} method to find + * all the resources available from this classloader and adds all the + * resources from all the parents. + * + * @param name the resource name + * @return an Enumeration of URLs for the resources + * @throws IOException if I/O errors occur + */ + protected final synchronized Enumeration findResources(String name) throws IOException { + zombieCheck(name); + final int slashIdx = name.lastIndexOf('/'); + if (slashIdx == -1) return EMPTY; // won't load from the default package + final String pkg = name.substring(0, slashIdx + 1); + + // Don't bother optimizing this call by domains. + // It is mostly used for resources for which isSpecialResource would be true anyway. + Enumeration[] es = new Enumeration[parents.length + 1]; + for (int i = 0; i < parents.length; i++) { + if (!shouldDelegateResource(pkg, parents[i])) { + es[i] = EMPTY; + continue; + } + if (parents[i] instanceof ProxyClassLoader) { + es[i] = ((ProxyClassLoader)parents[i]).simpleFindResources(name); + } else { + es[i] = parents[i].getResources(name); + } + } + es[parents.length] = simpleFindResources(name); + // Should not be duplicates, assuming the parent loaders are properly distinct + // from one another and do not overlap in JAR usage, which they ought not. + // Anyway MetaInfServicesLookup, the most important client of this method, does + // its own duplicate filtering already. + return new AAEnum (es); + } + + /** This ClassLoader can't load anything itself. Subclasses + * may override this method to do some resource loading themselves, this + * implementation simply delegates to findResources method of the superclass + * that should return empty Enumeration. + * + * @param name the resource name + * @return an Enumeration of URLs for the resources + * @throws IOException if I/O errors occur + */ + protected Enumeration simpleFindResources(String name) throws IOException { + return super.findResources(name); + } + + + /** + * Returns a Package that has been defined by this class loader or any + * of its parents. + * + * @param name the package name + * @return the Package corresponding to the given name, or null if not found + */ + protected Package getPackage(String name) { + zombieCheck(name); + + int idx = name.lastIndexOf('.'); + if (idx == -1) return null; + String spkg = name.substring(0, idx + 1).replace('.', '/'); + + synchronized (packages) { + Package pkg = (Package)packages.get(name); + if (pkg != null) return pkg; + + for (int i = 0; i < parents.length; i++) { + ClassLoader par = parents[i]; + if (par instanceof ProxyClassLoader && shouldDelegateResource(spkg, par)) { + pkg = ((ProxyClassLoader)par).getPackage(name); + if(pkg != null) break; + } + } + // do our own lookup + if (pkg == null) pkg = super.getPackage(name); + // cache results + if (pkg != null) packages.put(name, pkg); + + return pkg; + } + } + + /** This is here just for locking serialization purposes. + * Delegates to super.definePackage with proper locking. + */ + protected Package definePackage(String name, String specTitle, + String specVersion, String specVendor, String implTitle, + String implVersion, String implVendor, URL sealBase ) + throws IllegalArgumentException { + synchronized (packages) { + return super.definePackage (name, specTitle, specVersion, specVendor, implTitle, + implVersion, implVendor, sealBase); + } + } + + /** + * Returns all of the Packages defined by this class loader and its parents. + * + * @return the array of Package objects defined by this + * ClassLoader + */ + protected synchronized Package[] getPackages() { + zombieCheck(null); + Map all = new HashMap(); // Map + addPackages(all, super.getPackages()); + for (int i = 0; i < parents.length; i++) { + ClassLoader par = parents[i]; + if (par instanceof ProxyClassLoader) { + // XXX should ideally use shouldDelegateResource here... + addPackages(all, ((ProxyClassLoader)par).getPackages()); + } + } + synchronized (packages) { + Iterator it = all.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + Object name = entry.getKey(); + if (! packages.containsKey(name)) { + packages.put(name, entry.getValue()); + } + } + } + return (Package[])all.values().toArray(new Package[all.size()]); + } + + public Package getPackageAccessibly(String name) { + return getPackage(name); + } + + public Package[] getPackagesAccessibly() { + return getPackages(); + } + + + + /** Coalesce parent classloaders into an optimized set. + * This means that all parents of the specified classloaders + * are also added recursively, removing duplicates along the way. + * Search order should be preserved (parents before children, stable w.r.t. inputs). + * @param loaders list of suggested parents (no nulls or duplicates permitted) + * @return optimized list of parents (no nulls or duplicates) + * @throws IllegalArgumentException if there are cycles + */ + private ClassLoader[] coalesceParents(ClassLoader[] loaders) throws IllegalArgumentException { + int likelySize = loaders.length * 3 + 1; + Set resultingUnique = new HashSet(likelySize); // Set + List resulting = new ArrayList(likelySize); // List + for (int i = 0; i < loaders.length; i++) { + addRec(resultingUnique, resulting, loaders[i]); + } + ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]); + return ret; + } + + /** Coalesce a new set of loaders into the existing ones. + */ + private ClassLoader[] coalesceAppend(ClassLoader[] existing, ClassLoader[] appended) throws IllegalArgumentException { + int likelySize = existing.length + 3; + Set resultingUnique = new HashSet(likelySize); + List existingL = Arrays.asList(existing); + resultingUnique.addAll(existingL); + if (resultingUnique.containsAll(Arrays.asList(appended))) { + // No change required. + return existing; + } + List resulting = new ArrayList(likelySize); + resulting.addAll(existingL); + int fromIdx = resulting.size(); + for (int i = 0; i < appended.length; i++) { + addRec(resultingUnique, resulting, appended[i]); + } + ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]); + return ret; + } + + private void addRec(Set resultingUnique, List resulting, ClassLoader loader) throws IllegalArgumentException { + if (loader == this) throw new IllegalArgumentException("cycle in parents"); // NOI18N + if (resultingUnique.contains(loader)) return; + if (loader instanceof ProxyClassLoader) { + ClassLoader[] parents = ((ProxyClassLoader)loader).parents; + for (int i = 0; i < parents.length; i++) { + addRec(resultingUnique, resulting, parents[i]); + } + } + resultingUnique.add(loader); + resulting.add(loader); + } + + /** A method that finds a class either in itself or in parents. + * It uses dual signaling for class not found: it can either return null + * or throw CNFE itself. + * @param name class name, e.g. "org.netbeans.modules.foo.Clazz" + * @param fileName resource name, e.g. "org/netbeans/modules/foo/Clazz.class" + * @param pkg package component, e.g. "org/netbeans/modules/foo/" + * @return a class or null if not found. It can also throw an exception. + * @throws ClassNotFoundException in case it doesn't found a class + * and a parent eglible for loading it thrown it already. + */ + private final Class smartLoadClass(String name, String fileName, String pkg) throws ClassNotFoundException { + // First, check if the class has already been loaded + Class c = findLoadedClass(name); + if(c != null) return c; + + final ClassLoader owner = isSpecialResource(pkg) ? null : (ClassLoader)domainsByPackage.get(pkg); + if (owner == this) { + return simpleFindClass(name,fileName); + } + if (owner != null) { + // Note that shouldDelegateResource should already be true as we hit this pkg before. + if (owner instanceof ProxyClassLoader) { + return ((ProxyClassLoader)owner).fullFindClass(name,fileName); + } else { + return owner.loadClass(name); // May throw CNFE, will be propagated + } + } + + // Virgin package, do the parent scan + c = loadInOrder(name, fileName, pkg); + + if (c != null) { + final ClassLoader owner2 = c.getClassLoader(); // who got it? + domainsByPackage.put(pkg, owner2); + } + return c; + } + + + private final Class loadInOrder( String name, String fileName, String pkg ) throws ClassNotFoundException { + ClassNotFoundException cached = null; + for (int i = 0; i < parents.length; i++) { + ClassLoader par = parents[i]; + if (!shouldDelegateResource(pkg, par)) continue; + if (par instanceof ProxyClassLoader) { + Class c = ((ProxyClassLoader)par).fullFindClass(name,fileName); + if (c != null) return c; + } else { + try { + return par.loadClass(name); + } catch( ClassNotFoundException cnfe ) { + cached = cnfe; + } + } + } + + Class c = simpleFindClass(name,fileName); // Try it ourselves + if (c != null) return c; + if (cached != null) throw cached; + return null; + } + + private synchronized Class fullFindClass(String name, String fileName) { + Class c = findLoadedClass(name); + return (c == null) ? simpleFindClass(name, fileName) : c; + } + + private void addPackages(Map all, Package[] pkgs) { + // Would be easier if Package.equals() was just defined sensibly... + for (int i = 0; i < pkgs.length; i++) { + all.put(pkgs[i].getName(), pkgs[i]); + } + } + + /** Test whether a given resource name is something that any JAR might + * have, and for which the domain cache should be disabled. + * The result must not change from one call to the next with the same argument. + * By default the domain cache is disabled only for META-INF/* JAR information. + * @param pkg the package component of the resource path ending with a slash, + * e.g. "org/netbeans/modules/foo/" + * @return true if it is a special resource, false for normal domain-cached resource + * @since org.netbeans.core/1 1.3 + */ + protected boolean isSpecialResource(String pkg) { + if (pkg.startsWith("META-INF/")) return true; // NOI18N + return false; + } + + /** Test whether a given resource request (for a class or not) should be + * searched for in the specified parent classloader or not. + * The result must not change from one call to the next with the same arguments. + * By default, always true. Subclasses may override to "mask" certain + * packages from view, possibly according to the classloader chain. + * @param pkg the package component of the resource path ending with a slash, + * e.g. "org/netbeans/modules/foo/" + * @param parent a classloader which is a direct or indirect parent of this one + * @return true if the request should be delegated to this parent; false to + * only search elsewhere (other parents, this loader's own namespace) + * @since org.netbeans.core/1 1.3 + */ + protected boolean shouldDelegateResource(String pkg, ClassLoader parent) { + return true; + } + + + private static final class ArrayEnumeration implements Enumeration { + /** The array */ + private Object[] array; + /** Current index in the array */ + private int index = 0; + + /** Constructs a new ArrayEnumeration for specified array */ + public ArrayEnumeration (Object[] array) { + this.array = array; + } + + /** Tests if this enumeration contains more elements. + * @return true if this enumeration contains more elements; + * false otherwise. + */ + public boolean hasMoreElements() { + return (index < array.length); + } + + /** Returns the next element of this enumeration. + * @return the next element of this enumeration. + * @exception NoSuchElementException if no more elements exist. + */ + public Object nextElement() { + try { + return array[index++]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + } + + private static final class AAEnum implements Enumeration { + /** The array */ + private Enumeration[] array; + /** Current index in the array */ + private int index = 0; + + /** Constructs a new ArrayEnumeration for specified array */ + public AAEnum (Enumeration[] array) { + this.array = array; + } + + /** Tests if this enumeration contains more elements. + * @return true if this enumeration contains more elements; + * false otherwise. + */ + public boolean hasMoreElements() { + for (;;) { + if (index == array.length) { + return false; + } + + if (array[index].hasMoreElements ()) { + return true; + } + + index++; + } + } + + /** Returns the next element of this enumeration. + * @return the next element of this enumeration. + * @exception NoSuchElementException if no more elements exist. + */ + public Object nextElement() { + try { + return array[index].nextElement (); + } catch (NoSuchElementException ex) { + if (hasMoreElements ()) { + // try once more + return nextElement (); + } + throw ex; + } catch (ArrayIndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + } + +} Index: nb_all/core/src/org/netbeans/core/Main.java =================================================================== RCS file: /cvs/core/src/org/netbeans/core/Main.java,v retrieving revision 1.147 diff -u -r1.147 Main.java --- nb_all/core/src/org/netbeans/core/Main.java 29 Jul 2002 10:11:14 -0000 1.147 +++ nb_all/core/src/org/netbeans/core/Main.java 13 Aug 2002 23:37:52 -0000 @@ -121,8 +121,9 @@ /** Starts TopThreadGroup which properly overrides uncaughtException * Further - new thread in the group execs main */ - public static void start(String[] argv) { + public static void main (String[] argv) { TopThreadGroup tg = new TopThreadGroup ("IDE Main", argv); // NOI18N - programatic name + StartLog.logStart ("Forwarding to topThreadGroup"); // NOI18N tg.start (); } @@ -356,7 +357,7 @@ /** * @exception SecurityException if it is called multiple times */ - public static void main(String[] args) throws SecurityException { + static void start (String[] args) throws SecurityException { long time = System.currentTimeMillis(); StartLog.logEnd ("Forwarding to topThreadGroup"); // NOI18N Index: nb_all/core/src/org/netbeans/core/TopThreadGroup.java =================================================================== RCS file: /cvs/core/src/org/netbeans/core/TopThreadGroup.java,v retrieving revision 1.16 diff -u -r1.16 TopThreadGroup.java --- nb_all/core/src/org/netbeans/core/TopThreadGroup.java 29 Jul 2002 10:11:14 -0000 1.16 +++ nb_all/core/src/org/netbeans/core/TopThreadGroup.java 13 Aug 2002 23:37:52 -0000 @@ -78,7 +78,7 @@ public void run() { try { - Main.main(args); + Main.start (args); } catch (Throwable t) { // XXX is this not handled by uncaughtException? ErrorManager.getDefault().notify(t); Index: nb_all/core/src/org/netbeans/core/modules/JarClassLoader.java =================================================================== RCS file: nb_all/core/src/org/netbeans/core/modules/JarClassLoader.java diff -N nb_all/core/src/org/netbeans/core/modules/JarClassLoader.java --- nb_all/core/src/org/netbeans/core/modules/JarClassLoader.java 29 Jul 2002 10:11:15 -0000 1.14 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,401 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.core.modules; - -import java.net.URL; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.jar.Attributes; -import java.util.jar.Attributes.Name; -import java.util.zip.ZipEntry; -import java.io.*; -import java.net.MalformedURLException; -import java.security.*; -import java.security.cert.Certificate; -import java.util.*; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -import org.openide.ErrorManager; - -/** - * A ProxyClassLoader capable of loading classes from a set of jar files - * and local directories. - * - * @author Petr Nejedly - */ -public class JarClassLoader extends ProxyClassLoader { - private Source[] sources; - /** temp copy JARs which ought to be deleted */ - private Set deadJars = null; // Set - - /** Creates new JarClassLoader */ - public JarClassLoader (List files, ClassLoader[] parents) { - super(parents); - - sources = new Source[files.size()]; - try { - int i=0; - for (Iterator it = files.iterator(); it.hasNext(); i++ ) { - Object act = it.next(); - if (act instanceof File) { - sources[i] = new DirSource((File)act); - } else { - sources[i] = new JarSource((JarFile)act); - } - } - } catch (MalformedURLException exc) { - throw new IllegalArgumentException(exc.getMessage()); - } - - } - - protected PermissionCollection getPermissions( CodeSource cs ) { - return Policy.getPolicy().getPermissions(cs); - } - - protected Package definePackage(String name, Manifest man, URL url) - throws IllegalArgumentException - { - if (man == null ) { - return definePackage(name, null, null, null, null, null, null, null); - } - - String path = name.replace('.', '/').concat("/"); // NOI18N - Attributes spec = man.getAttributes(path); - Attributes main = man.getMainAttributes(); - - String specTitle = getAttr(spec, main, Name.SPECIFICATION_TITLE); - String implTitle = getAttr(spec, main, Name.IMPLEMENTATION_TITLE); - String specVersion = getAttr(spec, main, Name.SPECIFICATION_VERSION); - String implVersion = getAttr(spec, main, Name.IMPLEMENTATION_VERSION); - String specVendor = getAttr(spec, main, Name.SPECIFICATION_VENDOR); - String implVendor = getAttr(spec, main, Name.IMPLEMENTATION_VENDOR); - String sealed = getAttr(spec, main, Name.SEALED); - - URL sealBase = "true".equalsIgnoreCase(sealed) ? url : null; // NOI18N - return definePackage(name, specTitle, specVersion, specVendor, - implTitle, implVersion, implVendor, sealBase); - } - - private static String getAttr(Attributes spec, Attributes main, Name name) { - String val = null; - if (spec != null) val = spec.getValue (name); - if (val == null && main != null) val = main.getValue (name); - return val; - } - - protected Class simpleFindClass(String name, String path) { - // look up the Sources and return a class based on their content - for( int i=0; i - try { - for (int i = 0; i < sources.length; i++) { - if (sources[i] instanceof JarSource) { - JarFile origJar = ((JarSource)sources[i]).getJarFile(); - File orig = new File(origJar.getName()); - if (!orig.isFile()) { - // Can happen when a test module is deleted: - // the physical JAR has already been deleted - // when the module was disabled. In this case it - // is possible that a classloader request for something - // in the JAR could still come in. Does it matter? - // See comment in Module.cleanup. - continue; - } - String name = orig.getName(); - String prefix, suffix; - int idx = name.lastIndexOf('.'); - if (idx == -1) { - prefix = name; - suffix = null; - } else { - prefix = name.substring(0, idx); - suffix = name.substring(idx); - } - while (prefix.length() < 3) prefix += "x"; // NOI18N - File temp = File.createTempFile(prefix, suffix); - temp.deleteOnExit(); - InputStream is = new FileInputStream(orig); - try { - OutputStream os = new FileOutputStream(temp); - try { - byte[] buf = new byte[4096]; - int j; - while ((j = is.read(buf)) != -1) { - os.write(buf, 0, j); - } - } finally { - os.close(); - } - } finally { - is.close(); - } - // Don't use OPEN_DELETE even though it sounds like a good idea. - // Can cause real problems under 1.4; see Module.java. - JarFile tempJar = new JarFile(temp); - origJar.close(); - forceRelease(orig); - deadJars.add(tempJar); - sources[i] = new JarSource(tempJar); - Util.err.log("#21114: replacing " + orig + " with " + temp); - } - } - } catch (IOException ioe) { - Util.err.notify(ErrorManager.INFORMATIONAL, ioe); - } - } - - /** Release jar: locks when the classloader is shut down. - * Should help reloading modules with changed resources. - */ - public void destroy() { - super.destroy(); - for (int i = 0; i < sources.length; i++) { - if (sources[i] instanceof JarSource) { - JarFile j = ((JarSource)sources[i]).getJarFile(); - File f = new File(j.getName()); - forceRelease(f); - } - } - } - - /** Delete any temporary JARs we were holding on to. - * Also close any other JARs in our list. - */ - protected void finalize() throws Throwable { - super.finalize(); - for (int i = 0; i < sources.length; i++) { - if (sources[i] instanceof JarSource) { - JarFile j = ((JarSource)sources[i]).getJarFile(); - File f = new File(j.getName()); - j.close(); - forceRelease(f); - if (deadJars != null && deadJars.contains(j)) { - Util.err.log("#21114: closing and deleting temporary JAR " + f); - if (f.isFile() && !f.delete()) { - Util.err.log("(but failed to delete it)"); - } - } - } - } - } - - /** Make sure the Java runtime's jar: URL cache is not holding - * onto the specified file. - * Workaround for JDK bug #4646668. - */ - private static void forceRelease(File f) { - if (fileCache == null || factory == null) return; - try { - synchronized (factory) { - Iterator it = fileCache.values().iterator(); - while (it.hasNext()) { - JarFile j = (JarFile)it.next(); - if (f.equals(new File(j.getName()))) { - j.close(); - it.remove(); - Util.err.log("Removing jar: cache for " + f + " as workaround for JDK #4646668"); - } - } - } - } catch (Exception e) { - Util.err.annotate(e, ErrorManager.UNKNOWN, "Could not remove jar: cache for " + f, null, null, null); - Util.err.notify(ErrorManager.INFORMATIONAL, e); - } - } - private static Object factory = null; - private static HashMap fileCache = null; - static { - try { - Class juc = Class.forName("sun.net.www.protocol.jar.JarURLConnection"); // NOI18N - Field factoryF = juc.getDeclaredField("factory"); // NOI18N - factoryF.setAccessible(true); - factory = factoryF.get(null); - Class jff = Class.forName("sun.net.www.protocol.jar.JarFileFactory"); // NOI18N - if (!jff.isInstance(factory)) throw new ClassCastException(factory.getClass().getName()); - Field fileCacheF = jff.getDeclaredField("fileCache"); // NOI18N - fileCacheF.setAccessible(true); - if (Modifier.isStatic(fileCacheF.getModifiers())) { - // JDK 1.3.1 or 1.4 seems to have it static. - fileCache = (HashMap)fileCacheF.get(null); - } else { - // But in 1.3.0 it appears to be an instance var. - fileCache = (HashMap)fileCacheF.get(factory); - } - Util.err.log("Workaround for JDK #4646668 active as part of IZ #21114"); - } catch (Exception e) { - Util.err.annotate(e, ErrorManager.UNKNOWN, "Workaround for JDK #4646668 as part of IZ #21114 failed", null, null, null); - Util.err.notify(ErrorManager.INFORMATIONAL, e); - } - } - - abstract class Source { - private URL url; - private ProtectionDomain pd; - - public Source(URL url) { - this.url = url; - CodeSource cs = new CodeSource(url, new Certificate[0]); - pd = new ProtectionDomain(cs, getPermissions(cs)); - } - - public final URL getURL() { - return url; - } - - public final ProtectionDomain getProtectionDomain() { - return pd; - } - - public final URL getResource(String name) { - try { - return doGetResource(name); - } catch (MalformedURLException e) { - Util.err.log(e.toString()); - } - return null; - } - - protected abstract URL doGetResource(String name) throws MalformedURLException; - - public final byte[] getClassData(String name, String path) { - try { - return readClass(name, path); - } catch (IOException e) { - Util.err.log(e.toString()); - } - return null; - } - - protected abstract byte[] readClass(String name, String path) throws IOException; - - public Manifest getManifest() { - return null; - } - } - - class JarSource extends Source { - JarFile src; - - public JarSource(JarFile file) throws MalformedURLException { - super(new URL("file:" + file.getName())); - src = file; - } - - public Manifest getManifest() { - try { - return src.getManifest(); - } catch (IOException e) { - return null; - } - } - - JarFile getJarFile() { - return src; - } - - protected URL doGetResource(String name) throws MalformedURLException { - ZipEntry ze = src.getEntry(name); - return ze == null ? null : new URL("jar:file:" + src.getName() + "!/" + ze.getName()); // NOI18N - } - - protected byte[] readClass(String name, String path) throws IOException { - ZipEntry ze = src.getEntry(path); - if (ze == null) return null; - - int len = (int)ze.getSize(); - byte[] data = new byte[len]; - InputStream is = src.getInputStream(ze); - int count = 0; - while (count < len) { - count += is.read(data, count, len-count); - } - return data; - } - } - - class DirSource extends Source { - File dir; - - public DirSource(File file) throws MalformedURLException { - super(file.toURL()); - dir = file; - } - - protected URL doGetResource(String name) throws MalformedURLException { - File resFile = new File(dir, name); - return resFile.exists() ? resFile.toURL() : null; - } - - protected byte[] readClass(String name, String path) throws IOException { - File clsFile = new File(dir, path.replace('/', File.separatorChar)); - - int len = (int)clsFile.length(); - byte[] data = new byte[len]; - InputStream is = new FileInputStream(clsFile); - int count = 0; - while (count < len) { - count += is.read(data, count, len-count); - } - return data; - } - - } -} Index: nb_all/core/src/org/netbeans/core/modules/Module.java =================================================================== RCS file: /cvs/core/src/org/netbeans/core/modules/Module.java,v retrieving revision 1.30 diff -u -r1.30 Module.java --- nb_all/core/src/org/netbeans/core/modules/Module.java 29 Jul 2002 10:11:15 -0000 1.30 +++ nb_all/core/src/org/netbeans/core/modules/Module.java 13 Aug 2002 23:37:52 -0000 @@ -30,6 +30,8 @@ import org.openide.modules.SpecificationVersion; import org.openide.modules.Dependency; import org.openide.util.WeakSet; +import org.netbeans.JarClassLoader; +import org.netbeans.ProxyClassLoader; /** Object representing one module, possibly installed. * Responsible for opening of module JAR file; reading @@ -797,15 +799,31 @@ // #9273: load any modules/patches/this-code-name/*.jar files first: File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N getCodeNameBase().replace('.', '-')); // NOI18N - if (patchdir.isDirectory()) { - File[] jars = patchdir.listFiles(Util.jarFilter()); - if (jars != null) { - for (int j = 0; j < jars.length; j++) { - ev.log(Events.PATCH, jars[j]); - classp.add(new JarFile(jars[j])); + + scanFilesInADir (patchdir, classp); + + String patchesClassPath = System.getProperty ("netbeans.patches." + getCodeNameBase ()); // NOI18N + if (patchesClassPath != null) { + //scanFilesInADir (new File (dir), classp); + StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator); + while (tokenizer.hasMoreElements()) { + String element = (String) tokenizer.nextElement(); + File fileElement = new File(element); + if (fileElement.isDirectory()) { + // adding directory + Util.err.log("module patches: adding directory "+fileElement+" for "+getCodeNameBase()); + File[] jars = fileElement.listFiles(Util.jarFilter()); + if (jars != null) { + for (int j=0; j < jars.length; j++) { + // add jar files + System.out.println("adding jar file:"+jars[j]); + classp.add( new JarFile(jars[j])); + } + } + // add also dir + System.out.println("adding directory:"+fileElement); + classp.add((Object) fileElement); } - } else { - Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir); } } if (reloadable) { @@ -829,6 +847,11 @@ File act = (File)it.next(); classp.add(act.isDirectory() ? (Object)act : new JarFile(act)); } + + if (loaders.isEmpty()) { + loaders.add (Module.class.getClassLoader()); + } + try { classloader = new OneModuleClassLoader(classp, (ClassLoader[])loaders.toArray(new ClassLoader[loaders.size()])); } catch (IllegalArgumentException iae) { @@ -839,6 +862,23 @@ } oldClassLoaders.add(classloader); } + + /** Scans content of a directory */ + private void scanFilesInADir (File patchdir, List classp) throws IOException { + if (!patchdir.isDirectory()) { + return; + } + File[] jars = patchdir.listFiles(Util.jarFilter()); + if (jars != null) { + for (int j = 0; j < jars.length; j++) { + ev.log(Events.PATCH, jars[j]); + classp.add(new JarFile(jars[j])); + } + } else { + Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir); + } + } + /** Turn off the classloader and release all resources. */ void classLoaderDown() { if (isFixed()) return; // don't touch it Index: nb_all/core/src/org/netbeans/core/modules/ModuleManager.java =================================================================== RCS file: /cvs/core/src/org/netbeans/core/modules/ModuleManager.java,v retrieving revision 1.35 diff -u -r1.35 ModuleManager.java --- nb_all/core/src/org/netbeans/core/modules/ModuleManager.java 5 Aug 2002 15:29:16 -0000 1.35 +++ nb_all/core/src/org/netbeans/core/modules/ModuleManager.java 13 Aug 2002 23:37:52 -0000 @@ -31,6 +31,7 @@ import org.openide.modules.SpecificationVersion; import org.openide.modules.Dependency; import org.openide.ErrorManager; +import org.netbeans.ProxyClassLoader; /** Manages a collection of modules. * Must use {@link #mutex} to access its important methods. @@ -56,7 +57,7 @@ private final ModuleInstaller installer; - private SystemClassLoader classLoader = new SystemClassLoader(new ClassLoader[0], Collections.EMPTY_SET); + private SystemClassLoader classLoader = new SystemClassLoader(new ClassLoader[] {ModuleManager.class.getClassLoader()}, Collections.EMPTY_SET); private final Object classLoaderLock = "ModuleManager.classLoaderLock"; // NOI18N private final Events ev; @@ -233,13 +234,16 @@ } parents.add(m.getClassLoader()); } + if (parents.isEmpty()) { + parents.add (ModuleManager.class.getClassLoader()); + } ClassLoader[] parentCLs = (ClassLoader[])parents.toArray(new ClassLoader[parents.size()]); SystemClassLoader nue; try { nue = new SystemClassLoader(parentCLs, modules); } catch (IllegalArgumentException iae) { Util.err.notify(iae); - nue = new SystemClassLoader(new ClassLoader[0], Collections.EMPTY_SET); + nue = new SystemClassLoader(new ClassLoader[] {ModuleManager.class.getClassLoader()}, Collections.EMPTY_SET); } synchronized (classLoaderLock) { classLoader = nue; Index: nb_all/core/src/org/netbeans/core/modules/ProxyClassLoader.java =================================================================== RCS file: nb_all/core/src/org/netbeans/core/modules/ProxyClassLoader.java diff -N nb_all/core/src/org/netbeans/core/modules/ProxyClassLoader.java --- nb_all/core/src/org/netbeans/core/modules/ProxyClassLoader.java 29 Jul 2002 10:11:16 -0000 1.14 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,527 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.core.modules; - -import java.util.*; -import java.net.URL; -import java.io.IOException; -import org.openide.ErrorManager; -import org.openide.util.WeakSet; -import org.openide.util.enum.*; - -/** - * A class loader that has multiple parents and uses them for loading - * classes and resources. It can be used in tree hierarchy, where it - * can exploit its capability to not throw ClassNotFoundException when - * communicating with other ProxyClassLoader. - * It itself doesn't load classes or resources, but allows subclasses - * to add such functionality. - * - * @author Petr Nejedly, Jesse Glick - */ -public class ProxyClassLoader extends ClassLoader { - - // Map - // packages are given in format "org/netbeans/modules/foo/" - private final Map domainsByPackage = new HashMap(); - // Map - private HashMap packages = new HashMap(); - - // All parentf of this classloader, including their parents recursively - private ClassLoader[] parents; - - /** if true, we have been destroyed */ - private boolean dead = false; - - /** Create a multi-parented classloader. - * @param parents list of parent classloaders. - * @throws IllegalArgumentException if there are any nulls or duplicate - * parent loaders or cycles. - */ - public ProxyClassLoader( ClassLoader[] parents ) { - if (parents.length == 0) { - parents = new ClassLoader[] { ProxyClassLoader.class.getClassLoader() }; - } - - Set check = new HashSet(Arrays.asList(parents)); // Set - if (check.size() < parents.length) throw new IllegalArgumentException("duplicate parents"); // NOI18N - if (check.contains(null)) throw new IllegalArgumentException("null parent"); // NOI18N - - this.parents = coalesceParents(parents); - } - - // this is used only by system classloader, maybe we can redesign it a bit - // to live without this functionality, then destroy may also go away - /** Add new parents dynamically. - * @param parents the new parents to add (append to list) - * @throws IllegalArgumentException in case of a null or cyclic parent (duplicate OK) - */ - public synchronized void append(ClassLoader[] nueparents) throws IllegalArgumentException { - // XXX should this be synchronized? - if (nueparents == null) throw new IllegalArgumentException("null parents array"); // NOI18N - for (int i = 0; i < nueparents.length; i++) { - if (nueparents[i] == null) throw new IllegalArgumentException("null parent"); // NOI18N - } - - parents = coalesceAppend(parents, nueparents); - } - - - - /** Try to destroy this classloader. - * Subsequent attempts to use it will log an error (at most one though). - */ - public void destroy() { - dead = true; - } - - private void zombieCheck(String hint) { - if (dead) { - IllegalStateException ise = new IllegalStateException("WARNING - attempting to use a zombie classloader " + this + " on " + hint + ". This means classes from a disabled module are still active. May or may not be a problem."); // NOI18N - ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ise); - // don't warn again for same loader... this was enough - dead = false; - } - } - - /** - * Loads the class with the specified name. The implementation of - * this method searches for classes in the following order:

- *

    - *
  1. Calls {@link #findLoadedClass(String)} to check if the class has - * already been loaded. - *
  2. Checks the caches whether another class from the same package - * was already loaded and uses the same classloader - *
  3. Tries to find the class using parent loaders in their order. - *
  4. Calls the {@link #simpleFindClass(String,String)} method to find - * the class using this class loader. - *
- * - * @param name the name of the class - * @param resolve if true then resolve the class - * @return the resulting Class object - * @exception ClassNotFoundException if the class could not be found - */ - protected synchronized final Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - zombieCheck(name); - // XXX this section is a candidate for local optimization: - String filename = name.replace('.', '/').concat(".class"); // NOI18N - int idx = filename.lastIndexOf('/'); // NOI18N - if (idx == -1) throw new ClassNotFoundException("Will not load classes from default package"); // NOI18N - String pkg = filename.substring(0, idx + 1); // "org/netbeans/modules/foo/" - Class c = smartLoadClass(name, filename, pkg); - if(c == null) throw new ClassNotFoundException(name); - if (resolve) resolveClass(c); - return c; - } - - /** This ClassLoader can't load anything itself. Subclasses - * may override this method to do some class loading themselves. The - * implementation should not throw any exception, just return - * null if it can't load required class. - * - * @param name the name of the class - * @param fileName the expected filename of the classfile, like - * java/lang/Object.class for java.lang.Object - * The ClassLoader implementation may or may not use it, depending - * whether it is usefull to it. - * @return the resulting Class object or null - */ - protected Class simpleFindClass(String name, String fileName) { - return null; - } - - - /** - * Finds the resource with the given name. The implementation of - * this method searches for resources in the following order:

- *

    - *
  1. Checks the caches whether another resource or class from the same - * package was already loaded and uses the same classloader. - *
  2. Tries to find the resources using parent loaders in their order. - *
  3. Calls the {@link #findResource(String)} method to find - * the resources using this class loader. - *
- * - * @param name a "/"-separated path name that identifies the resource. - * @return a URL for reading the resource, or null if - * the resource could not be found. - * @see #findResource(String) - */ - public final URL getResource(final String name) { - zombieCheck(name); - - final int slashIdx = name.lastIndexOf('/'); - if (slashIdx == -1) return null; // won't load from the default package - final String pkg = name.substring(0, slashIdx + 1); - - if (isSpecialResource(pkg)) { - // Disable domain cache for this one, do a simple check. - for (int i = 0; i < parents.length; i++) { - if (!shouldDelegateResource(pkg, parents[i])) continue; - URL u; - if (parents[i] instanceof ProxyClassLoader) { - u = ((ProxyClassLoader)parents[i]).findResource(name); - } else { - u = parents[i].getResource(name); - } - if (u != null) return u; - } - return findResource(name); - } - - ClassLoader owner = (ClassLoader)domainsByPackage.get(pkg); - - if (owner != null) { // known package - // Note that shouldDelegateResource should already be true for this! - if (owner instanceof ProxyClassLoader) { - return ((ProxyClassLoader)owner).findResource(name); // we have its parents, skip them - } else { - return owner.getResource(name); // know nothing about this loader and his structure - } - } - - // virgin package - URL retVal = null; - for (int i = 0; i < parents.length; i++) { - owner = parents[i]; - if (!shouldDelegateResource(pkg, owner)) continue; - if (owner instanceof ProxyClassLoader) { - retVal = ((ProxyClassLoader)owner).findResource(name); // skip parents (checked already) - } else { - retVal = owner.getResource(name); // know nothing about this loader and his structure - } - if (retVal != null) { - domainsByPackage.put(pkg, owner); - return retVal; - } - } - - // try it ourself - retVal = findResource(name); - if (retVal != null) { - domainsByPackage.put(pkg, this); - } - return retVal; - } - - /** This ClassLoader can't load anything itself. Subclasses - * may override this method to do some resource loading themselves. - * - * @param name the resource name - * @return a URL for reading the resource, or null - * if the resource could not be found. - */ - protected URL findResource(String name) { - return null; - } - - /** - * Finds all the resource with the given name. The implementation of - * this method uses the {@link #simpleFindResources(String)} method to find - * all the resources available from this classloader and adds all the - * resources from all the parents. - * - * @param name the resource name - * @return an Enumeration of URLs for the resources - * @throws IOException if I/O errors occur - */ - protected final synchronized Enumeration findResources(String name) throws IOException { - zombieCheck(name); - final int slashIdx = name.lastIndexOf('/'); - if (slashIdx == -1) return EmptyEnumeration.EMPTY; // won't load from the default package - final String pkg = name.substring(0, slashIdx + 1); - - // Don't bother optimizing this call by domains. - // It is mostly used for resources for which isSpecialResource would be true anyway. - Enumeration[] es = new Enumeration[parents.length + 1]; - for (int i = 0; i < parents.length; i++) { - if (!shouldDelegateResource(pkg, parents[i])) { - es[i] = EmptyEnumeration.EMPTY; - continue; - } - if (parents[i] instanceof ProxyClassLoader) { - es[i] = ((ProxyClassLoader)parents[i]).simpleFindResources(name); - } else { - es[i] = parents[i].getResources(name); - } - } - es[parents.length] = simpleFindResources(name); - // Should not be duplicates, assuming the parent loaders are properly distinct - // from one another and do not overlap in JAR usage, which they ought not. - // Anyway MetaInfServicesLookup, the most important client of this method, does - // its own duplicate filtering already. - return new SequenceEnumeration(new ArrayEnumeration(es)); - } - - /** This ClassLoader can't load anything itself. Subclasses - * may override this method to do some resource loading themselves, this - * implementation simply delegates to findResources method of the superclass - * that should return empty Enumeration. - * - * @param name the resource name - * @return an Enumeration of URLs for the resources - * @throws IOException if I/O errors occur - */ - protected Enumeration simpleFindResources(String name) throws IOException { - return super.findResources(name); - } - - - /** - * Returns a Package that has been defined by this class loader or any - * of its parents. - * - * @param name the package name - * @return the Package corresponding to the given name, or null if not found - */ - protected Package getPackage(String name) { - zombieCheck(name); - - int idx = name.lastIndexOf('.'); - if (idx == -1) return null; - String spkg = name.substring(0, idx + 1).replace('.', '/'); - - synchronized (packages) { - Package pkg = (Package)packages.get(name); - if (pkg != null) return pkg; - - for (int i = 0; i < parents.length; i++) { - ClassLoader par = parents[i]; - if (par instanceof ProxyClassLoader && shouldDelegateResource(spkg, par)) { - pkg = ((ProxyClassLoader)par).getPackage(name); - if(pkg != null) break; - } - } - // do our own lookup - if (pkg == null) pkg = super.getPackage(name); - // cache results - if (pkg != null) packages.put(name, pkg); - - return pkg; - } - } - - /** This is here just for locking serialization purposes. - * Delegates to super.definePackage with proper locking. - */ - protected Package definePackage(String name, String specTitle, - String specVersion, String specVendor, String implTitle, - String implVersion, String implVendor, URL sealBase ) - throws IllegalArgumentException { - synchronized (packages) { - return super.definePackage (name, specTitle, specVersion, specVendor, implTitle, - implVersion, implVendor, sealBase); - } - } - - /** - * Returns all of the Packages defined by this class loader and its parents. - * - * @return the array of Package objects defined by this - * ClassLoader - */ - protected synchronized Package[] getPackages() { - zombieCheck(null); - Map all = new HashMap(); // Map - addPackages(all, super.getPackages()); - for (int i = 0; i < parents.length; i++) { - ClassLoader par = parents[i]; - if (par instanceof ProxyClassLoader) { - // XXX should ideally use shouldDelegateResource here... - addPackages(all, ((ProxyClassLoader)par).getPackages()); - } - } - synchronized (packages) { - Iterator it = all.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = (Map.Entry)it.next(); - Object name = entry.getKey(); - if (! packages.containsKey(name)) { - packages.put(name, entry.getValue()); - } - } - } - return (Package[])all.values().toArray(new Package[all.size()]); - } - - public Package getPackageAccessibly(String name) { - return getPackage(name); - } - - public Package[] getPackagesAccessibly() { - return getPackages(); - } - - - - /** Coalesce parent classloaders into an optimized set. - * This means that all parents of the specified classloaders - * are also added recursively, removing duplicates along the way. - * Search order should be preserved (parents before children, stable w.r.t. inputs). - * @param loaders list of suggested parents (no nulls or duplicates permitted) - * @return optimized list of parents (no nulls or duplicates) - * @throws IllegalArgumentException if there are cycles - */ - private ClassLoader[] coalesceParents(ClassLoader[] loaders) throws IllegalArgumentException { - int likelySize = loaders.length * 3 + 1; - Set resultingUnique = new HashSet(likelySize); // Set - List resulting = new ArrayList(likelySize); // List - for (int i = 0; i < loaders.length; i++) { - addRec(resultingUnique, resulting, loaders[i]); - } - ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]); - return ret; - } - - /** Coalesce a new set of loaders into the existing ones. - */ - private ClassLoader[] coalesceAppend(ClassLoader[] existing, ClassLoader[] appended) throws IllegalArgumentException { - int likelySize = existing.length + 3; - Set resultingUnique = new HashSet(likelySize); - List existingL = Arrays.asList(existing); - resultingUnique.addAll(existingL); - if (resultingUnique.containsAll(Arrays.asList(appended))) { - // No change required. - return existing; - } - List resulting = new ArrayList(likelySize); - resulting.addAll(existingL); - int fromIdx = resulting.size(); - for (int i = 0; i < appended.length; i++) { - addRec(resultingUnique, resulting, appended[i]); - } - ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]); - return ret; - } - - private void addRec(Set resultingUnique, List resulting, ClassLoader loader) throws IllegalArgumentException { - if (loader == this) throw new IllegalArgumentException("cycle in parents"); // NOI18N - if (resultingUnique.contains(loader)) return; - if (loader instanceof ProxyClassLoader) { - ClassLoader[] parents = ((ProxyClassLoader)loader).parents; - for (int i = 0; i < parents.length; i++) { - addRec(resultingUnique, resulting, parents[i]); - } - } - resultingUnique.add(loader); - resulting.add(loader); - } - - /** A method that finds a class either in itself or in parents. - * It uses dual signaling for class not found: it can either return null - * or throw CNFE itself. - * @param name class name, e.g. "org.netbeans.modules.foo.Clazz" - * @param fileName resource name, e.g. "org/netbeans/modules/foo/Clazz.class" - * @param pkg package component, e.g. "org/netbeans/modules/foo/" - * @return a class or null if not found. It can also throw an exception. - * @throws ClassNotFoundException in case it doesn't found a class - * and a parent eglible for loading it thrown it already. - */ - private final Class smartLoadClass(String name, String fileName, String pkg) throws ClassNotFoundException { - // First, check if the class has already been loaded - Class c = findLoadedClass(name); - if(c != null) return c; - - final ClassLoader owner = isSpecialResource(pkg) ? null : (ClassLoader)domainsByPackage.get(pkg); - if (owner == this) { - return simpleFindClass(name,fileName); - } - if (owner != null) { - // Note that shouldDelegateResource should already be true as we hit this pkg before. - if (owner instanceof ProxyClassLoader) { - return ((ProxyClassLoader)owner).fullFindClass(name,fileName); - } else { - return owner.loadClass(name); // May throw CNFE, will be propagated - } - } - - // Virgin package, do the parent scan - c = loadInOrder(name, fileName, pkg); - - if (c != null) { - final ClassLoader owner2 = c.getClassLoader(); // who got it? - domainsByPackage.put(pkg, owner2); - } - return c; - } - - - private final Class loadInOrder( String name, String fileName, String pkg ) throws ClassNotFoundException { - ClassNotFoundException cached = null; - for (int i = 0; i < parents.length; i++) { - ClassLoader par = parents[i]; - if (!shouldDelegateResource(pkg, par)) continue; - if (par instanceof ProxyClassLoader) { - Class c = ((ProxyClassLoader)par).fullFindClass(name,fileName); - if (c != null) return c; - } else { - try { - return par.loadClass(name); - } catch( ClassNotFoundException cnfe ) { - cached = cnfe; - } - } - } - - Class c = simpleFindClass(name,fileName); // Try it ourselves - if (c != null) return c; - if (cached != null) throw cached; - return null; - } - - private synchronized Class fullFindClass(String name, String fileName) { - Class c = findLoadedClass(name); - return (c == null) ? simpleFindClass(name, fileName) : c; - } - - private void addPackages(Map all, Package[] pkgs) { - // Would be easier if Package.equals() was just defined sensibly... - for (int i = 0; i < pkgs.length; i++) { - all.put(pkgs[i].getName(), pkgs[i]); - } - } - - /** Test whether a given resource name is something that any JAR might - * have, and for which the domain cache should be disabled. - * The result must not change from one call to the next with the same argument. - * By default the domain cache is disabled only for META-INF/* JAR information. - * @param pkg the package component of the resource path ending with a slash, - * e.g. "org/netbeans/modules/foo/" - * @return true if it is a special resource, false for normal domain-cached resource - * @since org.netbeans.core/1 1.3 - */ - protected boolean isSpecialResource(String pkg) { - if (pkg.startsWith("META-INF/")) return true; // NOI18N - return false; - } - - /** Test whether a given resource request (for a class or not) should be - * searched for in the specified parent classloader or not. - * The result must not change from one call to the next with the same arguments. - * By default, always true. Subclasses may override to "mask" certain - * packages from view, possibly according to the classloader chain. - * @param pkg the package component of the resource path ending with a slash, - * e.g. "org/netbeans/modules/foo/" - * @param parent a classloader which is a direct or indirect parent of this one - * @return true if the request should be delegated to this parent; false to - * only search elsewhere (other parents, this loader's own namespace) - * @since org.netbeans.core/1 1.3 - */ - protected boolean shouldDelegateResource(String pkg, ClassLoader parent) { - return true; - } - -} Index: nb_all/core/test/cfg-unit.xml =================================================================== RCS file: /cvs/core/test/cfg-unit.xml,v retrieving revision 1.22 diff -u -r1.22 cfg-unit.xml --- nb_all/core/test/cfg-unit.xml 21 Jun 2002 15:16:47 -0000 1.22 +++ nb_all/core/test/cfg-unit.xml 13 Aug 2002 23:37:52 -0000 @@ -57,6 +57,7 @@ + Index: nb_all/core/test/unit/src/org/netbeans/PatchByteCodeTest.java =================================================================== RCS file: nb_all/core/test/unit/src/org/netbeans/PatchByteCodeTest.java diff -N nb_all/core/test/unit/src/org/netbeans/PatchByteCodeTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/core/test/unit/src/org/netbeans/PatchByteCodeTest.java 13 Aug 2002 23:37:53 -0000 @@ -0,0 +1,194 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans; + +import junit.framework.AssertionFailedError; +import junit.textui.TestRunner; +import org.netbeans.junit.*; +import java.io.InputStream; +import java.lang.reflect.*; + +/** Test patching of openide.jar byte code for compatibility. + * @author Jaroslav Tulach + */ +public class PatchByteCodeTest extends NbTestCase { + + public PatchByteCodeTest(String name) { + super(name); + } + + public static void main(String[] args) { + TestRunner.run(new NbTestSuite(PatchByteCodeTest.class)); + } + + protected void setUp() throws Exception { + super.setUp(); + } + + public void testBeanTreeViewLoad () throws Exception { + checkPatching ( + "org.openide.explorer.view.BeanTreeView", + "data/BeanTreeView.clazz", + null + ); + } + + public void testCompilerGroupLoad () throws Exception { + checkPatching ( + "org.openide.compiler.CompilerGroup", + "data/CompilerGroup.clazz", + null + ); + + InputStream is = getClass ().getResourceAsStream ("data/CompilerGroup.clazz"); + assertNotNull ("Class has not been found", is); + + byte[] arr = new byte[is.available ()]; + int l = is.read (arr); + assertEquals ("Read exactly as much as expected", l, arr.length); + + + byte[] res = PatchByteCode.enhance(arr, null, new String[] { "addCompilerListener", "removeCompilerListener" } ); + PatchClassLoader loader = new PatchClassLoader ("org.openide.compiler.CompilerGroup", res, ClassLoader.getSystemClassLoader()); + + Class c = loader.loadClass ("org.openide.compiler.CompilerGroup"); + + Method m = c.getDeclaredMethod("addCompilerListener", new Class[] { org.openide.compiler.CompilerListener.class }); + assertTrue ("Is not final", !Modifier.isFinal (m.getModifiers ())); + + m = c.getDeclaredMethod("removeCompilerListener", new Class[] { org.openide.compiler.CompilerListener.class }); + assertTrue ("Is not final", !Modifier.isFinal (m.getModifiers ())); + } + + public void testClassCanBeAlsoInstantiated () throws Exception { + Class c = checkPatching ( + Sample.class.getName (), + "Sample.class", + "java.lang.Throwable" + ); + + c.newInstance (); + } + + public void testPatchingOfFieldsAndMethodsToPublicAndNonFinal () throws Exception { + InputStream is = getClass ().getResourceAsStream ("Sample.class"); + assertNotNull ("Class has not been found", is); + + byte[] arr = new byte[is.available ()]; + int l = is.read (arr); + assertEquals ("Read exactly as much as expected", l, arr.length); + + + + byte[] res = PatchByteCode.enhance(arr, null, new String[] { "member", "field", "method", "staticmethod" } ); + PatchClassLoader loader = new PatchClassLoader (Sample.class.getName (), res, ClassLoader.getSystemClassLoader()); + + Class c = loader.loadClass (Sample.class.getName ()); + + assertTrue ("Class should be public", Modifier.isPublic (c.getModifiers())); + + Method m = c.getDeclaredMethod("method", new Class[0]); + assertNotNull ("Mehtod method is there", m); + assertTrue ("And is public", Modifier.isPublic (m.getModifiers())); + assertTrue ("And is not final", !Modifier.isFinal(m.getModifiers ())); + assertTrue ("And is not static", !Modifier.isStatic(m.getModifiers())); + assertTrue ("And is not synchronzied", !Modifier.isSynchronized(m.getModifiers())); + + m = c.getDeclaredMethod("member", new Class[] { Object.class }); + assertNotNull ("Member method is there", m); + assertTrue ("And is public", Modifier.isPublic (m.getModifiers())); + assertTrue ("And is not final", !Modifier.isFinal(m.getModifiers ())); + assertTrue ("And is not static", !Modifier.isStatic(m.getModifiers())); + assertTrue ("And is synchronzied", Modifier.isSynchronized(m.getModifiers())); + + m = c.getDeclaredMethod("staticmethod", new Class[] { }); + assertNotNull ("Member method is there", m); + assertTrue ("And is public", Modifier.isPublic (m.getModifiers())); + assertTrue ("And is not final", !Modifier.isFinal(m.getModifiers ())); + assertTrue ("And is not static", Modifier.isStatic(m.getModifiers())); + assertTrue ("And is not synchronzied", !Modifier.isSynchronized(m.getModifiers())); + + java.lang.reflect.Field f; + + f = c.getDeclaredField("member"); + assertNotNull ("Really exists", f); + assertTrue ("Is public", Modifier.isPublic (f.getModifiers ())); + assertTrue ("Is not final", !Modifier.isFinal (f.getModifiers ())); + assertTrue ("Is static", Modifier.isStatic (f.getModifiers ())); + + f = c.getDeclaredField("field"); + assertNotNull ("Really exists", f); + assertTrue ("Is public", Modifier.isPublic (f.getModifiers ())); + assertTrue ("Is not final", !Modifier.isFinal (f.getModifiers ())); + assertTrue ("Is static", !Modifier.isStatic (f.getModifiers ())); + + } + + + private Class checkPatching ( + String className, String resource, String superclass + ) throws Exception { + if (superclass == null) { + superclass = PatchByteCodeTest.class.getName (); + } + + InputStream is = getClass ().getResourceAsStream (resource); + assertNotNull ("Resource has been found " + resource, is); + + byte[] arr = new byte[is.available ()]; + int l = is.read (arr); + assertEquals ("Read exactly as much as expected", l, arr.length); + + byte[] res = PatchByteCode.enhance(arr, superclass.replace ('.', '/')); + PatchClassLoader loader = new PatchClassLoader (className, res); + + Class c = loader.loadClass (className); + + assertEquals ( + "Superclass changed appropriately", + superclass, + c.getSuperclass().getName () + ); + + return c; + } + + + private static final class PatchClassLoader extends ClassLoader { + private String res; + private byte[] arr; + + public PatchClassLoader (String res, byte[] arr) { + this (res, arr, PatchClassLoader.class.getClassLoader ()); + } + + public PatchClassLoader (String res, byte[] arr, ClassLoader c) { + super (c); + + this.res = res; + this.arr = arr; + } + + protected synchronized Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + if (res.equals (name)) { + byte[] patch = PatchByteCode.patch(arr); + + return defineClass (name, patch, 0, patch.length); + } else { + return super.loadClass (name, resolve); + } + } + } +} Index: nb_all/core/test/unit/src/org/netbeans/Sample.java =================================================================== RCS file: nb_all/core/test/unit/src/org/netbeans/Sample.java diff -N nb_all/core/test/unit/src/org/netbeans/Sample.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/core/test/unit/src/org/netbeans/Sample.java 13 Aug 2002 23:37:53 -0000 @@ -0,0 +1,40 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans; + +import junit.framework.AssertionFailedError; +import junit.textui.TestRunner; +import org.netbeans.junit.*; +import java.io.InputStream; +import java.lang.reflect.*; + +/** Sample class to pass to PatchByteCodeTest to see what changes can be done. + */ +class Sample extends Object { + private static Object member; + private final Object field = null; + + public Sample () { + } + + protected synchronized void member (Object x) { + } + + private final Object method () { + return null; + } + + protected static void staticmethod () { + } +} Index: nb_all/core/test/unit/src/org/netbeans/data/BeanTreeView.clazz =================================================================== RCS file: nb_all/core/test/unit/src/org/netbeans/data/BeanTreeView.clazz diff -N nb_all/core/test/unit/src/org/netbeans/data/BeanTreeView.clazz Binary files /dev/null and BeanTreeView.clazz differ Index: nb_all/core/test/unit/src/org/netbeans/data/CompilerGroup.clazz =================================================================== RCS file: nb_all/core/test/unit/src/org/netbeans/data/CompilerGroup.clazz diff -N nb_all/core/test/unit/src/org/netbeans/data/CompilerGroup.clazz Binary files /dev/null and CompilerGroup.clazz differ Index: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbEnhanceClass.java =================================================================== RCS file: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbEnhanceClass.java diff -N nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbEnhanceClass.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbEnhanceClass.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,217 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.nbbuild; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Iterator; +// IMPORTANT! You may need to mount ant.jar before this class will +// compile. So mount the JAR modules/ext/ant-1.4.1.jar (NOT modules/ant.jar) +// from your IDE installation directory in your Filesystems before +// continuing to ensure that it is in your classpath. + +import org.apache.tools.ant.*; +import org.apache.tools.ant.types.*; + +/** + * @author Jaroslav Tulach + */ +public class NbEnhanceClass extends Task { + /* Path to library containing the patch method */ + private File patchLibrary; + public void setLibrary (File f) { + patchLibrary = f; + } + + /* Name of class with patch method */ + private String patchClass = "org.netbeans.PatchByteCode"; + public void setPatchClass (String f) { + patchClass = f; + } + + /** Name of the method to call. Must have byte[] array argument and return the same + */ + private String enhanceMethod = "enhance"; + public void setEnhanceMethod (String f) { + enhanceMethod = f; + } + + /* Base dir to find classes relative to */ + private File basedir; + public void setBasedir (File f) { + basedir = f; + } + + /* The class to change its super class and the value of the super class. + */ + public static class Patch { + String clazz; + String nbSuperClass; + ArrayList members; + + + /** Class in form of java/lang/Object */ + public void setClass (String s) { + clazz = s; + } + /** Class in form of java/lang/Object */ + public void setSuper (String s) { + nbSuperClass = s; + } + + public Object createMember () { + Member m = new Member(); + if (members == null) { + members = new ArrayList (); + } + members.add (m); + return m; + } + + public static final class Member extends Object { + String name; + + public void setName (String s) { + name = s; + } + } + } + private ArrayList patches = new ArrayList (); // List + public Patch createPatch () { + Patch n = new Patch (); + patches.add(n); + return n; + } + + + public void execute() throws BuildException { + if (basedir == null) { + throw new BuildException ("Attribute basedir must be specified"); + } + + if (patches.isEmpty()) { + // no work + return; + } + + // + // Initialize the method + // + + ClassLoader cl; + if (patchLibrary == null) { + log ("Loading patch class from task loader"); + cl = getClass ().getClassLoader(); + } else { + try { + cl = new URLClassLoader (new URL[] { patchLibrary.toURL() }); + } catch (java.net.MalformedURLException ex) { + throw new BuildException (ex); + } + } + + java.lang.reflect.Method m; + try { + Class c = cl.loadClass (patchClass); + m = c.getMethod(enhanceMethod, new Class[] { byte[].class, String.class, String[].class }); + if (m.getReturnType() != byte[].class) { + throw new BuildException ("Method does not return byte[]: " + m); + } + } catch (Exception ex) { + throw new BuildException ("Cannot initialize class " + patchClass + " and method " + enhanceMethod, ex); + } + + /* + try { + log ("Testing method " + m); + byte[] res = (byte[])m.invoke (null, new Object[] { new byte[0], "someString" }); + } catch (Exception ex) { + throw new BuildException ("Exception during test invocation of the method", ex); + } + */ + + // + // Ok we have the method and we can do the patching + // + + Iterator it = patches.iterator(); + while (it.hasNext()) { + Patch p = (Patch)it.next (); + + if (p.clazz == null) { + throw new BuildException ("Attribute class must be specified"); + } + + File f = new File (basedir, p.clazz + ".class"); + if (!f.exists ()) { + throw new BuildException ("File " + f + " for class " + p.clazz + " does not exists"); + } + + byte[] arr = new byte[(int)f.length()]; + try { + FileInputStream is = new FileInputStream (f); + if (arr.length != is.read (arr)) { + throw new BuildException ("Not all bytes read"); + } + is.close (); + } catch (IOException ex) { + throw new BuildException ("Cannot read file " + f, ex); + } + + String[] members; + if (p.members != null) { + members = new String[p.members.size ()]; + Iterator myIt = p.members.iterator(); + int i = 0; + while (myIt.hasNext ()) { + members[i++] = ((Patch.Member)myIt.next ()).name; + } + } else { + members = null; + } + + + byte[] out; + try { + out = (byte[])m.invoke (null, new Object[] { arr, p.nbSuperClass, members }); + if (out == null) { + // no patching needed + continue; + } + } catch (Exception ex) { + throw new BuildException (ex); + } + + if (p.nbSuperClass != null) { + log ("Enhanced " + f + " to have alternate superclass " + p.nbSuperClass + " and be public"); + } else { + log ("Enhanced " + f + " to be public"); + } + + try { + FileOutputStream os = new FileOutputStream (f); + os.write (out); + os.close (); + } catch (IOException ex) { + throw new BuildException ("Cannot overwrite file " + f, ex); + } + } + } + +} Index: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchClass.java =================================================================== RCS file: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchClass.java diff -N nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchClass.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchClass.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,191 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.nbbuild; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.jar.JarFile; +// IMPORTANT! You may need to mount ant.jar before this class will +// compile. So mount the JAR modules/ext/ant-1.4.1.jar (NOT modules/ant.jar) +// from your IDE installation directory in your Filesystems before +// continuing to ensure that it is in your classpath. + +import org.apache.tools.ant.*; +import org.apache.tools.ant.types.*; + +/** + * @author Jaroslav Tulach + */ +public class NbPatchClass extends Task { + /* Path to library containing the patch method */ + private File patchLibrary; + public void setLibrary (File f) { + patchLibrary = f; + } + + /* Name of class with patch method */ + private String patchClass = "org.netbeans.PatchByteCode"; + public void setPatchClass (String f) { + patchClass = f; + } + + /** Name of the method to call. Must have byte[] array argument and return the same + */ + private String patchMethod = "patch"; + public void setPatchMethod (String f) { + patchMethod = f; + } + + /** Source JAR to extract. + */ + private File sourceJar; + public void setSource (File f) { + sourceJar = f; + } + + /* Base dir to find classes relative to */ + private File targetdir; + public void setTargetdir (File f) { + targetdir = f; + } + + public void execute() throws BuildException { + if (targetdir == null) { + throw new BuildException ("Attribute targetdir must be specified"); + } + + if (sourceJar == null) { + throw new BuildException ("Attribute source must be specified"); + } + + + JarFile jar; + + try { + jar = new JarFile (sourceJar); + } catch (IOException ex) { + throw new BuildException ("Problem initializing file " + sourceJar, ex); + } + + // + // Initialize the method + // + + log ("Initilalizing patching " + patchClass + '.' + patchMethod); + + ClassLoader cl; + if (patchLibrary == null) { + log ("Loading patch class from task loader"); + cl = getClass ().getClassLoader(); + } else { + try { + cl = new URLClassLoader (new URL[] { patchLibrary.toURL() }); + } catch (java.net.MalformedURLException ex) { + throw new BuildException (ex); + } + } + + java.lang.reflect.Method m; + try { + Class c = cl.loadClass (patchClass); + m = c.getMethod(patchMethod, new Class[] { byte[].class }); + if (m.getReturnType() != byte[].class) { + throw new BuildException ("Method does not return byte[]: " + m); + } + } catch (Exception ex) { + throw new BuildException ("Cannot initialize class " + patchClass + " and method " + patchMethod, ex); + } + + /* + try { + log ("Testing method " + m); + byte[] res = (byte[])m.invoke (null, new Object[] { new byte[0], "someString" }); + } catch (Exception ex) { + throw new BuildException ("Exception during test invocation of the method", ex); + } + */ + + // + // Ok we have the method and we can do the patching + // + + java.util.Enumeration it = jar.entries(); + while (it.hasMoreElements()) { + java.util.jar.JarEntry e = (java.util.jar.JarEntry)it.nextElement (); + + int size = (int)e.getSize(); + if (size <= 4) { + // not interesting entry + continue; + } + + byte[] arr = new byte[size]; + + try { + java.io.InputStream is = jar.getInputStream(e); + + int indx = 0; + while (indx < arr.length) { + int read = is.read (arr, indx, arr.length - indx); + if (read == -1) { + throw new BuildException("Entry: " + e.getName () + " size should be: " + size + " but was read just: " + indx); + } + indx += read; + } + } catch (IOException ex) { + throw new BuildException (ex); + } + + byte[] original = (byte[])arr.clone (); + byte[] out; + try { + out = (byte[])m.invoke (null, new Object[] { arr }); + } catch (java.lang.reflect.InvocationTargetException ex) { + throw new BuildException (ex.getTargetException()); + } catch (Exception ex) { + throw new BuildException (ex); + } + + if (java.util.Arrays.equals (original, out)) { + // no patching, go on + continue; + } + + File f = new File (targetdir, e.getName ().replace ('/', File.separatorChar)); + if (f.exists () && f.lastModified() > sourceJar.lastModified ()) { + // if the file is newer + continue; + } + + f.getParentFile().mkdirs(); + + log ("Writing patched file " + f); + + try { + FileOutputStream os = new FileOutputStream (f); + os.write (out); + os.close (); + } catch (IOException ex) { + throw new BuildException ("Cannot write file " + f, ex); + } + } + } + +} Index: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchSuperClass.java =================================================================== RCS file: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchSuperClass.java diff -N nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchSuperClass.java --- nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchSuperClass.java 19 Jul 2002 07:27:45 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,186 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.nbbuild; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Iterator; -// IMPORTANT! You may need to mount ant.jar before this class will -// compile. So mount the JAR modules/ext/ant-1.4.1.jar (NOT modules/ant.jar) -// from your IDE installation directory in your Filesystems before -// continuing to ensure that it is in your classpath. - -import org.apache.tools.ant.*; -import org.apache.tools.ant.types.*; - -/** - * @author Jaroslav Tulach - */ -public class NbPatchSuperClass extends Task { - /* Path to library containing the patch method */ - private File patchLibrary; - public void setPatchLibrary (File f) { - patchLibrary = f; - } - - /* Name of class with patch method */ - private String patchClass = "org.netbeans.PatchByteCode"; - public void setPatchClass (String f) { - patchClass = f; - } - - /** Name of the method to call. Must have byte[] array argument and return the same - */ - private String patchMethod = "enhance"; - public void setPatchMethod (String f) { - patchMethod = f; - } - - /* Base dir to find classes relative to */ - private File basedir; - public void setBasedir (File f) { - basedir = f; - } - - /* The class to change its super class and the value of the super class. - */ - public static class Patch { - String clazz; - String nbSuperClass; - /** Class in form of java/lang/Object */ - public void setClass (String s) { - clazz = s; - } - /** Class in form of java/lang/Object */ - public void setSuper (String s) { - nbSuperClass = s; - } - } - private ArrayList patches = new ArrayList (); // List - public Patch createPatch () { - Patch n = new Patch (); - patches.add(n); - return n; - } - - - public void execute() throws BuildException { - if (basedir == null) { - throw new BuildException ("Attribute basedir must be specified"); - } - - if (patches.isEmpty()) { - // no work - return; - } - - // - // Initialize the method - // - - log ("Initilalizing patching " + patchClass + '.' + patchMethod); - - ClassLoader cl; - if (patchLibrary == null) { - log ("Loading patch class from task loader"); - cl = getClass ().getClassLoader(); - } else { - try { - cl = new URLClassLoader (new URL[] { patchLibrary.toURL() }); - } catch (java.net.MalformedURLException ex) { - throw new BuildException (ex); - } - } - - java.lang.reflect.Method m; - try { - Class c = cl.loadClass (patchClass); - m = c.getMethod(patchMethod, new Class[] { byte[].class, String.class }); - if (m.getReturnType() != byte[].class) { - throw new BuildException ("Method does not return byte[]: " + m); - } - } catch (Exception ex) { - throw new BuildException ("Cannot initialize class " + patchClass + " and method " + patchMethod, ex); - } - - /* - try { - log ("Testing method " + m); - byte[] res = (byte[])m.invoke (null, new Object[] { new byte[0], "someString" }); - } catch (Exception ex) { - throw new BuildException ("Exception during test invocation of the method", ex); - } - */ - - // - // Ok we have the method and we can do the patching - // - - Iterator it = patches.iterator(); - while (it.hasNext()) { - Patch p = (Patch)it.next (); - - if (p.clazz == null) { - throw new BuildException ("Attribute class must be specified"); - } - - File f = new File (basedir, p.clazz + ".class"); - if (!f.exists ()) { - throw new BuildException ("File " + f + " for class " + p.clazz + " does not exists"); - } - - byte[] arr = new byte[(int)f.length()]; - try { - FileInputStream is = new FileInputStream (f); - if (arr.length != is.read (arr)) { - throw new BuildException ("Not all bytes read"); - } - is.close (); - } catch (IOException ex) { - throw new BuildException ("Cannot read file " + f, ex); - } - - byte[] out; - try { - out = (byte[])m.invoke (null, new Object[] { arr, p.nbSuperClass }); - if (out == null) { - // no patching needed - continue; - } - } catch (Exception ex) { - throw new BuildException (ex); - } - - if (p.nbSuperClass != null) { - log ("Patch applied to " + f + " to have alternate superclass " + p.nbSuperClass + " and be public"); - } else { - log ("Patch applied to " + f + " to be public"); - } - - try { - FileOutputStream os = new FileOutputStream (f); - os.write (out); - os.close (); - } catch (IOException ex) { - throw new BuildException ("Cannot overwrite file " + f, ex); - } - } - } - -} Index: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Postprocess.java =================================================================== RCS file: /cvs/nbbuild/antsrc/org/netbeans/nbbuild/Postprocess.java,v retrieving revision 1.3 diff -u -r1.3 Postprocess.java --- nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Postprocess.java 15 Nov 2001 11:34:38 -0000 1.3 +++ nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Postprocess.java 13 Aug 2002 23:38:19 -0000 @@ -26,6 +26,7 @@ * though a little more customized for binary files. * * @author Jaroslav Tulach +* @deprecated No longer used. */ public class Postprocess extends Task { /** file to post process */ Index: nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Preprocess.java =================================================================== RCS file: /cvs/nbbuild/antsrc/org/netbeans/nbbuild/Preprocess.java,v retrieving revision 1.4 diff -u -r1.4 Preprocess.java --- nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Preprocess.java 27 Oct 2000 11:13:24 -0000 1.4 +++ nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Preprocess.java 13 Aug 2002 23:38:19 -0000 @@ -58,6 +58,7 @@ * more conservative changes. It should not be used as a general-purpose Java * preprocessor, we are not C++ programmers here! * @author Jaroslav Tulach, Jesse Glick +* @deprecated No longer used. */ public class Preprocess extends MatchingTask { /** the format of begining of substitution */ Index: nb_all/openide/.cvsignore =================================================================== RCS file: /cvs/openide/.cvsignore,v retrieving revision 1.18 diff -u -r1.18 .cvsignore --- nb_all/openide/.cvsignore 24 Jun 2002 18:48:31 -0000 1.18 +++ nb_all/openide/.cvsignore 13 Aug 2002 23:38:19 -0000 @@ -7,7 +7,6 @@ examplemodules examplemodulereload openide-13javac-workaround.jar -compatkit-work standalone nb-api-tutorial.zip openide.nbm Index: nb_all/openide/build.xml =================================================================== RCS file: /cvs/openide/build.xml,v retrieving revision 1.107 diff -u -r1.107 build.xml --- nb_all/openide/build.xml 6 Aug 2002 17:15:16 -0000 1.107 +++ nb_all/openide/build.xml 13 Aug 2002 23:38:19 -0000 @@ -27,8 +27,7 @@ - - + @@ -84,52 +83,124 @@ -->
- - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -188,7 +259,7 @@ - + @@ -213,21 +284,14 @@ + + + + + + + - - - - - - - - - - @@ -301,16 +365,6 @@ - @@ -882,7 +936,6 @@ - Index: nb_all/openide/api/doc/changes/apichanges.xml =================================================================== RCS file: /cvs/openide/api/doc/changes/apichanges.xml,v retrieving revision 1.85 diff -u -r1.85 apichanges.xml --- nb_all/openide/api/doc/changes/apichanges.xml 6 Aug 2002 13:09:58 -0000 1.85 +++ nb_all/openide/api/doc/changes/apichanges.xml 13 Aug 2002 23:38:19 -0000 @@ -106,6 +106,7 @@ + Deprecation of parts of MouseUtils.PopupMenuAdapter @@ -3940,6 +3941,8 @@

Binary Compatibility Kit

+

Binary Compatibility up to NetBeans 3.4

+

In most cases, when it is desirable from an architectural standpoint to change an API in an incompatible way, the standard Java mechanism of @deprecated tags in Javadoc suffices as a compromise: @@ -4002,6 +4005,17 @@ into an IDE installation that has had its lib/patches/openide-compat.jar removed, to ensure that they are not depending on the deprecated APIs.

+ +

Binary Compatibility after NetBeans 3.4

+ +

+ In releases after 3.4 (expected 4.0), the system used is slightly + different, though the effect is similar. + lib/openide-compat.jar is now the compatibility JAR + location. It contains fake superclasses for some classes; the fake + superclasses will be inserted into the inheritance tree at runtime and + include methods and interfaces which are not available in source code. +

Index: nb_all/openide/compat/.cvsignore =================================================================== RCS file: nb_all/openide/compat/.cvsignore diff -N nb_all/openide/compat/.cvsignore --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/.cvsignore 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1 @@ +patched Index: nb_all/openide/compat/src/org/openide/awt/$Toolbar$Patch$.java =================================================================== RCS file: nb_all/openide/compat/src/org/openide/awt/$Toolbar$Patch$.java diff -N nb_all/openide/compat/src/org/openide/awt/$Toolbar$Patch$.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/src/org/openide/awt/$Toolbar$Patch$.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,63 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.awt; + +import java.awt.event.MouseEvent; +import javax.swing.JToolBar; +import javax.swing.event.MouseInputListener; + +/** A fake class that holds methods that for compatibility reasons + * should be public even in the definition are not. + * + * @author Jaroslav Tulach + */ +public abstract class $Toolbar$Patch$ extends JToolBar +implements MouseInputListener { + /** Constructor that delegates. + */ + public $Toolbar$Patch$ () { + } + + /** listener to delegate to */ + abstract MouseInputListener mouseDelegate (); + + public void mouseClicked(MouseEvent e) { + mouseDelegate ().mouseClicked (e); + } + + public void mouseDragged(MouseEvent e) { + mouseDelegate ().mouseDragged (e); + } + + public void mouseEntered(MouseEvent e) { + mouseDelegate ().mouseEntered (e); + } + + public void mouseExited(MouseEvent e) { + mouseDelegate ().mouseExited (e); + } + + public void mouseMoved(MouseEvent e) { + mouseDelegate ().mouseMoved (e); + } + + public void mousePressed(MouseEvent e) { + mouseDelegate ().mousePressed (e); + } + + public void mouseReleased(MouseEvent e) { + mouseDelegate ().mouseReleased (e); + } + +} Index: nb_all/openide/compat/src/org/openide/filesystems/$AbstractFileSystem$Patch$.java =================================================================== RCS file: nb_all/openide/compat/src/org/openide/filesystems/$AbstractFileSystem$Patch$.java diff -N nb_all/openide/compat/src/org/openide/filesystems/$AbstractFileSystem$Patch$.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/src/org/openide/filesystems/$AbstractFileSystem$Patch$.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,28 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.filesystems; + +/** A fake class that holds methods that for compatibility reasons + * should be public even in the definition are not. + * + * @author Jaroslav Tulach + */ +public abstract class $AbstractFileSystem$Patch$ extends FileSystem { + // implemented in AbstractFileSystem + abstract AbstractFileObject refreshRootImpl (); + + protected final AbstractFileObject refreshRoot () { + return refreshRootImpl (); + } +} Index: nb_all/openide/compat/src/org/openide/filesystems/$JarFileSystem$Patch$.java =================================================================== RCS file: nb_all/openide/compat/src/org/openide/filesystems/$JarFileSystem$Patch$.java diff -N nb_all/openide/compat/src/org/openide/filesystems/$JarFileSystem$Patch$.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/src/org/openide/filesystems/$JarFileSystem$Patch$.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,27 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.filesystems; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** A fake class that holds that implements interfaces + * that used to be implemented by LocalFS and JarFS + * + * @author Jaroslav Tulach + */ +abstract class $JarFileSystem$Patch$ extends AbstractFileSystem +implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change, AbstractFileSystem.Attr { +} Index: nb_all/openide/compat/src/org/openide/filesystems/$LocalFileSystem$Patch$.java =================================================================== RCS file: nb_all/openide/compat/src/org/openide/filesystems/$LocalFileSystem$Patch$.java diff -N nb_all/openide/compat/src/org/openide/filesystems/$LocalFileSystem$Patch$.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/src/org/openide/filesystems/$LocalFileSystem$Patch$.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,27 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.filesystems; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** A fake class that holds that implements interfaces + * that used to be implemented by LocalFS and JarFS + * + * @author Jaroslav Tulach + */ +abstract class $LocalFileSystem$Patch$ extends AbstractFileSystem +implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change { +} Index: nb_all/openide/compat/src/org/openide/filesystems/$Repository$Patch$.java =================================================================== RCS file: nb_all/openide/compat/src/org/openide/filesystems/$Repository$Patch$.java diff -N nb_all/openide/compat/src/org/openide/filesystems/$Repository$Patch$.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/src/org/openide/filesystems/$Repository$Patch$.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,26 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.filesystems; + +/** A fake class that holds methods that for compatibility reasons + * should be public even in the definition are not. + * + *

+ * This class should implement Node.Cookie, so it does. + * + * @author Jaroslav Tulach + */ +abstract class $Repository$Patch$ extends Object +implements org.openide.nodes.Node.Cookie { +} Index: nb_all/openide/compat/src/org/openide/util/actions/$SystemAction$Patch$.java =================================================================== RCS file: nb_all/openide/compat/src/org/openide/util/actions/$SystemAction$Patch$.java diff -N nb_all/openide/compat/src/org/openide/util/actions/$SystemAction$Patch$.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/src/org/openide/util/actions/$SystemAction$Patch$.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,50 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.util.actions; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import org.openide.util.Utilities; + +/** A fake class that holds methods that for compatibility reasons + * should be public even in the definition are not. + * + * @author Jaroslav Tulach + */ +public abstract class $SystemAction$Patch$ extends org.openide.util.SharedClassObject { + /** Constructor that delegates. + */ + public $SystemAction$Patch$ () { + } + + // Will be define by SystemAction + public abstract void setIcon (Icon icon); + public abstract Icon getIcon (boolean flag); + + // used to be define + public final void setIcon (ImageIcon icon) { + setIcon ((Icon) icon); + } + public final ImageIcon getIcon () { + Icon i = getIcon (false); + if (i instanceof ImageIcon) { + return ((ImageIcon) i); + } else { + // [PENDING] could try to translate Icon -> ImageIcon somehow, + // but I have no idea how to do this (paint it, take Component + // graphics, load the image data somehow??) + return new ImageIcon(Utilities.loadImage("org/openide/resources/actions/empty.gif")); // NOI18N + } + } +} Index: nb_all/openide/compat/test/.cvsignore =================================================================== RCS file: nb_all/openide/compat/test/.cvsignore diff -N nb_all/openide/compat/test/.cvsignore --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/test/.cvsignore 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,4 @@ +gensrc +lib +results +work Index: nb_all/openide/compat/test/build-unit.xml =================================================================== RCS file: nb_all/openide/compat/test/build-unit.xml diff -N nb_all/openide/compat/test/build-unit.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/test/build-unit.xml 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: nb_all/openide/compat/test/build.xml =================================================================== RCS file: nb_all/openide/compat/test/build.xml diff -N nb_all/openide/compat/test/build.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/test/build.xml 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: nb_all/openide/compat/test/cfg-unit.xml =================================================================== RCS file: nb_all/openide/compat/test/cfg-unit.xml diff -N nb_all/openide/compat/test/cfg-unit.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/test/cfg-unit.xml 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Index: nb_all/openide/compat/test/unit/src/org/openide/CompatibilityTest.java =================================================================== RCS file: nb_all/openide/compat/test/unit/src/org/openide/CompatibilityTest.java diff -N nb_all/openide/compat/test/unit/src/org/openide/CompatibilityTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/openide/compat/test/unit/src/org/openide/CompatibilityTest.java 13 Aug 2002 23:38:19 -0000 @@ -0,0 +1,264 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide; + +import java.io.IOException; +import java.util.*; + + +import org.netbeans.junit.NbTestCase; +import org.netbeans.junit.NbTestSuite; +import org.openide.compiler.ExternalCompiler; +import org.openide.filesystems.AbstractFileSystem; +import org.openide.filesystems.JarFileSystem; +import org.openide.filesystems.LocalFileSystem; +import org.openide.loaders.DataFolder; + +/** Tests compatibility of the openide. Compiles against classes as they +* are seen in runtime, but executed is just in regular IDE. +*/ +public class CompatibilityTest extends NbTestCase { + public CompatibilityTest (String name) { + super (name); + } + + public static void main(java.lang.String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static junit.framework.Test suite() { + junit.framework.TestSuite suite = new NbTestSuite(CompatibilityTest.class); + return suite; + } + + protected void setUp () { + } + + public void testDataLoaderPoolShadowLoaderIsPublic () { + new org.openide.loaders.DataLoaderPool$ShadowLoader (); + } + + public void testDataLoaderPoolDefaultLoaderIsPublic () { + new org.openide.loaders.DataLoaderPool$DefaultLoader (); + } + + public void testDataLoaderPoolInstanceLoaderIsPublic () { + new org.openide.loaders.DataLoaderPool$InstanceLoader (); + } + + public void testDataLoaderPoolFolderLoaderIsPublic () { + new org.openide.loaders.DataLoaderPool$FolderLoader (); + } + + public void testSetDefaultValueActionIsPublic () { + new org.openide.explorer.propertysheet.SetDefaultValueAction (); + } + + public void testJarFileSystemImplementsAFSInterfaces () { + JarFileSystem fs = new JarFileSystem (); + callAFSInfo (fs); + callAFSChange (fs); + callAFSList (fs); + callAFSAttr (fs); + } + + public void testLocalFileSystemImplementsAFSIntefaces () { + LocalFileSystem fs = new LocalFileSystem (); + callAFSInfo (fs); + callAFSChange (fs); + callAFSList (fs); + } + + public void testAbstractFileSystemHasTwoRefreshRootMethods () { + int cnt = 0; + + Class c = AbstractFileSystem.class; + + while (c != null) { + java.lang.reflect.Method[] arr = c.getDeclaredMethods(); + + for (int i = 0; i < arr.length; i++) { + if (arr[i].getName ().equals ("refreshRoot")) { + cnt++; + } + } + + c = c.getSuperclass(); + } + + assertEquals ("There are two refreshRoot methods defined", 2, cnt); + + } + + public void testToolbarBASIC_HEIGHTisnotfinal () { + int prev = org.openide.awt.Toolbar.BASIC_HEIGHT; + org.openide.awt.Toolbar.BASIC_HEIGHT = 22; + org.openide.awt.Toolbar.BASIC_HEIGHT = prev; + } + + public void testToolbarDnDFieldsArePublic () { + org.openide.awt.Toolbar t = new org.openide.awt.Toolbar (); + org.openide.awt.Toolbar.DnDEvent ev = new org.openide.awt.Toolbar.DnDEvent ( + t, "Str", 1, 2, 3 + ); + + assertEquals ("Str", ev.name); + assertEquals (1, ev.dx); + assertEquals (2, ev.dy); + assertEquals (3, ev.type); + } + + + public void testPossibleToOverrideListenerMethodsInCompilerGroup () { + class C extends org.openide.compiler.CompilerGroup { + boolean add; + boolean remove; + + public boolean start () { + return true; + } + + public void add (org.openide.compiler.Compiler c) { + } + + public void addCompilerListener (org.openide.compiler.CompilerListener l) { + add = true; + } + public void removeCompilerListener (org.openide.compiler.CompilerListener l) { + remove = true; + } + } + + C c = new C (); + c.addCompilerListener (null); + c.removeCompilerListener (null); + + assertTrue (c.add); + assertTrue (c.remove); + + } + + public void testExternalCompilerIsUpToDataIsPublic () { + new ExternalCompiler ( + new java.io.File ("ahoj"), + ExternalCompiler.COMPILE, + new org.openide.execution.NbProcessDescriptor ("x", "y"), + ExternalCompiler.JAVAC + ).isUpToDate (); + } + + public void testBeanTreeViewSelectionChangedIsPublic () { + try { + new org.openide.explorer.view.BeanTreeView ().selectionChanged( + new org.openide.nodes.Node[0], new org.openide.explorer.ExplorerManager () + ); + } catch (java.beans.PropertyVetoException ex) { + // ok + } + } + + public void testAbstractNodeGetCookieSetIsPublic () { + new org.openide.nodes.AbstractNode ( + org.openide.nodes.Children.LEAF + ).getCookieSet(); + } + + public void testMultiDataObjectGetCookieSetIsPublic () { + JarFileSystem fs = new JarFileSystem (); + DataFolder f = DataFolder.findFolder(fs.getRoot ()); + f.getCookieSet (); + } + + public void testRepositoryImplementsCookie () { + assertTrue ( + new org.openide.filesystems.Repository (new JarFileSystem ()) + instanceof org.openide.nodes.Node.Cookie + ); + } + + public void testSystemActionGetSetIcon () { + boolean[] res = new boolean[4]; + + java.lang.reflect.Method[] arr = org.openide.util.actions.SystemAction.class.getMethods(); + + for (int i = 0; i < arr.length; i++) { + int indx = -1; + if (arr[i].getName ().equals ("getIcon") && arr[i].getParameterTypes().length == 0) { + if (arr[i].getReturnType() == javax.swing.Icon.class) { + indx = 0; + } + if (arr[i].getReturnType() == javax.swing.ImageIcon.class) { + indx = 1; + } + } + if (arr[i].getName ().equals ("setIcon") && arr[i].getParameterTypes().length == 1) { + if (arr[i].getParameterTypes()[0] == javax.swing.Icon.class) { + indx = 2; + } + if (arr[i].getParameterTypes()[0] == javax.swing.ImageIcon.class) { + indx = 3; + } + } + + if (indx >= 0) { + assertTrue ("Not yet set", !res[indx]); + res[indx] = true; + } + + } + + assertTrue ("Icon getIcon () exists", res[0]); + assertTrue ("ImageIcon getIcon () exists", res[1]); + assertTrue ("setIcon (Icon) exists", res[2]); + assertTrue ("setIcon (ImageIcon) exists", res[3]); + } + + // + // Methods to do calls on filesystems + // + + private static void callAFSInfo (AbstractFileSystem.Info info) { + info.folder(""); + info.lastModified(""); + info.mimeType(""); + info.markUnimportant(""); + info.readOnly(""); + info.size (""); + + // getting IOException is good response... + try { info.inputStream(""); } catch (IOException ex) {} + try { info.outputStream(""); } catch (IOException ex) {} + try { info.lock(""); } catch (IOException ex) {} + + } + + private static void callAFSChange (AbstractFileSystem.Change change) { + // getting IOException is good response... + try { change.createData(""); } catch (IOException ex) {} + try { change.createFolder (""); } catch (IOException ex) {} + try { change.delete(""); } catch (IOException ex) {} + try { change.rename("", ""); } catch (IOException ex) {} + } + + private static void callAFSList (AbstractFileSystem.List change) { + change.children(""); + } + + private static void callAFSAttr (AbstractFileSystem.Attr attr) { + attr.attributes(""); + attr.deleteAttributes(""); + attr.readAttribute("", ""); + attr.renameAttributes("", ""); + } +} Index: nb_all/openide/src/org/openide/awt/Toolbar.java =================================================================== RCS file: /cvs/openide/src/org/openide/awt/Toolbar.java,v retrieving revision 1.70 diff -u -r1.70 Toolbar.java --- nb_all/openide/src/org/openide/awt/Toolbar.java 6 Aug 2002 14:15:46 -0000 1.70 +++ nb_all/openide/src/org/openide/awt/Toolbar.java 13 Aug 2002 23:38:20 -0000 @@ -39,18 +39,9 @@ * * @author David Peroutka, Libor Kramolis */ -public class Toolbar extends JToolBar -/*nbif compat -implements MouseInputListener -/*nbend*/ -{ +public class Toolbar extends JToolBar /*implemented by patchsuperclass MouseInputListener*/ { /** Basic toolbar height. */ - public static - /*nbif compat - nbelse*/ - final - /*nbend*/ - int BASIC_HEIGHT = 34; + public static final int BASIC_HEIGHT = 34; /** 5 pixels is tolerance of toolbar height so toolbar can be high (BASIC_HEIGHT + HEIGHT_TOLERANCE) but it will be set to BASIC_HEIGHT high. */ @@ -235,6 +226,10 @@ listener.dropToolbar (new DnDEvent (this, getName(), dx, dy, type)); } + synchronized final MouseInputListener mouseDelegate () { + if (mouseListener == null) mouseListener = new ToolbarMouseListener (); + return mouseListener; + } /** Toolbar mouse listener. */ class ToolbarMouseListener extends MouseInputAdapter { @@ -297,37 +292,6 @@ } // end of inner class ToolbarMouseListener - /*nbif compat - public void mouseClicked (MouseEvent e) { - if (mouseListener == null) mouseListener = new ToolbarMouseListener (); - mouseListener.mouseClicked (e); - } - public void mouseEntered (MouseEvent e) { - if (mouseListener == null) mouseListener = new ToolbarMouseListener (); - mouseListener.mouseEntered (e); - } - public void mouseExited (MouseEvent e) { - if (mouseListener == null) mouseListener = new ToolbarMouseListener (); - mouseListener.mouseExited (e); - } - public void mousePressed (MouseEvent e) { - if (mouseListener == null) mouseListener = new ToolbarMouseListener (); - mouseListener.mousePressed (e); - } - public void mouseReleased (MouseEvent e) { - if (mouseListener == null) mouseListener = new ToolbarMouseListener (); - mouseListener.mouseReleased (e); - } - public void mouseDragged (MouseEvent e) { - if (mouseListener == null) mouseListener = new ToolbarMouseListener (); - mouseListener.mouseDragged (e); - } - public void mouseMoved (MouseEvent e) { - if (mouseListener == null) mouseListener = new ToolbarMouseListener (); - mouseListener.mouseMoved (e); - } - /*nbend*/ - /** * This class can be used to produce a Toolbar instance from * the given DataFolder. @@ -620,33 +584,13 @@ public static final int DND_LINE = 3; /** Name of toolbar where event occured. */ - /*nbif compat - public - nbelse*/ - private - /*nbend*/ - String name; + private String name; /** distance of horizontal dragging */ - /*nbif compat - public - nbelse*/ - private - /*nbend*/ - int dx; + private int dx; /** distance of vertical dragging */ - /*nbif compat - public - nbelse*/ - private - /*nbend*/ - int dy; + private int dy; /** Type of event. */ - /*nbif compat - public - nbelse*/ - private - /*nbend*/ - int type; + private int type; static final long serialVersionUID =4389530973297716699L; public DnDEvent (Toolbar toolbar, String name, int dx, int dy, int type) { Index: nb_all/openide/src/org/openide/compiler/CompilerGroup.java =================================================================== RCS file: /cvs/openide/src/org/openide/compiler/CompilerGroup.java,v retrieving revision 1.10 diff -u -r1.10 CompilerGroup.java --- nb_all/openide/src/org/openide/compiler/CompilerGroup.java 29 Jul 2002 10:11:30 -0000 1.10 +++ nb_all/openide/src/org/openide/compiler/CompilerGroup.java 13 Aug 2002 23:38:20 -0000 @@ -64,12 +64,7 @@ /** Add a listener. * @param l the listener to add */ - public - /*nbif compat - nbelse*/ - final - /*nbend*/ - synchronized void addCompilerListener (CompilerListener l) { + public final synchronized void addCompilerListener (CompilerListener l) { if (listeners == null ) { listeners = new javax.swing.event.EventListenerList(); } @@ -79,12 +74,7 @@ /** Remove a listener. * @param l the listener to remove */ - public - /*nbif compat - nbelse*/ - final - /*nbend*/ - synchronized void removeCompilerListener (CompilerListener l) { + public final synchronized void removeCompilerListener (CompilerListener l) { if (listeners == null) return; listeners.remove (org.openide.compiler.CompilerListener.class, l); } Index: nb_all/openide/src/org/openide/compiler/ExternalCompiler.java =================================================================== RCS file: /cvs/openide/src/org/openide/compiler/ExternalCompiler.java,v retrieving revision 1.39 diff -u -r1.39 ExternalCompiler.java --- nb_all/openide/src/org/openide/compiler/ExternalCompiler.java 29 Jul 2002 10:11:30 -0000 1.39 +++ nb_all/openide/src/org/openide/compiler/ExternalCompiler.java 13 Aug 2002 23:38:20 -0000 @@ -429,12 +429,7 @@ } } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - boolean isUpToDate() { + protected boolean isUpToDate() { if (type == BUILD) { return false; } else { Index: nb_all/openide/src/org/openide/explorer/propertysheet/SetDefaultValueAction.java =================================================================== RCS file: /cvs/openide/src/org/openide/explorer/propertysheet/SetDefaultValueAction.java,v retrieving revision 1.22 diff -u -r1.22 SetDefaultValueAction.java --- nb_all/openide/src/org/openide/explorer/propertysheet/SetDefaultValueAction.java 29 Jul 2002 10:11:31 -0000 1.22 +++ nb_all/openide/src/org/openide/explorer/propertysheet/SetDefaultValueAction.java 13 Aug 2002 23:38:20 -0000 @@ -21,12 +21,12 @@ * * @author Jan Jancura, Petr Hamernik, Ian Formanek */ -/*nbif compat -public -/*nbend*/ final class SetDefaultValueAction extends CallbackSystemAction { /** generated Serialized Version UID */ static final long serialVersionUID = -1285705164427519181L; + + public SetDefaultValueAction () { + } public String getName () { return getString ("SetDefaultValue"); Index: nb_all/openide/src/org/openide/explorer/view/BeanTreeView.java =================================================================== RCS file: /cvs/openide/src/org/openide/explorer/view/BeanTreeView.java,v retrieving revision 1.18 diff -u -r1.18 BeanTreeView.java --- nb_all/openide/src/org/openide/explorer/view/BeanTreeView.java 29 Jul 2002 10:11:31 -0000 1.18 +++ nb_all/openide/src/org/openide/explorer/view/BeanTreeView.java 13 Aug 2002 23:38:20 -0000 @@ -70,13 +70,7 @@ * @param nodes nodes * @param em explorer manager */ - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void selectionChanged(Node[] nodes, ExplorerManager em) throws PropertyVetoException { - + protected void selectionChanged(Node[] nodes, ExplorerManager em) throws PropertyVetoException { if (nodes.length > 0) { Node context = nodes[0].getParentNode (); for (int i = 1; i < nodes.length; i++) { Index: nb_all/openide/src/org/openide/filesystems/AbstractFileSystem.java =================================================================== RCS file: /cvs/openide/src/org/openide/filesystems/AbstractFileSystem.java,v retrieving revision 1.46 diff -u -r1.46 AbstractFileSystem.java --- nb_all/openide/src/org/openide/filesystems/AbstractFileSystem.java 29 Jul 2002 10:11:32 -0000 1.46 +++ nb_all/openide/src/org/openide/filesystems/AbstractFileSystem.java 13 Aug 2002 23:38:20 -0000 @@ -259,12 +259,6 @@ return refreshRootImpl (); } - /*nbif compat - protected final AbstractFileObject r3fr3shR00t () { - return refreshRootImpl (); - } - /*nbend*/ - /** Allows subclasses to fire that a change occured in a * file or folder. The change can be "expected" when it is * a result of an user action and the user knows that such Index: nb_all/openide/src/org/openide/filesystems/JarFileSystem.java =================================================================== RCS file: /cvs/openide/src/org/openide/filesystems/JarFileSystem.java,v retrieving revision 1.68 diff -u -r1.68 JarFileSystem.java --- nb_all/openide/src/org/openide/filesystems/JarFileSystem.java 29 Jul 2002 10:11:32 -0000 1.68 +++ nb_all/openide/src/org/openide/filesystems/JarFileSystem.java 13 Aug 2002 23:38:20 -0000 @@ -37,11 +37,7 @@ * them, or (better) use delegation. * @author Jan Jancura, Jaroslav Tulach, Petr Hamernik, Radek Matous */ -public class JarFileSystem extends AbstractFileSystem - /*nbif compat - implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change, AbstractFileSystem.Attr - /*nbend*/ -{ +public class JarFileSystem extends AbstractFileSystem { /** generated Serialized Version UID */ static final long serialVersionUID = -98124752801761145L; @@ -252,12 +248,7 @@ // List // - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - String[] children (String name) { + protected String[] children (String name) { EntryCache tmpRootCache = getCacheOfRoot (); if (tmpRootCache == null) { if ((tmpRootCache = parse (false)) == null) @@ -273,39 +264,19 @@ // Change // - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void createFolder (String name) throws java.io.IOException { + protected void createFolder (String name) throws java.io.IOException { throw new IOException (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void createData (String name) throws IOException { + protected void createData (String name) throws IOException { throw new IOException (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void rename(String oldName, String newName) throws IOException { + protected void rename(String oldName, String newName) throws IOException { throw new IOException (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void delete (String name) throws IOException { + protected void delete (String name) throws IOException { throw new IOException (); } @@ -313,23 +284,13 @@ // Info // - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - java.util.Date lastModified(String name) { + protected java.util.Date lastModified(String name) { /** JarEntry.getTime returns wrong value: already reported in bugtraq 4319781 * Fixed in jdk1.4 */ return new java.util.Date (getEntry (name).getTime ()); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - boolean folder (String name) { + protected boolean folder (String name) { if ("".equals (name)) return true; // NOI18N EntryCache tmpRootCache = getCacheOfRoot (); if (tmpRootCache == null) @@ -340,40 +301,20 @@ return tmpCache.isFolder (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - boolean readOnly (String name) { + protected boolean readOnly (String name) { return true; } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - String mimeType (String name) { + protected String mimeType (String name) { return null; } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - long size (String name) { + protected long size (String name) { long retVal = getEntry (name).getSize (); return (retVal == -1) ? 0 : retVal; } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - InputStream inputStream (String name) throws java.io.FileNotFoundException { + protected InputStream inputStream (String name) throws java.io.FileNotFoundException { InputStream is = null; AbstractFolder fo = null; try { @@ -429,46 +370,21 @@ return in; } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - OutputStream outputStream (String name) throws java.io.IOException { + protected OutputStream outputStream (String name) throws java.io.IOException { throw new IOException (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void lock (String name) throws IOException { + protected void lock (String name) throws IOException { FSException.io ("EXC_CannotLock", name, getDisplayName (), name); // NOI18N } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void unlock (String name) { - } - - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void markUnimportant (String name) { - } - - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - Object readAttribute(String name, String attrName) { + protected void unlock (String name) { + } + + protected void markUnimportant (String name) { + } + + protected Object readAttribute(String name, String attrName) { Attributes attr = getManifest ().getAttributes (name); try { return attr == null ? null : attr.getValue (attrName); @@ -477,21 +393,11 @@ } } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void writeAttribute(String name, String attrName, Object value) throws IOException { + protected void writeAttribute(String name, String attrName, Object value) throws IOException { throw new IOException (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - Enumeration attributes(String name) { + protected Enumeration attributes(String name) { Attributes attr = getManifest ().getAttributes (name); if (attr != null) { @@ -506,20 +412,10 @@ } } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void renameAttributes (String oldName, String newName) { + protected void renameAttributes (String oldName, String newName) { } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void deleteAttributes (String name) { + protected void deleteAttributes (String name) { } /** Close the jar file when we go away...*/ Index: nb_all/openide/src/org/openide/filesystems/LocalFileSystem.java =================================================================== RCS file: /cvs/openide/src/org/openide/filesystems/LocalFileSystem.java,v retrieving revision 1.54 diff -u -r1.54 LocalFileSystem.java --- nb_all/openide/src/org/openide/filesystems/LocalFileSystem.java 29 Jul 2002 10:11:32 -0000 1.54 +++ nb_all/openide/src/org/openide/filesystems/LocalFileSystem.java 13 Aug 2002 23:38:20 -0000 @@ -34,11 +34,7 @@ * as protected in this class. Do not call them! Subclasses might override * them, or (better) use delegation. */ -public class LocalFileSystem extends AbstractFileSystem - /*nbif compat - implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change - /*nbend*/ -{ +public class LocalFileSystem extends AbstractFileSystem { /** generated Serialized Version UID */ private static final long serialVersionUID = -5355566113542272442L; @@ -155,12 +151,7 @@ // List // - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - String[] children (String name) { + protected String[] children (String name) { File f = getFile (name); if (f.isDirectory ()) { return f.list (); @@ -173,12 +164,7 @@ // Change // - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void createFolder (String name) throws java.io.IOException { + protected void createFolder (String name) throws java.io.IOException { File f = getFile (name); if (name.equals ("")) { // NOI18N @@ -219,12 +205,7 @@ } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void createData (String name) throws IOException { + protected void createData (String name) throws IOException { File f = getFile (name); if (!f.createNewFile ()) { @@ -245,12 +226,7 @@ */ } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void rename(String oldName, String newName) throws IOException { + protected void rename(String oldName, String newName) throws IOException { File of = getFile (oldName); File nf = getFile (newName); @@ -260,12 +236,7 @@ } } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void delete(String name) throws IOException { + protected void delete(String name) throws IOException { File file = getFile(name); if (deleteFile(file) != SUCCESS) { if (file.exists()) @@ -323,49 +294,24 @@ // Info // - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - java.util.Date lastModified(String name) { + protected java.util.Date lastModified(String name) { return new java.util.Date (getFile (name).lastModified ()); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - boolean folder (String name) { + protected boolean folder (String name) { return getFile (name).isDirectory (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - boolean readOnly (String name) { + protected boolean readOnly (String name) { File f = getFile (name); return !f.canWrite () && f.exists (); } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - String mimeType (String name) { + protected String mimeType (String name) { return null; } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - long size (String name) { + protected long size (String name) { return getFile (name).length (); } @@ -399,12 +345,7 @@ // ============================================================================ // Begin of the original part - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - InputStream inputStream (String name) throws java.io.FileNotFoundException { + protected InputStream inputStream (String name) throws java.io.FileNotFoundException { FileInputStream fis; File file = null; @@ -419,24 +360,14 @@ return fis; } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - OutputStream outputStream (String name) throws java.io.IOException { + protected OutputStream outputStream (String name) throws java.io.IOException { return new FileOutputStream (getFile (name)); } // End of the original part // ============================================================================ - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void lock (String name) throws IOException { + protected void lock (String name) throws IOException { File file = getFile (name); if ((!file.canWrite () && file.exists ()) || isReadOnly()) { @@ -444,20 +375,10 @@ } } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void unlock (String name) { + protected void unlock (String name) { } - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - void markUnimportant (String name) { + protected void markUnimportant (String name) { } /** Creates file for given string name. Index: nb_all/openide/src/org/openide/filesystems/Repository.java =================================================================== RCS file: /cvs/openide/src/org/openide/filesystems/Repository.java,v retrieving revision 1.38 diff -u -r1.38 Repository.java --- nb_all/openide/src/org/openide/filesystems/Repository.java 29 Jul 2002 10:11:32 -0000 1.38 +++ nb_all/openide/src/org/openide/filesystems/Repository.java 13 Aug 2002 23:38:20 -0000 @@ -38,9 +38,6 @@ * @author Jaroslav Tulach, Petr Hamernik */ public class Repository extends Object implements java.io.Serializable -/*nbif compat -, org.openide.nodes.Node.Cookie -/*nbend*/ { /** list of filesystems (FileSystem) */ private ArrayList fileSystems; Index: nb_all/openide/src/org/openide/loaders/DataFolder.java =================================================================== RCS file: /cvs/openide/src/org/openide/loaders/DataFolder.java,v retrieving revision 1.127 diff -u -r1.127 DataFolder.java --- nb_all/openide/src/org/openide/loaders/DataFolder.java 19 Jul 2002 08:41:37 -0000 1.127 +++ nb_all/openide/src/org/openide/loaders/DataFolder.java 13 Aug 2002 23:38:20 -0000 @@ -686,7 +686,7 @@ countDown--; try { // resolve temporary object for moving into - DataLoaderPool.FolderLoader folderLoader = (DataLoaderPool.FolderLoader) getMultiFileLoader (); + DataLoaderPool$FolderLoader folderLoader = (DataLoaderPool$FolderLoader) getMultiFileLoader (); newFolder = (DataFolder) folderLoader.createMultiObject (newFile, this); dispose = false; break; Index: nb_all/openide/src/org/openide/loaders/DataLoaderPool.java =================================================================== RCS file: /cvs/openide/src/org/openide/loaders/DataLoaderPool.java,v retrieving revision 1.87 diff -u -r1.87 DataLoaderPool.java --- nb_all/openide/src/org/openide/loaders/DataLoaderPool.java 29 Jul 2002 10:11:34 -0000 1.87 +++ nb_all/openide/src/org/openide/loaders/DataLoaderPool.java 13 Aug 2002 23:38:20 -0000 @@ -472,7 +472,7 @@ private static MultiFileLoader[] getSystemLoaders () { if (systemLoaders == null) { systemLoaders = new MultiFileLoader [] { - new ShadowLoader (), + new DataLoaderPool$ShadowLoader (), (MultiFileLoader) DataLoader.getLoader(InstanceLoaderSystem.class) }; } @@ -484,10 +484,10 @@ private static MultiFileLoader[] getDefaultLoaders () { if (defaultLoaders == null) { defaultLoaders = new MultiFileLoader [] { - (MultiFileLoader) DataLoader.getLoader(FolderLoader.class), + (MultiFileLoader) DataLoader.getLoader(DataLoaderPool$FolderLoader.class), (MultiFileLoader) DataLoader.getLoader(XMLDataObject.Loader.class), - (MultiFileLoader) DataLoader.getLoader(InstanceLoader.class), - (MultiFileLoader) DataLoader.getLoader(DefaultLoader.class) + (MultiFileLoader) DataLoader.getLoader(DataLoaderPool$InstanceLoader.class), + (MultiFileLoader) DataLoader.getLoader(DataLoaderPool$DefaultLoader.class) }; } return defaultLoaders; @@ -516,110 +516,13 @@ // // Default loaders // - - /** Loader for folders, since 1.13 changed to UniFileLoader. */ - /*nbif compat - public - nbelse*/ - /*nbend*/ - static class FolderLoader extends UniFileLoader { - static final long serialVersionUID =-8325525104047820255L; - - /* Representation class is DataFolder */ - public FolderLoader () { - super ("org.openide.loaders.DataFolder"); // NOI18N - // super (DataFolder.class); - } - - /** Get default actions. - * @return array of default system actions or null if this loader does not have any - * actions - */ - protected SystemAction[] defaultActions () { - return new SystemAction[] { - SystemAction.get (org.openide.actions.OpenLocalExplorerAction.class), - SystemAction.get (org.openide.actions.FindAction.class), - SystemAction.get (org.openide.actions.FileSystemAction.class), - null, - SystemAction.get (org.openide.actions.CompileAction.class), - SystemAction.get (org.openide.actions.CompileAllAction.class), - null, - SystemAction.get (org.openide.actions.BuildAction.class), - SystemAction.get (org.openide.actions.BuildAllAction.class), - null, - SystemAction.get (org.openide.actions.CutAction.class), - SystemAction.get (org.openide.actions.CopyAction.class), - SystemAction.get (org.openide.actions.PasteAction.class), - null, - SystemAction.get (org.openide.actions.DeleteAction.class), - SystemAction.get (org.openide.actions.RenameAction.class), - null, - SystemAction.get (org.openide.actions.NewTemplateAction.class), - null, - SystemAction.get (org.openide.actions.ToolsAction.class), - SystemAction.get (org.openide.actions.PropertiesAction.class) - }; - } - - /** Get the default display name of this loader. - * @return default display name - */ - protected String defaultDisplayName () { - return NbBundle.getMessage (DataLoaderPool.class, "LBL_folder_loader_display_name"); - } - - protected FileObject findPrimaryFile(FileObject fo) { - if (fo.isFolder()) { - return fo; - } - return null; - } - - protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) { - return new FileEntry.Folder(obj, primaryFile); - } - - protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException { - return new DataFolder (primaryFile); - } - - /** This method is used only in DataFolder.handleMove method. - * For more comments see {@link org.openide.loaders.DataFolder#handleMove}. - * - * @param primaryFile the primary file of the datafolder to be created - * @param original The original DataFolder. The returned MultiDataObject - * delegates createNodeDelegate and getClonedNodeDelegate methods calls - * to the original DataFolder. - * @return The DataFolder that shares the nodes with the original DataFolder. - */ - MultiDataObject createMultiObject(FileObject primaryFile, final DataFolder original) throws DataObjectExistsException, IOException { - class NodeSharingDataFolder extends DataFolder { - public NodeSharingDataFolder(FileObject fo) throws DataObjectExistsException, IllegalArgumentException { - super(fo); - } - protected Node createNodeDelegate() { - return new FilterNode(original.getNodeDelegate()); - } - Node getClonedNodeDelegate (DataFilter filter) { - return new FilterNode(original.getClonedNodeDelegate(filter)); - } - } - return new NodeSharingDataFolder(primaryFile); - } - - public void writeExternal(ObjectOutput oo) throws IOException { - } - public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException { - } - - } /* Instance loader recognizing .settings files. It's placed at the beginning * of loader pool, .settings files must alwaus be recognized by this loader * otherwise IDE settings will not work at all. No module is permitted to use * .settings files. */ - private static class InstanceLoaderSystem extends InstanceLoader { + private static class InstanceLoaderSystem extends DataLoaderPool$InstanceLoader { private static final long serialVersionUID = -935749906623354837L; /* Creates new InstanceLoader */ @@ -648,293 +551,380 @@ }; } } +} // end of DataLoaderPool - /* Instance loader recognizing .ser and .instance files. It's placed at - * the end of loader pool among default loaders. + +/* Instance loader recognizing .ser and .instance files. It's placed at + * the end of loader pool among default loaders. + */ +class DataLoaderPool$InstanceLoader extends UniFileLoader { + static final long serialVersionUID =-3462727693843631328L; + + + /* Creates new InstanceLoader */ + public DataLoaderPool$InstanceLoader () { + super ("org.openide.loaders.InstanceDataObject"); // NOI18N + } + + protected void initialize () { + super.initialize(); + setExtensions(null); + } + + /** Get default actions. + * @return array of default system actions or null if this loader does not have any + * actions + */ + protected SystemAction[] defaultActions () { + return new SystemAction[] { + SystemAction.get (org.openide.actions.CustomizeBeanAction.class), + SystemAction.get (org.openide.actions.FileSystemAction.class), + null, + SystemAction.get(org.openide.actions.CutAction.class), + SystemAction.get(org.openide.actions.CopyAction.class), + SystemAction.get(org.openide.actions.PasteAction.class), + null, + SystemAction.get(org.openide.actions.DeleteAction.class), + // #16278: Rename should be there. (It may or may not be enabled...) + SystemAction.get(org.openide.actions.RenameAction.class), + null, + SystemAction.get (org.openide.actions.ToolsAction.class), + SystemAction.get(org.openide.actions.PropertiesAction.class) + }; + } + + /** Get the default display name of this loader. + * @return default display name + */ + protected String defaultDisplayName () { + return NbBundle.getMessage (DataLoaderPool.class, "LBL_instance_loader_display_name"); + } + + /* Creates the right data object for given primary file. + * It is guaranteed that the provided file is realy primary file + * returned from the method findPrimaryFile. + * + * @param primaryFile the primary file + * @return the data object for this file + * @exception DataObjectExistsException if the primary file already has data object */ - /*nbif compat - public - nbelse*/ - private - /*nbend*/ - static class InstanceLoader extends UniFileLoader { - static final long serialVersionUID =-3462727693843631328L; - - - /* Creates new InstanceLoader */ - public InstanceLoader() { - super ("org.openide.loaders.InstanceDataObject"); // NOI18N - } - - protected void initialize () { - super.initialize(); - setExtensions(null); + protected MultiDataObject createMultiObject (FileObject primaryFile) + throws DataObjectExistsException, java.io.IOException { + InstanceDataObject obj = new InstanceDataObject(primaryFile, this); + return obj; + } + + public void writeExternal (ObjectOutput oo) throws IOException { + // does not use super serialization of extensions + oo.writeObject (this); + + super.writeExternal (oo); + } + + public void readExternal (ObjectInput oi) throws IOException, ClassNotFoundException { + // the result of following code is either ExtensionList (original version) + // or this (current version). + Object o = oi.readObject (); + if (o instanceof SystemAction[]) { + //added for compatibility with FFJ2.0 + setActions ((SystemAction[]) o); + setExtensions(getExtensions()); + } else if (o instanceof ExtensionList) { + // old serialization, add new extension + ExtensionList list = (ExtensionList)o; + setExtensions(list); + } else { + // newer serialization, everything should be ok, just read + // the original value + super.readExternal (oi); + setExtensions(getExtensions()); } - - /** Get default actions. - * @return array of default system actions or null if this loader does not have any - * actions - */ - protected SystemAction[] defaultActions () { - return new SystemAction[] { - SystemAction.get (org.openide.actions.CustomizeBeanAction.class), + } + + /** Set the extension list for this data loader. + * Checks if all required extensions are in new list of extensions. + * @param ext new list of extensions + */ + public void setExtensions(ExtensionList ext) { + super.setExtensions(initExtensions(ext)); + } + + /** fill in instance file's extension list; if ext == null new list is created */ + private ExtensionList initExtensions(ExtensionList ext) { + String rqext [] = getRequiredExt (); + if (ext == null) ext = new ExtensionList(); + for (int i = 0; i < rqext.length; i++) + ext.addExtension(rqext[i]); + return ext; + } + + /** @return list of all required extensions for this loader */ + protected String [] getRequiredExt () { + return new String[] { + InstanceDataObject.INSTANCE, + InstanceDataObject.SER_EXT, + InstanceDataObject.XML_EXT + }; + } +} // end of DataLoaderPool$InstanceLoader + + + + + +/** Loader for file objects not recognized by any other loader */ +class DataLoaderPool$DefaultLoader extends MultiFileLoader { + static final long serialVersionUID =-6761887227412396555L; + + /* Representation class is DefaultDataObject */ + public DataLoaderPool$DefaultLoader () { + super ("org.openide.loaders.DefaultDataObject"); // NOI18N + //super (DefaultDataObject.class); + } + + /** Get default actions. + * @return array of default system actions or null if this loader does not have any + * actions + */ + protected SystemAction[] defaultActions () { + return new SystemAction[] { SystemAction.get (org.openide.actions.FileSystemAction.class), null, - SystemAction.get(org.openide.actions.CutAction.class), - SystemAction.get(org.openide.actions.CopyAction.class), - SystemAction.get(org.openide.actions.PasteAction.class), + SystemAction.get (org.openide.actions.CutAction.class), + SystemAction.get (org.openide.actions.CopyAction.class), + SystemAction.get (org.openide.actions.PasteAction.class), null, - SystemAction.get(org.openide.actions.DeleteAction.class), - // #16278: Rename should be there. (It may or may not be enabled...) - SystemAction.get(org.openide.actions.RenameAction.class), + SystemAction.get (org.openide.actions.DeleteAction.class), + SystemAction.get (org.openide.actions.RenameAction.class), null, SystemAction.get (org.openide.actions.ToolsAction.class), - SystemAction.get(org.openide.actions.PropertiesAction.class) + SystemAction.get (org.openide.actions.PropertiesAction.class) }; - } - - /** Get the default display name of this loader. - * @return default display name - */ - protected String defaultDisplayName () { - return NbBundle.getMessage (DataLoaderPool.class, "LBL_instance_loader_display_name"); - } + } - /* Creates the right data object for given primary file. - * It is guaranteed that the provided file is realy primary file - * returned from the method findPrimaryFile. - * - * @param primaryFile the primary file - * @return the data object for this file - * @exception DataObjectExistsException if the primary file already has data object - */ - protected MultiDataObject createMultiObject (FileObject primaryFile) - throws DataObjectExistsException, java.io.IOException { - InstanceDataObject obj = new InstanceDataObject(primaryFile, this); - return obj; - } - - public void writeExternal (ObjectOutput oo) throws IOException { - // does not use super serialization of extensions - oo.writeObject (this); - - super.writeExternal (oo); - } - - public void readExternal (ObjectInput oi) throws IOException, ClassNotFoundException { - // the result of following code is either ExtensionList (original version) - // or this (current version). - Object o = oi.readObject (); - if (o instanceof SystemAction[]) { - //added for compatibility with FFJ2.0 - setActions ((SystemAction[]) o); - setExtensions(getExtensions()); - } else if (o instanceof ExtensionList) { - // old serialization, add new extension - ExtensionList list = (ExtensionList)o; - setExtensions(list); - } else { - // newer serialization, everything should be ok, just read - // the original value - super.readExternal (oi); - setExtensions(getExtensions()); - } - } - - /** Set the extension list for this data loader. - * Checks if all required extensions are in new list of extensions. - * @param ext new list of extensions - */ - public void setExtensions(ExtensionList ext) { - super.setExtensions(initExtensions(ext)); + /** Get the default display name of this loader. + * @return default display name + */ + protected String defaultDisplayName () { + return NbBundle.getMessage (DataLoaderPool.class, "LBL_default_loader_display_name"); + } + + /** Get the primary file. + * @param fo the file to find the primary file for + * + * @return the primary file + */ + protected FileObject findPrimaryFile (FileObject fo) { + // never recognize folders + if (fo.isFolder()) return null; + return fo; + } + + /* Creates the right data object for given primary file. + * It is guaranteed that the provided file is realy primary file + * returned from the method findPrimaryFile. + * + * @param primaryFile the primary file + * @return the data object for this file + * @exception DataObjectExistsException if the primary file already has data object + */ + protected MultiDataObject createMultiObject (FileObject primaryFile) + throws DataObjectExistsException, java.io.IOException { + return new DefaultDataObject(primaryFile, this); + } + + /* Creates the right primary entry for given primary file. + * + * @param obj requesting object + * @param primaryFile primary file recognized by this loader + * @return primary entry for that file + */ + protected MultiDataObject.Entry createPrimaryEntry (MultiDataObject obj, FileObject primaryFile) { + return new FileEntry (obj, primaryFile); + } + + /** Do not create a seconday entry. + * + * @param obj ignored + * @param secondaryFile ignored + * @return never returns + * @exception UnsupportedOperationException because this loader supports only a primary file object + */ + protected MultiDataObject.Entry createSecondaryEntry (MultiDataObject obj, FileObject secondaryFile) { + throw new UnsupportedOperationException (); + } + + /** Does nothing because this loader works only with objects + * with one file => primary file so it is not necessary to search + * for anything else. + * + * @param obj the object to test + */ + void checkFiles (MultiDataObject obj) { + } +} // end of DataLoaderPool$DefaultLoader + + + + + +/** Loader for shadows, since 1.13 changed to UniFileLoader. */ +class DataLoaderPool$ShadowLoader extends UniFileLoader { + static final long serialVersionUID =-11013405787959120L; + + /* Adapter for listening on filesystems changes */ + private static ShadowChangeAdapter changeAdapter = new ShadowChangeAdapter(); + + /* Representation class is DataShadow */ + public DataLoaderPool$ShadowLoader () { + super ("org.openide.loaders.DataShadow"); // NOI18N + //super (DataShadow.class); + } + + /** Get the default display name of this loader. + * @return default display name + */ + protected String defaultDisplayName () { + return NbBundle.getMessage (DataLoaderPool.class, "LBL_shadow_loader_display_name"); + } + + /** For a given file finds the primary file. + * @param fo the (secondary) file + * + * @return the primary file for the file or null if the file is not + * recognized by this loader + */ + protected FileObject findPrimaryFile(FileObject fo) { + if (fo.hasExt (DataShadow.SHADOW_EXTENSION)) { + return fo; } + return null; + } + + /** Creates the right primary entry for a given primary file. + * + * @param obj requesting object + * @param primaryFile primary file recognized by this loader + * @return primary entry for that file + */ + protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) { + return new FileEntry(obj, primaryFile); + } - /** fill in instance file's extension list; if ext == null new list is created */ - private ExtensionList initExtensions(ExtensionList ext) { - String rqext [] = getRequiredExt (); - if (ext == null) ext = new ExtensionList(); - for (int i = 0; i < rqext.length; i++) - ext.addExtension(rqext[i]); - return ext; + /** Creates the right data object for a given primary file. + * It is guaranteed that the provided file will actually be the primary file + * returned by {@link #findPrimaryFile}. + * + * @param primaryFile the primary file + * @return the data object for this file + * @exception DataObjectExistsException if the primary file already has a data object + */ + protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException { + try { + DataObject d = DataShadow.deserialize (primaryFile); + if (d != null) return new DataShadow (primaryFile, d, this); + } catch (IOException ex) { + // broken link or damaged shadow file } - - /** @return list of all required extensions for this loader */ - protected String [] getRequiredExt () { - return new String[] { - InstanceDataObject.INSTANCE, - InstanceDataObject.SER_EXT, - InstanceDataObject.XML_EXT + /* Link is broken, create BrokenDataShadow */ + return new BrokenDataShadow (primaryFile, this); + } + public void writeExternal(ObjectOutput oo) throws IOException { + } + public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException { + } +} // end of DataLoaderPool$ShadowLoader + +/** Loader for folders, since 1.13 changed to UniFileLoader. Will be made public by patching + */ +class DataLoaderPool$FolderLoader extends UniFileLoader { + static final long serialVersionUID =-8325525104047820255L; + + /* Representation class is DataFolder */ + public DataLoaderPool$FolderLoader () { + super ("org.openide.loaders.DataFolder"); // NOI18N + // super (DataFolder.class); + } + + /** Get default actions. + * @return array of default system actions or null if this loader does not have any + * actions + */ + protected SystemAction[] defaultActions () { + return new SystemAction[] { + SystemAction.get (org.openide.actions.OpenLocalExplorerAction.class), + SystemAction.get (org.openide.actions.FindAction.class), + SystemAction.get (org.openide.actions.FileSystemAction.class), + null, + SystemAction.get (org.openide.actions.CompileAction.class), + SystemAction.get (org.openide.actions.CompileAllAction.class), + null, + SystemAction.get (org.openide.actions.BuildAction.class), + SystemAction.get (org.openide.actions.BuildAllAction.class), + null, + SystemAction.get (org.openide.actions.CutAction.class), + SystemAction.get (org.openide.actions.CopyAction.class), + SystemAction.get (org.openide.actions.PasteAction.class), + null, + SystemAction.get (org.openide.actions.DeleteAction.class), + SystemAction.get (org.openide.actions.RenameAction.class), + null, + SystemAction.get (org.openide.actions.NewTemplateAction.class), + null, + SystemAction.get (org.openide.actions.ToolsAction.class), + SystemAction.get (org.openide.actions.PropertiesAction.class) }; - } } - - - /** Loader for file objects not recognized by any other loader */ - /*nbif compat - public - nbelse*/ - private - /*nbend*/ - static class DefaultLoader extends MultiFileLoader { - static final long serialVersionUID =-6761887227412396555L; - - /* Representation class is DataFolder */ - public DefaultLoader () { - super ("org.openide.loaders.DefaultDataObject"); // NOI18N - //super (DefaultDataObject.class); - } - - /** Get default actions. - * @return array of default system actions or null if this loader does not have any - * actions - */ - protected SystemAction[] defaultActions () { - return new SystemAction[] { - SystemAction.get (org.openide.actions.FileSystemAction.class), - null, - SystemAction.get (org.openide.actions.CutAction.class), - SystemAction.get (org.openide.actions.CopyAction.class), - SystemAction.get (org.openide.actions.PasteAction.class), - null, - SystemAction.get (org.openide.actions.DeleteAction.class), - SystemAction.get (org.openide.actions.RenameAction.class), - null, - SystemAction.get (org.openide.actions.ToolsAction.class), - SystemAction.get (org.openide.actions.PropertiesAction.class) - }; - } - - /** Get the default display name of this loader. - * @return default display name - */ - protected String defaultDisplayName () { - return NbBundle.getMessage (DataLoaderPool.class, "LBL_default_loader_display_name"); - } - - /** Get the primary file. - * @param fo the file to find the primary file for - * - * @return the primary file - */ - protected FileObject findPrimaryFile (FileObject fo) { - // never recognize folders - if (fo.isFolder()) return null; + + /** Get the default display name of this loader. + * @return default display name + */ + protected String defaultDisplayName () { + return NbBundle.getMessage (DataLoaderPool.class, "LBL_folder_loader_display_name"); + } + + protected FileObject findPrimaryFile(FileObject fo) { + if (fo.isFolder()) { return fo; } - - /* Creates the right data object for given primary file. - * It is guaranteed that the provided file is realy primary file - * returned from the method findPrimaryFile. - * - * @param primaryFile the primary file - * @return the data object for this file - * @exception DataObjectExistsException if the primary file already has data object - */ - protected MultiDataObject createMultiObject (FileObject primaryFile) - throws DataObjectExistsException, java.io.IOException { - return new DefaultDataObject(primaryFile, this); - } - - /* Creates the right primary entry for given primary file. - * - * @param obj requesting object - * @param primaryFile primary file recognized by this loader - * @return primary entry for that file - */ - protected MultiDataObject.Entry createPrimaryEntry (MultiDataObject obj, FileObject primaryFile) { - return new FileEntry (obj, primaryFile); - } - - /** Do not create a seconday entry. - * - * @param obj ignored - * @param secondaryFile ignored - * @return never returns - * @exception UnsupportedOperationException because this loader supports only a primary file object - */ - protected MultiDataObject.Entry createSecondaryEntry (MultiDataObject obj, FileObject secondaryFile) { - throw new UnsupportedOperationException (); - } - - /** Does nothing because this loader works only with objects - * with one file => primary file so it is not necessary to search - * for anything else. - * - * @param obj the object to test - */ - void checkFiles (MultiDataObject obj) { - } + return null; } - - /** Loader for shadows, since 1.13 changed to UniFileLoader. */ - /*nbif compat - public - nbelse*/ - private - /*nbend*/ - static class ShadowLoader extends UniFileLoader { - static final long serialVersionUID =-11013405787959120L; - - /* Adapter for listening on filesystems changes */ - private static ShadowChangeAdapter changeAdapter = new ShadowChangeAdapter(); - - /* Representation class is DataShadow */ - public ShadowLoader () { - super ("org.openide.loaders.DataShadow"); // NOI18N - //super (DataShadow.class); - } - - /** Get the default display name of this loader. - * @return default display name - */ - protected String defaultDisplayName () { - return NbBundle.getMessage (DataLoaderPool.class, "LBL_shadow_loader_display_name"); - } - - /** For a given file finds the primary file. - * @param fo the (secondary) file - * - * @return the primary file for the file or null if the file is not - * recognized by this loader - */ - protected FileObject findPrimaryFile(FileObject fo) { - if (fo.hasExt (DataShadow.SHADOW_EXTENSION)) { - return fo; + + protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) { + return new FileEntry.Folder(obj, primaryFile); + } + + protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException { + return new DataFolder (primaryFile); + } + + /** This method is used only in DataFolder.handleMove method. + * For more comments see {@link org.openide.loaders.DataFolder#handleMove}. + * + * @param primaryFile the primary file of the datafolder to be created + * @param original The original DataFolder. The returned MultiDataObject + * delegates createNodeDelegate and getClonedNodeDelegate methods calls + * to the original DataFolder. + * @return The DataFolder that shares the nodes with the original DataFolder. + */ + MultiDataObject createMultiObject(FileObject primaryFile, final DataFolder original) throws DataObjectExistsException, IOException { + class NodeSharingDataFolder extends DataFolder { + public NodeSharingDataFolder(FileObject fo) throws DataObjectExistsException, IllegalArgumentException { + super(fo); } - return null; - } - - /** Creates the right primary entry for a given primary file. - * - * @param obj requesting object - * @param primaryFile primary file recognized by this loader - * @return primary entry for that file - */ - protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) { - return new FileEntry(obj, primaryFile); - } - - /** Creates the right data object for a given primary file. - * It is guaranteed that the provided file will actually be the primary file - * returned by {@link #findPrimaryFile}. - * - * @param primaryFile the primary file - * @return the data object for this file - * @exception DataObjectExistsException if the primary file already has a data object - */ - protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException { - try { - DataObject d = DataShadow.deserialize (primaryFile); - if (d != null) return new DataShadow (primaryFile, d, this); - } catch (IOException ex) { - // broken link or damaged shadow file + protected Node createNodeDelegate() { + return new FilterNode(original.getNodeDelegate()); + } + Node getClonedNodeDelegate (DataFilter filter) { + return new FilterNode(original.getClonedNodeDelegate(filter)); } - /* Link is broken, create BrokenDataShadow */ - return new BrokenDataShadow (primaryFile, this); - } - public void writeExternal(ObjectOutput oo) throws IOException { - } - public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException { } + return new NodeSharingDataFolder(primaryFile); + } + + public void writeExternal(ObjectOutput oo) throws IOException { } -} + public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException { + } + +} // end of DataLoaderPool$FolderLoader Index: nb_all/openide/src/org/openide/loaders/MultiDataObject.java =================================================================== RCS file: /cvs/openide/src/org/openide/loaders/MultiDataObject.java,v retrieving revision 1.67 diff -u -r1.67 MultiDataObject.java --- nb_all/openide/src/org/openide/loaders/MultiDataObject.java 29 Jul 2002 10:11:34 -0000 1.67 +++ nb_all/openide/src/org/openide/loaders/MultiDataObject.java 13 Aug 2002 23:38:20 -0000 @@ -585,12 +585,7 @@ * @param s the cookie set to use * @deprecated just use getCookieSet().add(...) instead */ - /*nbif compat - public - nbelse*/ - protected final - /*nbend*/ - void setCookieSet (CookieSet s) { + protected final void setCookieSet (CookieSet s) { setCookieSet(s, true); } @@ -625,12 +620,7 @@ * * @return the cookie set (never null) */ - /*nbif compat - public - nbelse*/ - protected final - /*nbend*/ - CookieSet getCookieSet () { + protected final CookieSet getCookieSet () { CookieSet s = cookieSet; if (s != null) return s; synchronized (cookieSetLock) { Index: nb_all/openide/src/org/openide/nodes/AbstractNode.java =================================================================== RCS file: /cvs/openide/src/org/openide/nodes/AbstractNode.java,v retrieving revision 1.51 diff -u -r1.51 AbstractNode.java --- nb_all/openide/src/org/openide/nodes/AbstractNode.java 29 Jul 2002 10:11:34 -0000 1.51 +++ nb_all/openide/src/org/openide/nodes/AbstractNode.java 13 Aug 2002 23:38:20 -0000 @@ -512,12 +512,7 @@ * * @return the cookie set created by {@link #setCookieSet}, or an empty set (never null) */ - /*nbif compat - public - nbelse*/ - protected - /*nbend*/ - final CookieSet getCookieSet () { + protected final CookieSet getCookieSet () { CookieSet s = cookieSet; if (s != null) return s; synchronized (this) { Index: nb_all/openide/src/org/openide/util/actions/SystemAction.java =================================================================== RCS file: /cvs/openide/src/org/openide/util/actions/SystemAction.java,v retrieving revision 1.58 diff -u -r1.58 SystemAction.java --- nb_all/openide/src/org/openide/util/actions/SystemAction.java 29 Jul 2002 10:11:35 -0000 1.58 +++ nb_all/openide/src/org/openide/util/actions/SystemAction.java 13 Aug 2002 23:38:32 -0000 @@ -188,23 +188,6 @@ return getIcon (false); } - /*nbif compat - public final void setIcon (ImageIcon icon) { - setIcon ((Icon) icon); - } - public final ImageIcon g3t1c0n () { - Icon i = getIcon (false); - if (i instanceof ImageIcon) { - return ((ImageIcon) i); - } else { - // [PENDING] could try to translate Icon -> ImageIcon somehow, - // but I have no idea how to do this (paint it, take Component - // graphics, load the image data somehow??) - return getBlankIcon(); - } - } - /*nbend*/ - /** Get the action's display icon, possibly creating a text label. * @param createLabel if true, create a textual icon if otherwise there * would be none; if false, create a blank icon Index: nb_all/xtest/build.xml =================================================================== RCS file: /cvs/xtest/build.xml,v retrieving revision 1.39 diff -u -r1.39 build.xml --- nb_all/xtest/build.xml 16 Jul 2002 16:58:11 -0000 1.39 +++ nb_all/xtest/build.xml 13 Aug 2002 23:39:11 -0000 @@ -39,6 +39,7 @@ + @@ -68,15 +69,23 @@ basedir="src" excludesfile="../nbbuild/standard-jar-excludes.txt" compress="false" - includes="org/netbeans/xtest/**" excludes="org/netbeans/xtest/pe/server*/**" /> + includes="org/netbeans/xtest/**" excludes="org/netbeans/xtest/pe/server*/**,org/netbeans/xtest/ide/**" /> + + + + @@ -108,6 +117,7 @@ + Index: nb_all/xtest/bin/xtest-pes.sh =================================================================== RCS file: /cvs/xtest/bin/xtest-pes.sh,v retrieving revision 1.2 diff -u -r1.2 xtest-pes.sh --- nb_all/xtest/bin/xtest-pes.sh 27 Feb 2002 14:14:31 -0000 1.2 +++ nb_all/xtest/bin/xtest-pes.sh 13 Aug 2002 23:39:11 -0000 @@ -1,177 +1,228 @@ -#!/bin/sh -# -# Sun Public License Notice -# -# The contents of this file are subject to the Sun Public License -# Version 1.0 (the "License"). You may not use this file except in -# compliance with the License. A copy of the License is available at -# http://www.sun.com/ -# -# The Original Code is NetBeans. The Initial Developer of the Original -# Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun -# Microsystems, Inc. All Rights Reserved. - -# -# this script is a simple executor for Publishing Engine Server -# - it handles running the code in an endless loop -# - its basic behaviour is similar to other services -# available on Unix systems -# - you can use: -# 'xtest-pes.sh run' to tun the server -# 'xtest-pes.sh stop' to stop the server -# 'xtest-pes.sh kill' to kill the server -# - - -# These variables needs to be updated to correspond your values - -# where is Publishing Engine Server installed -#PES_HOME=/space/xtest-pes - -# where is Ant -#ANT_HOME=/space/xtest-pes/jakarta-ant-1.4.1 - -# set all the Java stuff -#JAVA_HOME=/usr/j2sdk1_3_1_02 -#JDK_HOME=$JAVA_HOME -#JAVA_PATH=$JAVA_HOME - -# add tit to path and export it -#PATH=$ANT_HOME/bin:$JDK_HOME/bin:$PATH -#export ANT_HOME JAVA_HOME JAVA_PATH JDK_HOME PATH - -# -# internal script stuff - you should not touch anything after this line -# -pes_status_file=xtest-pes.run -pes_stop_file=xtest-pes.stop -SLEEP_INTERVAL=300 - -pes_server_run() { - - if [ -r "$PES_HOME/$pes_status_file" ]; then - echo Another instance of XTest PES already running - return - fi - - # create the flag file with PID in PES home - echo $$ > $PES_HOME/$pes_status_file - - timer=0 - check_interval=5 - - while true - do - - if [ "$timer" -eq 0 ]; then - echo Running ANT part of PES - ant -f pes.xml - echo ANT part finished - fi - - timer=`expr $timer + $check_interval` - - # check if PES should be stopped - if [ -r "$PES_HOME/$pes_stop_file" ]; then - echo Stopping XTest PES - rm -f "$PES_HOME/$pes_stop_file" - rm -f "$PES_HOME/$pes_status_file" - return - fi - - if [ "$timer" -ge "$SLEEP_INTERVAL" ]; then - timer=0 - fi - - #echo Sleeping for $SLEEP_INTERVAL seconds - sleep $check_interval - done - -} - - -pes_server_stop() { - if [ ! -r "$PES_HOME/$pes_status_file" ]; then - echo "XTest PES does not seem to run. Cannot stop" - echo "You can try to $0 kill to kill the server" - return - fi - echo stopping xtest PES - if [ -r "$PES_HOME/$pes_stop_file" ]; then - echo "Command $0 stop is already running" - echo "If not, you can try to $0 kill to kill server" - return - fi - - # create the stop file and wait until run file is deleted - touch "$PES_HOME/$pes_stop_file" - echo "Waiting until XTest PES finished it's work" - while true; do - if [ ! -r "$PES_HOME/$pes_status_file" ]; then - echo "XTest PES stopped" - return - fi - # sleep for a second - sleep 1 - done - -} - - -pes_server_kill() { - if [ -r "$PES_HOME/$pes_status_file" ]; then - pid_to_kill=` cat $PES_HOME/$pes_status_file` - echo "Killing xtest-pes with PID $pid_to_kill" - kill -9 $pid_to_kill - rm -f "$PES_HOME/$pes_status_file" - if [ -r "$PES_HOME/$pes_stop_file" ]; then - rm -f "$PES_HOME/$pes_stop_file" - fi - return - fi - - if [ ! -r "$PES_HOME/$pes_status_file" ]; then - echo "XTest PES does not seem to run." - echo "You have to kill xtest-pes manually" - fi -} - - - -if [ -z "$PES_HOME" ]; then - echo PES_HOME needs to be set to XTest PES home - exit 1 -fi - -cd $PES_HOME - - -if [ -z "$ANT_HOME" ]; then - echo ANT_HOME needs to be set to ANT home directory -fi - -case "$1" in -'run') - echo 'Running XTest Publishing Server (PES)' - pes_server_run - ;; - -'stop') - echo 'Stopping XTest Publishing Server' - pes_server_stop - ;; - - -'kill') - echo 'Killing XTest Publishing Server' - pes_server_kill - ;; - -*) - echo "Usage: $0 { run | stop | kill}" - exit 1 - ;; - - -esac -exit 0 +#!/bin/sh +# +# Sun Public License Notice +# +# The contents of this file are subject to the Sun Public License +# Version 1.0 (the "License"). You may not use this file except in +# compliance with the License. A copy of the License is available at +# http://www.sun.com/ +# +# The Original Code is NetBeans. The Initial Developer of the Original +# Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun +# Microsystems, Inc. All Rights Reserved. + +# +# this script is a simple executor for Publishing Engine Server +# - it handles running the code in an endless loop +# - its basic behaviour is similar to other services +# available on Unix systems +# - you can use: +# 'xtest-pes.sh run' to tun the server +# 'xtest-pes.sh stop' to stop the server +# 'xtest-pes.sh kill' to kill the server +# + + +# These variables needs to be updated to correspond your values + +# where is Publishing Engine Server installed +# PES_HOME=/your/pes/home + + +# where is PES' config stored +#PES_CONFIG=/your/pes/config + + +# set all the Java stuff +#JAVA_HOME=/your/java/home + +# sleep interval +SLEEP_INTERVAL=300 + +# logging level for pes, should be set to WARNING +PES_LOGGING_LEVEL=WARNING + + +# +# internal script stuff - you should not touch anything after this line +# +pes_status_file=xtest-pes.run +pes_stop_file=xtest-pes.stop + + +pes_server_run() { + + if [ -r "$PES_HOME/$pes_status_file" ]; then + echo Another instance of XTest PES already running + return + fi + + # create the flag file with PID in PES home + echo $$ > $PES_HOME/$pes_status_file + + timer=0 + check_interval=5 + + while true + do + + if [ "$timer" -eq 0 ]; then + pes_server_cmd 'run' + fi + + timer=`expr $timer + $check_interval` + + # check if PES should be stopped + if [ -r "$PES_HOME/$pes_stop_file" ]; then + echo `date`: Stopping XTest PES + rm -f "$PES_HOME/$pes_stop_file" + rm -f "$PES_HOME/$pes_status_file" + return + fi + + if [ "$timer" -ge "$SLEEP_INTERVAL" ]; then + timer=0 + fi + + #echo Sleeping for $SLEEP_INTERVAL seconds + sleep $check_interval + done + +} + +pes_server_reconfigure() { + + if [ -r "$PES_HOME/$pes_status_file" ]; then + echo Another instance of XTest PES already running + return + fi + + # create the flag file with PID in PES home + echo $$ > $PES_HOME/$pes_status_file + + # run pes + pes_server_cmd 'reconfigure' + + # delete the status file + if [ -r "$PES_HOME/$pes_stop_file" ]; then + rm -f "$PES_HOME/$pes_stop_file" + fi +} + +# runs pes command +pes_server_cmd() { + pes_cmd=${1:-run} + # create PES' classpath + pes_classpath="" + for i in ${PES_HOME}/lib/*.jar ; do + pes_classpath=${pes_classpath}:$i + done + cmd="$JAVA_HOME/bin/java -cp $pes_classpath -Dpes.logging.level=$PES_LOGGING_LEVEL -Dxtest.home=$PES_HOME -Dpes.config=$PES_CONFIG -Dpes.command=$pes_cmd org.netbeans.xtest.pe.server.PEServer" +# echo running : $cmd +# echo `date`: Running PES + eval $cmd +# echo `date`: PES Done +} + + +pes_server_stop() { + if [ ! -r "$PES_HOME/$pes_status_file" ]; then + echo "XTest PES does not seem to run. Cannot stop" + echo "You can try to $0 kill to kill the server" + return + fi + echo stopping xtest PES + if [ -r "$PES_HOME/$pes_stop_file" ]; then + echo "Command $0 stop is already running" + echo "If not, you can try to $0 kill to kill server" + return + fi + + # create the stop file and wait until run file is deleted + touch "$PES_HOME/$pes_stop_file" + echo "Waiting until XTest PES finished it's work" + while true; do + if [ ! -r "$PES_HOME/$pes_status_file" ]; then + echo "XTest PES stopped" + return + fi + # sleep for a second + sleep 1 + done + +} + + +pes_server_kill() { + if [ -r "$PES_HOME/$pes_status_file" ]; then + pid_to_kill=` cat $PES_HOME/$pes_status_file` + echo "Killing xtest-pes with PID $pid_to_kill" + kill -9 $pid_to_kill + rm -f "$PES_HOME/$pes_status_file" + if [ -r "$PES_HOME/$pes_stop_file" ]; then + rm -f "$PES_HOME/$pes_stop_file" + fi + return + fi + + if [ ! -r "$PES_HOME/$pes_status_file" ]; then + echo "XTest PES does not seem to run." + echo "You have to kill xtest-pes manually" + fi +} + + + +if [ -z "$PES_HOME" ]; then + echo PES_HOME needs to be set to XTest PES home + exit 1 +fi + +if [ -z "$PES_CONFIG" ]; then + echo PES_CONFIG needs to be set to PES configuration file + exit 1 +fi + +if [ -z "$JAVA_HOME" ]; then + echo JAVA_HOME needs to be set to JDK 1.4 home + exit 1 +fi + +cd $PES_HOME + + +case "$1" in +'run') + echo `date`: Running XTest Publishing Engine Server + pes_server_run + ;; + +'start') + echo `date`: Starting XTest Publishing Engine Server + pes_server_run & + ;; + +'stop') + echo `date`: Stopping XTest Publishing Engine Server + pes_server_stop + ;; + + +'kill') + echo `date`: Killing XTest Publishing Engine Server + pes_server_kill + ;; + +'reconfigure') + echo `date`: Reconfiguring XTest Publishing Engine Server + pes_server_reconfigure + ;; + +*) + echo "Usage: $0 { run | stop | kill | reconfigue}" + exit 1 + ;; + + +esac +exit 0 Index: nb_all/xtest/examples/MyModule/test/build-unit.xml =================================================================== RCS file: /cvs/xtest/examples/MyModule/test/build-unit.xml,v retrieving revision 1.1 diff -u -r1.1 build-unit.xml --- nb_all/xtest/examples/MyModule/test/build-unit.xml 13 Feb 2002 09:51:48 -0000 1.1 +++ nb_all/xtest/examples/MyModule/test/build-unit.xml 13 Aug 2002 23:39:11 -0000 @@ -36,7 +36,7 @@ this file will be searched in directories specified by property xtest.extra.jars.path example: --> - + + + + + + + + + + + @@ -311,7 +325,10 @@ + + Index: nb_all/xtest/src/org/netbeans/Main.java =================================================================== RCS file: nb_all/xtest/src/org/netbeans/Main.java diff -N nb_all/xtest/src/org/netbeans/Main.java --- nb_all/xtest/src/org/netbeans/Main.java 25 Jul 2002 12:22:42 -0000 1.28 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,644 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans; - -import java.util.*; -import java.awt.EventQueue; -import java.awt.Toolkit; -import java.awt.AWTEvent; -import java.awt.event.MouseEvent; -import java.awt.event.*; -import org.openide.*; -import org.openide.filesystems.*; -import org.openide.filesystems.FileSystem; // override java.io.FileSystem -import org.openide.loaders.*; -import org.openide.nodes.*; -import org.openide.execution.*; -import org.openide.util.*; -import org.openide.util.actions.*; - -import org.netbeans.core.output.OutputSettings; -import org.netbeans.core.execution.TopSecurityManager; - -// flag file stuff -import java.io.*; - -// native kill stuff -import org.netbeans.xtest.util.JNIKill; - -/** - * - * @author jchalupa - */ -public class Main extends Object { - - // terminate code :-) - public static final int TERMINATE_CODE = 666; - // terminate command :-) - public static final String TERMINATE_NAME = "kill"; - - private static ErrorManager errMan; - - // ide running flag file - private static File ideRunning = null; - - - - // flag whether IDE was interrupted - private static boolean ideInterrupted = false; - - - // finds terminate process action in the action array - private static SystemAction findTerminateAction(SystemAction[] actions) { - if (actions == null) { - throw new IllegalArgumentException(); - } - // I need to get the string from resource bundle - // bundle = org.netbeans.core.execution.Bundle.properties - // key = terminateProcess - String terminateString = NbBundle.getMessage(org.netbeans.core.execution.ProcessNode.class,"terminateProcess"); - for (int i=0; i 0) { - // better sleep for a sec, so they can be really killed - try { - Thread.sleep(5000); - } catch (InterruptedException ie) { - // nothing - } - } - return notTerminatedProcesses; - } - - - /** Installs XTestErrorManager to NetBeans - * - */ - private static boolean installXTestErrorManager() { - try { - System.out.println("Installing XTestErrorManager"); - FileSystem systemFS = TopManager.getDefault().getRepository().findFileSystem("SystemFileSystem"); - DataFolder emFolder = DataFolder.findFolder(systemFS.getRoot().getFileObject("Services").getFileObject("Hidden")); - InstanceDataObject xem = InstanceDataObject.create(emFolder,"xem","org.netbeans.xtest.XTestErrorManager"); - // sleep for a sec, so ErrorManager gets installed - Thread.sleep(1000); - System.out.println("XTestErrorManager Installed"); - return true; - } catch (NullPointerException npe) { - // cannot install custom ErrorManager - return false; - } catch (IOException ioe) { - return false; - } catch (InterruptedException ie) { - return true; - } - } - - - /** Starts the IDE. - * @param args the command line arguments - */ - public static void main(String args[]) { - - // create the IDE flag file - String workdir = System.getProperty("xtest.workdir"); - if (workdir!=null) { - // create flag file indicating running tests - ideRunning = new File(workdir,"ide.flag"); - File idePID = new File(workdir,"ide.pid"); - PrintWriter writer = null; - try { - ideRunning.createNewFile(); - idePID.createNewFile(); - writer = new PrintWriter(new FileOutputStream(idePID)); - // get my pid - JNIKill kill = new JNIKill(); - long myPID = kill.getMyPID(); - System.out.println("IDE is running under PID:"+myPID); - writer.println(myPID); - } catch (IOException ioe) { - System.out.println("cannot create flag file:"+ideRunning); - ideRunning = null; - } catch (Throwable e) { - System.out.println("There was a problem: " + e); - } finally { - if (writer != null) - writer.close(); - } - } else { - System.out.println("cannot get xtest.workdir property - it has to be set to a valid working directory"); - } - - // do the expected stuff - try { - org.netbeans.core.Main.main(args); - } - catch (Exception e) { - e.printStackTrace(); - exit(); - } - - // install XTest error manager (only if xtest.error.manager=true) - // and openide version > 2 - - // get openide version - if sys property is not found - assume it is version 0 - float openideVersion = 0; - try { - openideVersion = Float.parseFloat(System.getProperty("org.openide.specification.version","0")); - } catch (NumberFormatException nfe) { - // property is not found - go on with 0 - } - - if (System.getProperty("xtest.error.manager","false").equals("true")) { - if (openideVersion > 2.0) { - boolean result = installXTestErrorManager(); - if (result==false) { - System.out.println("Cannot install XTestErrorManager"); - } else { - System.setProperty("xtest.error.manager","installed"); - } - } else { - System.out.println("OpenIDE version must be over 2.0 to use XTestErrorManager"); - System.out.println("Current version is "+openideVersion); - } - } - - - - - - // get the static ErrorManager instance - errMan = TopManager.getDefault().getErrorManager(); - - // some threads may be still active, wait for the event queue to become quiet - Thread initThread = new Thread(new Runnable() { - public void run() { - try { - new QueueEmpty().waitEventQueueEmpty(2000); - } - catch (Exception ex) { - TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex); - } - } - }); - // start the init thread - initThread.start(); - try { - initThread.join(60000L); // wait 1 minute at the most - } - catch (InterruptedException iex) { - errMan.notify(ErrorManager.EXCEPTION, iex); - - } - if (initThread.isAlive()) { - // time-out expired, event queue still busy -> interrupt the init thread - errMan.log(ErrorManager.USER, new Date().toString() + ": EventQueue still busy, starting anyway."); - initThread.interrupt(); - } - // ok. The IDE should be up and fully initialized - // let's run the test now - try { - doTestPart(); - } - catch (RuntimeException ex) { - ex.printStackTrace(); - } - } - - - private static final String TEST_CLASS = "test.class"; - private static final String TEST_CLASSPATH = "test.classpath"; - private static final String TEST_ARGS = "test.arguments"; - private static final String TEST_EXECUTOR = "test.executor"; - private static final String TEST_EXIT = "test.exit"; - private static final String TEST_FINISHED = "test.finished"; - private static final String TEST_TIMEOUT = "test.timeout"; - private static final String TEST_REDIRECT = "test.output.redirect"; - private static final String TEST_REUSE_IDE = "test.reuse.ide"; - - private static final long DEFAULT_TIMEOUT = 30; - - private static void doTestPart() { - - long testTimeout; - - // do nothing if no TEST_CLASS specified - if (System.getProperty(TEST_CLASS) == null) - return; - - if (System.getProperty(TEST_REDIRECT) != null && System.getProperty(TEST_REDIRECT).equals("true")) { - ((OutputSettings) Lookup.getDefault().lookup( OutputSettings.class )).setRedirection(true); - } - - try { - // default timeout is 30 minutes - testTimeout = Long.parseLong(System.getProperty(TEST_TIMEOUT, "30")); - } - catch (NumberFormatException ex) { - testTimeout = DEFAULT_TIMEOUT; - } - if (testTimeout <= 0) { - testTimeout = DEFAULT_TIMEOUT; - } - // convert to milis - testTimeout *= 60000L; - - StringTokenizer st = new StringTokenizer(System.getProperty(TEST_ARGS, "")); - final String[] params = new String[st.countTokens()]; - int i = 0; - while (st.hasMoreTokens()) { - params[i++] = st.nextToken(); - } - - final long startTime = System.currentTimeMillis(); - final long testTime = testTimeout; - Thread testThread = new Thread( new Runnable() { - public void run() { - try { - - // setup the repository - if (System.getProperty(TEST_CLASSPATH) != null && - System.getProperty(TEST_REUSE_IDE, "false").equals("false")) { - mountFileSystems(); - } - - setNodeProperties(); - - ExecInfo ei = new org.openide.execution.ExecInfo(System.getProperty(TEST_CLASS), params); - Executor exec = (Executor)Class.forName(System.getProperty(TEST_EXECUTOR, "org.openide.execution.ThreadExecutor")).newInstance(); - - if (exec != null) { - System.setProperty(TEST_FINISHED, "false"); - ExecutorTask task = exec.execute(ei); - - while (System.getProperty(TEST_FINISHED).equals("false")) { - try { - Thread.sleep(2000); - } - catch (InterruptedException e) { - long currentTime = System.currentTimeMillis(); - if (startTime + testTime + 10000 > currentTime) { - break; - } - else { - errMan.log(ErrorManager.USER, new Date().toString() + ": False InterruptedException. Continuing running tests"); - } - } - } - } - } - catch (Exception ex) { - TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex); - } - } - }); - - errMan.log(ErrorManager.USER, new Date().toString() + ": just starting."); - // start the test thread - testThread.start(); - try { - testThread.join(testTimeout); - } - catch (InterruptedException iex) { - errMan.notify(ErrorManager.EXCEPTION, iex); - } - if (testThread.isAlive()) { - // time-out expired, test not finished -> interrupt - errMan.log(ErrorManager.USER, new Date().toString() + ": time-out expired - interrupting! ***"); - ideInterrupted = true; - testThread.interrupt(); - } - - // we're leaving IDE - // delete the flag file (if ide was not interrupted) - if (ideRunning!=null) { - if (!ideInterrupted) { - if (ideRunning.delete()==false) { - System.out.println("Cannot delete the flag file "+ideRunning); - } - } - } - - // close IDE - if (System.getProperty(TEST_EXIT, "false").equals("true")) { - Thread exitThread = new Thread(new Runnable() { - public void run() { - // terminate all running processes - try { - terminateProcesses(); - } catch (Exception e) { - System.out.println("Exception when terminating processes started from IDE"); - e.printStackTrace(); - } - TopManager.getDefault().exit(); - } - }); - // try to exit nicely first - errMan.log(ErrorManager.USER, new Date().toString() + ": soft exit attempt."); - exitThread.start(); - try { - // wait 90 seconds for the IDE to exit - exitThread.join(90000); - } - catch (InterruptedException iex) { - errMan.notify(ErrorManager.EXCEPTION, iex); - } - if (exitThread.isAlive()) { - // IDE refuses to shutdown, terminate unconditionally - errMan.log(ErrorManager.USER, new Date().toString() + ": hard exit attempt!!!."); - exitThread.interrupt(); - exit(); - } - } - } - - private static void exit() { - try { - Class param[] = new Class[1]; - param[0] = int.class; - Class c = org.netbeans.core.execution.TopSecurityManager.class; - java.lang.reflect.Method m = c.getMethod("exit",param); - Integer intparam[] = {new Integer(1)}; - errMan.log(ErrorManager.USER, new Date().toString() + ": using TopSecurityManager.exit(1) to exit IDE."); - // exit - m.invoke(null,intparam); - } - catch (Exception e) { - errMan.log(ErrorManager.USER, new Date().toString() + ": using System.exit(1) to exit IDE."); - // exit - System.exit(1); - } - } - - - private static void mountFileSystems() { - Repository repo = TopManager.getDefault().getRepository(); - - // unmount the currently mounted filesystems - // (could be more sofisticated some day) - Enumeration all = repo.getFileSystems(); - while (all.hasMoreElements()) { - FileSystem fs = (FileSystem)all.nextElement(); - // preserve the hidden and default filesystems - if (!fs.isHidden() && !fs.isDefault()) - repo.removeFileSystem(fs); - } - // mount new filesystems as specified in TEST_CLASSPATH - StringTokenizer stok = new StringTokenizer(System.getProperty(TEST_CLASSPATH), System.getProperty("path.separator")); - while (stok.hasMoreElements()) { - String pathelem = stok.nextToken(); - try { - if (pathelem.endsWith(".jar") || pathelem.endsWith(".zip")) { - JarFileSystem jfs = new JarFileSystem(); - jfs.setJarFile(new java.io.File(pathelem)); - repo.addFileSystem(jfs); - } - else { - LocalFileSystem lfs = new LocalFileSystem(); - lfs.setRootDirectory(new java.io.File(pathelem)); - repo.addFileSystem(lfs); - } - } - catch (Exception ex) { - TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex); - } - } - } - - - private static void setNodeProperties() { - FileObject fo = TopManager.getDefault().getRepository().findResource(System.getProperty(TEST_CLASS) + ".java"); - if (fo != null) { - try { - DataObject obj = DataObject.find(fo); - Node nod = obj.getNodeDelegate(); - Node.PropertySet[] psets = nod.getPropertySets(); - Node.Property[] props = null; - - // get the Execution property set - for (int i = 0; i < psets.length; i++) { - if (psets[i].getName().equals("Execution")) { - props = psets[i].getProperties(); - break; - } - } - // get the "params" property and try to set it - if (props != null) { - for (int i = 0; i < props.length; i++) { - if (props[i].getName().equals("params")) { - if (System.getProperty(TEST_ARGS) != null) { - props[i].setValue(System.getProperty(TEST_ARGS)); - } - } - } - } - } - catch (java.lang.Exception ex) { - // ok, not able to set the Arguments property - // it's still worth trying to proceed with the test - // the FileObject may just be read-only - } - - } - - } - - - private static class QueueEmpty implements java.awt.event.AWTEventListener { - - private long eventDelayTime = 100; // 100 millis - private long lastEventTime; - - /** Creates a new QueueEmpty instance */ - public QueueEmpty() { - } - - /** method called every time when AWT Event is dispatched - * @param event event dispatched from AWT Event Queue - */ - public void eventDispatched(java.awt.AWTEvent awtEvent) { - lastEventTime = System.currentTimeMillis(); - } - - /** constructor with user defined value - * @param eventdelaytime maximum delay between two events of one redraw action - */ - public synchronized void waitEventQueueEmpty(long eventDelayTime) throws InterruptedException { - this.eventDelayTime = eventDelayTime; - waitEventQueueEmpty(); - } - - /** Waits until the AWTEventQueue is empty for a specified interval - */ - public synchronized void waitEventQueueEmpty() throws InterruptedException { - // store current time as the start time - long startTime = System.currentTimeMillis(); - // register itself as an AWTEventListener - Toolkit.getDefaultToolkit().addAWTEventListener(this, - AWTEvent.ACTION_EVENT_MASK | - AWTEvent.ADJUSTMENT_EVENT_MASK | - AWTEvent.COMPONENT_EVENT_MASK | - AWTEvent.CONTAINER_EVENT_MASK | - AWTEvent.FOCUS_EVENT_MASK | - AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK | - AWTEvent.HIERARCHY_EVENT_MASK | - AWTEvent.INPUT_METHOD_EVENT_MASK | - AWTEvent.INVOCATION_EVENT_MASK | - AWTEvent.ITEM_EVENT_MASK | - AWTEvent.KEY_EVENT_MASK | - AWTEvent.MOUSE_EVENT_MASK | - AWTEvent.MOUSE_MOTION_EVENT_MASK | - AWTEvent.PAINT_EVENT_MASK | - AWTEvent.TEXT_EVENT_MASK | - AWTEvent.WINDOW_EVENT_MASK); - - // set last event time to the current time - lastEventTime=System.currentTimeMillis(); - // get the thread to be put asleep - Thread t = Thread.currentThread(); - // get current AWT Event Queue - EventQueue queue=Toolkit.getDefaultToolkit().getSystemEventQueue(); - - try { - - // while AWT Event Queue is not empty and timedelay from last event is shorter then eventdelaytime - - //wait till the queue is empty - while ( queue.peekEvent() != null ) Thread.currentThread().sleep(100); - //test it - post my own task and wait for it - synchronized(this){ - Runnable r = new Runnable() { - public void run() { - synchronized(QueueEmpty.this){QueueEmpty.this.notifyAll();} - } - }; - queue.invokeLater(r); - wait(); - } - //now 2 sec continuously should be silence - while (System.currentTimeMillis() - lastEventTime < eventDelayTime) { - //sleep for the rest of eventDelay time - t.sleep(eventDelayTime + lastEventTime - System.currentTimeMillis()); - } - - //if (queue.peekEvent()==null) System.out.println("The AWT event queue seems to be empty."); - //else System.out.println("Ops, in the AWT event queue still seems to be some tasks!"); - - } - catch (InterruptedException ex) { - throw ex; - } - finally { - //removing from listeners - Toolkit.getDefaultToolkit().removeAWTEventListener(this); - } - } - - - } -} - Index: nb_all/xtest/src/org/netbeans/core/modules/Module.java =================================================================== RCS file: nb_all/xtest/src/org/netbeans/core/modules/Module.java diff -N nb_all/xtest/src/org/netbeans/core/modules/Module.java --- nb_all/xtest/src/org/netbeans/core/modules/Module.java 6 Mar 2002 14:15:04 -0000 1.6 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,942 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.core.modules; - -// THIS CLASS OUGHT NOT USE NbBundle NOR org.openide CLASSES -// OUTSIDE OF openide-util.jar! UI AND FILESYSTEM/DATASYSTEM -// INTERACTIONS SHOULD GO ELSEWHERE. -// (NbBundle.getLocalizedValue is OK here.) - -import org.openide.modules.ModuleInfo; -import org.openide.ErrorManager; -import java.io.*; -import java.util.*; -import java.util.jar.*; -import java.net.URL; -import java.security.*; -import org.openide.util.NbBundle; -import java.util.zip.ZipEntry; -import org.openide.modules.SpecificationVersion; -import org.openide.modules.Dependency; - -/** Object representing one module, possibly installed. - * Responsible for opening of module JAR file; reading - * manifest; parsing basic information such as dependencies; - * and creating a classloader for use by the installer. - * Methods not defined in ModuleInfo must be called from within - * the module manager's read mutex as a rule. - * @author Jesse Glick - */ -public final class Module extends ModuleInfo { - - public static final String PROP_RELOADABLE = "reloadable"; // NOI18N - public static final String PROP_CLASS_LOADER = "classLoader"; // NOI18N - public static final String PROP_MANIFEST = "manifest"; // NOI18N - public static final String PROP_VALID = "valid"; // NOI18N - public static final String PROP_PROBLEMS = "problems"; // NOI18N - - /** manager which owns this module */ - private final ModuleManager mgr; - /** event logging (should not be much here) */ - private final Events ev; - /** associated history object - * @see ModuleHistory - */ - private final Object history; - /** JAR file holding the module */ - private final File jar; - /** if reloadable, temporary JAR file actually loaded from */ - private File physicalJar = null; - /** true if currently enabled; manipulated by ModuleManager */ - private boolean enabled; - /** whether it is supposed to be easily reloadable */ - private boolean reloadable; - /** whether it is supposed to be automatically loaded when required */ - private final boolean autoload; - /** if true, this module is eagerly turned on whenever it can be */ - private final boolean eager; - /** module manifest */ - private Manifest manifest; - /** code name base (no slash) */ - private String codeNameBase; - /** code name release, or -1 if undefined */ - private int codeNameRelease; - /** provided tokens */ - private String[] provides; - /** set of dependencies parsed from manifest */ - private Set dependencies; - /** specification version parsed from manifest, or null */ - private SpecificationVersion specVers; - /** currently active module classloader */ - private ClassLoader classloader = null; - /** localized properties, or null to use only manifest */ - private Properties localizedProps; - - /** Map from extension JARs to sets of JAR that load them via Class-Path. - * Used only for debugging purposes, so that a warning is printed if two - * different modules try to load the same extension (which would cause them - * to both load their own private copy, which may not be intended). - */ - private static final Map extensionOwners = new HashMap(); // Map> - - /** Set of locale-variants JARs for this module. - * Added explicitly to classloader, and can be used by execution engine. - */ - private final Set localeVariants = new HashSet(); // Set - /** Set of extension JARs that this module loads via Class-Path. - * Can be used e.g. by execution engine. (#9617) - */ - private final Set plainExtensions = new HashSet(); // Set - /** Set of localized extension JARs derived from plainExtensions. - * Used to add these to the classloader. (#9348) - * Can be used e.g. by execution engine. - */ - private final Set localeExtensions = new HashSet(); // Set - - /** Use ModuleManager.create as a factory. */ - Module(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException { - if (autoload && eager) throw new IllegalArgumentException("A module may not be both autoload and eager"); // NOI18N - this.mgr = mgr; - this.ev = ev; - this.jar = jar; - this.history = history; - this.reloadable = reloadable; - this.autoload = autoload; - this.eager = eager; - enabled = false; - loadManifest(); - parseManifest(); - } - - - /** hack !!! - old (release33) constructor */ - Module(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload) throws IOException { - this(mgr,ev,jar,history,reloadable,autoload,false); - } - - - - /** Create a special-purpose "fixed" JAR. */ - Module(ModuleManager mgr, Events ev, Manifest manifest, Object history, ClassLoader classloader) throws InvalidException { - this.mgr = mgr; - this.ev = ev; - this.manifest = manifest; - this.history = history; - this.classloader = classloader; - jar = null; - reloadable = false; - autoload = false; - eager = false; - enabled = false; - parseManifest(); - } - - /** Get the associated module manager. */ - public ModuleManager getManager() { - return mgr; - } - - public boolean isEnabled() { - return enabled; - } - - // Access from ModuleManager: - void setEnabled(boolean enabled) { - /* #13647: actually can happen if loading of bootstrap modules is rolled back: - if (isFixed() && ! enabled) throw new IllegalStateException("Cannot disable a fixed module: " + this); // NOI18N - */ - this.enabled = enabled; - } - - /** Normally a module once created and managed is valid - * (that is, either installed or not, but at least managed). - * If it is deleted any remaining references to it become - * invalid. - */ - public boolean isValid() { - return mgr.get(getCodeNameBase()) == this; - } - - /** Is this module automatically loaded? - * If so, no information about its state is kept - * permanently beyond the existence of its JAR file; - * it is enabled when some real module needs it to be, - * and disabled when this is no longer the case. - * @see #9779 - */ - public boolean isAutoload() { - return autoload; - } - - /** Is this module eagerly enabled? - * If so, no information about its state is kept permanently. - * It is turned on whenever it can be, i.e. whenever it meets all of - * its dependencies. This may be used to implement "bridge" modules with - * simple functionality that just depend on two normal modules. - * A module may not be simultaneously eager and autoload. - * @see #17501 - * @since org.netbeans.core/1 1.3 - */ - public boolean isEager() { - return eager; - } - - /** Get an associated arbitrary attribute. - * Right now, simply provides the main attributes of the manifest. - * In the future some of these could be suppressed (if only of dangerous - * interest, e.g. Class-Path) or enhanced with other information available - * from the core (if needed). - */ - public Object getAttribute(String attr) { - return getManifest().getMainAttributes().getValue(attr); - } - - /** Get a localized attribute. - * First, if OpenIDE-Module-Localizing-Bundle was given, the specified - * bundle file (in all locale JARs as well as base JAR) is searched for - * a key of the specified name. - * Otherwise, the manifest's main attributes are searched for an attribute - * with the specified name, possibly with a locale suffix. - * If the attribute name contains a slash, and there is a manifest section - * named according to the part before the last slash, then this section's attributes - * are searched instead of the main attributes, and for the attribute listed - * after the slash. Currently this would only be useful for localized filesystem - * names. E.g. you may request the attribute org/foo/MyFileSystem.class/Display-Name. - * In the future certain attributes known to be dangerous could be - * explicitly suppressed from this list; should only be used for - * documented localizable attributes such as OpenIDE-Module-Name etc. - */ - public Object getLocalizedAttribute(String attr) { - if (localizedProps != null) { - // Permit localized attributes to be defined in a separate bundle. - String val = localizedProps.getProperty(attr); - if (val != null) { - return val; - } - } - int idx = attr.lastIndexOf('/'); // NOI18N - if (idx == -1) { - // Simple main attribute. - return NbBundle.getLocalizedValue(getManifest().getMainAttributes(), new Attributes.Name(attr)); - } else { - // Attribute of a manifest section. - String section = attr.substring(0, idx); - String realAttr = attr.substring(idx + 1); - Attributes attrs = getManifest().getAttributes(section); - if (attrs != null) { - return NbBundle.getLocalizedValue(attrs, new Attributes.Name(realAttr)); - } else { - return null; - } - } - } - - public String getCodeName() { - return (String)getAttribute("OpenIDE-Module"); // NOI18N - } - - public String getCodeNameBase() { - return codeNameBase; - } - - public int getCodeNameRelease() { - return codeNameRelease; - } - - public String[] getProvides() { - return provides; - } - /** Test whether the module provides a given token or not. */ - final boolean provides(String token) { - for (int i = 0; i < provides.length; i++) { - if (provides[i].equals(token)) { - return true; - } - } - return false; - } - - public Set getDependencies() { - return dependencies; - } - // Just for binary compatibility, this is not the real impl in core: - final Dependency[] getDependenciesArray() { - return (Dependency[])dependencies.toArray(new Dependency[dependencies.size()]); - } - - public SpecificationVersion getSpecificationVersion() { - return specVers; - } - - public boolean owns(Class clazz) { - ClassLoader cl = clazz.getClassLoader(); - if (cl instanceof Util.ModuleProvider) { - return ((Util.ModuleProvider) cl).getModule() == this; - } - return false; - - } - - /** Original parseManifest - will decide whether to call - * parseManifest_New for trunk release or parseManifest_Old - * for release 33 - */ - private void parseManifest() throws InvalidException { - // have to use reflection and try to obtain - // ModuleManager.refineDependencies() - // if any problem is encountered with reflection -- fallback to - // the new version of parseManifest - try { - Class parameterTypes[] = new Class[2]; - parameterTypes[0] = this.getClass(); - parameterTypes[1] = Set.class; - java.lang.reflect.Method aMethod = mgr.getClass().getDeclaredMethod("refineDependencies",parameterTypes); - // good call parseManifest_New() - in finally blockk; - } catch (NoSuchMethodException nsme) { - // using old parseManifest - //System.out.println("XTest hack in org.netbeans.core.modules.Module.java: using old parseManifest()"); - parseManifest_Old(); - return; - } catch (Throwable t) { - // any problem - use new parseManifest - //System.out.println("XTest hack in org.netbeans.core.modules.Module.java: using new parseManifest() cannot get info on ModuleManager"); - parseManifest_New(); - } - //System.out.println("XTest hack in org.netbeans.core.modules.Module.java: using new parseManifest()"); - parseManifest_New(); - - } - - - /** Parse information from the current manifest. - * Includes code name, specification version, and dependencies. - * If anything is in an invalid format, throws an exception with - * some kind of description of the problem. - */ - private void parseManifest_New() throws InvalidException { - Attributes attr = manifest.getMainAttributes(); - // Code name - String codeName = attr.getValue("OpenIDE-Module"); // NOI18N - if (codeName == null) throw new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + /* #17629: important! */jar); // NOI18N - try { - // This has the side effect of checking syntax: - if (codeName.indexOf(',') != -1) { - throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module: " + codeName); // NOI18N - } - Dependency.create(Dependency.TYPE_MODULE, codeName); - int idx = codeName.lastIndexOf('/'); // NOI18N - if (idx == -1) { - codeNameBase = codeName; - codeNameRelease = -1; - } else { - codeNameBase = codeName.substring(0, idx); - codeNameRelease = Integer.parseInt(codeName.substring(idx + 1)); - } - // Spec vers - String specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); // NOI18N - if (specVersS != null) { - try { - specVers = new SpecificationVersion(specVersS); - } catch (NumberFormatException nfe) { - InvalidException ie = new InvalidException("While parsing OpenIDE-Module-Specification-Version: " + nfe.toString()); // NOI18N - Util.err.annotate(ie, nfe); - throw ie; - } - } else { - specVers = null; - } - // Token provides - String providesS = attr.getValue("OpenIDE-Module-Provides"); // NOI18N - if (providesS == null) { - provides = new String[] {}; - } else { - StringTokenizer tok = new StringTokenizer(providesS, ", "); // NOI18N - provides = new String[tok.countTokens()]; - for (int i = 0; i < provides.length; i++) { - String provide = tok.nextToken(); - if (provide.indexOf(',') != -1) { - throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module-Provides: " + provide); // NOI18N - } - Dependency.create(Dependency.TYPE_MODULE, provide); - if (provide.lastIndexOf('/') != -1) throw new IllegalArgumentException("Illegal OpenIDE-Module-Provides: " + provide); - provides[i] = provide; - } - if (new HashSet(Arrays.asList(provides)).size() < provides.length) { - throw new IllegalArgumentException("Duplicate entries in OpenIDE-Module-Provides: " + providesS); - } - } - // Dependencies - Set dependencies = new HashSet(20); // Set - dependencies.addAll(Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies"))); // NOI18N - dependencies.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); // NOI18N - dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); // NOI18N - dependencies.addAll(Dependency.create(Dependency.TYPE_PACKAGE, attr.getValue("OpenIDE-Module-Package-Dependencies"))); // NOI18N - dependencies.addAll(Dependency.create(Dependency.TYPE_REQUIRES, attr.getValue("OpenIDE-Module-Requires"))); // NOI18N - // Permit the concrete installer to make some changes: - mgr.refineDependencies(this, dependencies); - // Now copy (avoid synch problems): - this.dependencies = Collections.unmodifiableSet(dependencies); - } catch (IllegalArgumentException iae) { - InvalidException ie = new InvalidException("While parsing a dependency attribute: " + iae.toString()); // NOI18N - Util.err.annotate(ie, iae); - throw ie; - } - } - - /** Old version of parse manifest - for release33 compatibility - * Use at your own risk - */ - private void parseManifest_Old() throws InvalidException { - Attributes attr = manifest.getMainAttributes(); - // Code name - String codeName = attr.getValue("OpenIDE-Module"); // NOI18N - if (codeName == null) throw new InvalidException("Not a module: no OpenIDE-Module tag"); // NOI18N - try { - // This has the side effect of checking syntax: - if (codeName.indexOf(',') != -1) { - throw new InvalidException("Illegal code name syntax: " + codeName); // NOI18N - } - Dependency.create(Dependency.TYPE_MODULE, codeName); - int idx = codeName.lastIndexOf('/'); // NOI18N - if (idx == -1) { - codeNameBase = codeName; - codeNameRelease = -1; - } else { - codeNameBase = codeName.substring(0, idx); - codeNameRelease = Integer.parseInt(codeName.substring(idx + 1)); - } - // Spec vers - String specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); // NOI18N - if (specVersS != null) { - try { - specVers = new SpecificationVersion(specVersS); - } catch (NumberFormatException nfe) { - InvalidException ie = new InvalidException(nfe.toString()); - Util.err.annotate(ie, nfe); - throw ie; - } - } else { - specVers = null; - } - // Dependencies - Set dependencies = new HashSet(20); // Set - dependencies.addAll(Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies"))); // NOI18N - dependencies.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); // NOI18N - dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); // NOI18N - dependencies.addAll(Dependency.create(Dependency.TYPE_PACKAGE, attr.getValue("OpenIDE-Module-Package-Dependencies"))); // NOI18N - // Now copy (avoid synch problems): - this.dependencies = Collections.unmodifiableSet(dependencies); - } catch (IllegalArgumentException iae) { - InvalidException ie = new InvalidException(iae.toString()); - Util.err.annotate(ie, iae); - throw ie; - } - } - - - - /** Get the JAR this module is packaged in. - * May be null for modules installed specially, e.g. - * automatically from the classpath. - * @see #isFixed - */ - public File getJarFile() { - return jar; - } - - /** Check if this is a "fixed" module. - * Fixed modules are installed automatically (e.g. based on classpath) - * and cannot be uninstalled or manipulated in any way. - */ - public boolean isFixed() { - return jar == null; - } - - /** Create a temporary test JAR if necessary. - * This is primarily necessary to work around a Java bug, - * #4405789, which might be fixed in 1.4--check up on this. - */ - private void ensurePhysicalJar() throws IOException { - if (reloadable && physicalJar == null) { - physicalJar = Util.makeTempJar(jar); - } - } - private void destroyPhysicalJar() { - if (physicalJar != null) { - if (! physicalJar.delete()) { - Util.err.log(ErrorManager.WARNING, "Warning: temporary JAR " + physicalJar + " not currently deletable."); - } else { - Util.err.log("deleted: " + physicalJar); - } - physicalJar = null; - } else { - Util.err.log("no physicalJar to delete for " + this); - } - } - - /** Open the JAR, load its manifest, and do related things. */ - private void loadManifest() throws IOException { - Util.err.log("loading manifest of " + jar); - JarFile jarFile; - if (reloadable) { - ensurePhysicalJar(); - jarFile = new JarFile(physicalJar); - } else { - jarFile = new JarFile(jar); - } - try { - Manifest m = jarFile.getManifest(); - findExtensionsAndVariants(m); - loadLocalizedProps(jarFile, m); - manifest = m; - } finally { - jarFile.close(); - } - } - - /** Find any extensions loaded by the module, as well as any localized - * variants of the module or its extensions. - */ - private void findExtensionsAndVariants(Manifest m) { - localeVariants.clear(); - localeVariants.addAll(Util.findLocaleVariantsOf(jar, false)); - plainExtensions.clear(); - localeExtensions.clear(); - String classPath = m.getMainAttributes().getValue(Attributes.Name.CLASS_PATH); - if (classPath != null) { - StringTokenizer tok = new StringTokenizer(classPath); - while (tok.hasMoreTokens()) { - String ext = tok.nextToken(); - File extfile = new File(jar.getParentFile(), ext.replace('/', File.separatorChar)); - if (! extfile.exists()) { - // Ignore unloadable extensions. - continue; - } - synchronized (extensionOwners) { - Set owners = (Set)extensionOwners.get(extfile); - if (owners == null) { - owners = new HashSet(2); - owners.add(jar); - extensionOwners.put(extfile, owners); - } else if (! owners.contains(jar)) { - owners.add(jar); - ev.log(Events.EXTENSION_MULTIPLY_LOADED, extfile, owners); - } // else already know about it (OK or warned) - } - plainExtensions.add(extfile); - localeExtensions.addAll(Util.findLocaleVariantsOf(extfile, false)); - } - } - Util.err.log("localeVariants of " + jar + ": " + localeVariants); - Util.err.log("plainExtensions of " + jar + ": " + plainExtensions); - Util.err.log("localeExtensions of " + jar + ": " + localeExtensions); - } - - /** Check if there is any need to load localized properties. - * If so, try to load them. Throw an exception if they cannot - * be loaded for some reason. Uses an open JAR file for the - * base module at least, though may also open locale variants - * as needed. - * @see #12549 - */ - private void loadLocalizedProps(JarFile jarFile, Manifest m) throws IOException { - String locbundle = m.getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N - if (locbundle != null) { - // Something requested, read it in. - // locbundle is a resource path. - { - ZipEntry bundleFile = jarFile.getEntry(locbundle); - // May not be present in base JAR: might only be in e.g. default locale variant. - if (bundleFile != null) { - localizedProps = new Properties(); - InputStream is = jarFile.getInputStream(bundleFile); - try { - localizedProps.load(is); - } finally { - is.close(); - } - } - } - { - // Check also for localized variant JARs and load in anything from them as needed. - // Note we need to go in the reverse of the usual search order, so as to - // overwrite less specific bundles with more specific. - int idx = locbundle.lastIndexOf('.'); // NOI18N - String name, ext; - if (idx == -1) { - name = locbundle; - ext = ""; // NOI18N - } else { - name = locbundle.substring(0, idx); - ext = locbundle.substring(idx); - } - List pairs = Util.findLocaleVariantsOf(jar, true); - Collections.reverse(pairs); - Iterator it = pairs.iterator(); - while (it.hasNext()) { - Object[] pair = (Object[])it.next(); - File localeJar = (File)pair[0]; - String suffix = (String)pair[1]; - String rsrc = name + suffix + ext; - JarFile localeJarFile = new JarFile(localeJar); - try { - ZipEntry bundleFile = localeJarFile.getEntry(rsrc); - // Need not exist in all locale variants. - if (bundleFile != null) { - if (localizedProps == null) { - localizedProps = new Properties(); - } // else append and overwrite base-locale values - InputStream is = localeJarFile.getInputStream(bundleFile); - try { - localizedProps.load(is); - } finally { - is.close(); - } - } - } finally { - localeJarFile.close(); - } - } - } - if (localizedProps == null) { - // We should have loaded from at least some bundle in there... - throw new IOException("Could not find localizing bundle: " + locbundle); // NOI18N - } - /* Don't log; too large and annoying: - if (Util.err.isLoggable(ErrorManager.UNKNOWN)) { - Util.err.log("localizedProps=" + localizedProps); - } - */ - } - } - - /** Get all JARs loaded by this module. - * Includes the module itself, any locale variants of the module, - * any extensions specified with Class-Path, any locale variants - * of those extensions. - * If patches are implemented (#9273), the list will be in classpath order (patches first). - * Currently the temp JAR is provided in the case of test modules, to prevent - * sporadic ZIP file exceptions when background threads (like Java parsing) tries - * to open libraries found in the library path. - * JARs already present in the classpath are not listed. - * @return a List<File> of JARs - */ - public List getAllJars() { - if (jar == null) { - // Classpath module. - return Collections.EMPTY_LIST; - } - List l = new ArrayList (); // List - l.add (reloadable ? physicalJar : jar); - l.addAll (plainExtensions); - l.addAll (localeVariants); - l.addAll (localeExtensions); - return l; - } - - /** Is this module supposed to be easily reloadable? - * If so, it is suitable for testing inside the IDE. - * Controls whether a copy of the JAR file is made before - * passing it to the classloader, which can affect locking - * and refreshing of the JAR. - */ - public boolean isReloadable() { - return reloadable; - } - - /** Set whether this module is supposed to be reloadable. - * Has no immediate effect, only impacts what happens the - * next time it is enabled (after having been disabled if - * necessary). - */ - public void setReloadable(boolean r) { - if (isFixed()) throw new IllegalStateException(); - if (reloadable != r) { - reloadable = r; - mgr.fireReloadable(this); - } - } - - /** Used as a flag to tell if this module was really successfully released. - * Currently does not work, so if it cannot be made to work, delete it. - * (Someone seems to be holding a strong reference to the classloader--who?!) - */ - private transient boolean released; - /** Count which release() call is really being checked. */ - private transient int releaseCount = 0; - - /** Reload this module. Access from ModuleManager. - * If an exception is thrown, the module is considered - * to be in an invalid state. - */ - void reload() throws IOException { - if (isFixed()) throw new IllegalStateException(); - // Probably unnecessary but just in case: - destroyPhysicalJar(); - String codeNameBase1 = getCodeNameBase(); - localizedProps = null; - loadManifest(); - parseManifest(); - String codeNameBase2 = getCodeNameBase(); - if (! codeNameBase1.equals(codeNameBase2)) { - throw new InvalidException("Code name base changed during reload: " + codeNameBase1 + " -> " + codeNameBase2); // NOI18N - } - } - - /** Get the classloader capable of retrieving - * things from this module. - * If the module is disabled, this will be null (unless this module is fixed). - * If it is enabled, it must not be null. - * It is not guaranteed that change events will be fired - * for changes in this property. - */ - public ClassLoader getClassLoader() { - return classloader; - } - // Access from ModuleManager: - /** Turn on the classloader. Passed a list of parent modules to use. - * The parents should already have had their classloaders initialized. - */ - void classLoaderUp(Set parents) throws IOException { - if (isFixed()) return; // no need - Util.err.log("classLoaderUp on " + this + " with parents " + parents); - // Find classloaders for dependent modules and parent to them. - ClassLoader[] loaders = new ClassLoader[parents.size()]; - Iterator it = parents.iterator(); - int i = 0; - while (it.hasNext()) { - Module parent = (Module)it.next(); - loaders[i++] = parent.getClassLoader(); - } - List classp = new ArrayList(3); // List - // #9273: load any modules/patches/this-code-name/*.jar files first: - File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N - getCodeNameBase().replace('.', '-')); // NOI18N - if (patchdir.isDirectory()) { - File[] jars = patchdir.listFiles(Util.jarFilter()); - if (jars != null) { - for (int j = 0; j < jars.length; j++) { - ev.log(Events.PATCH, jars[j]); - classp.add(new JarFile(jars[j])); - } - } else { - Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir); - } - } - - // load tests by the same classloader as module classes - // this classpath was formerly mounted to repository - String testcp = System.getProperty("tbag.classpath"); - String xclname = System.getProperty("xtest.useclassloader"); - if ( xclname != null && xclname.equals ( getCodeNameBase() ) ) { - if ( testcp != null ) { - StringTokenizer stok = new StringTokenizer( testcp, System.getProperty("path.separator") ); - while ( stok.hasMoreElements() ) { - String testp = (String) stok.nextElement(); - File testdir = new File ( testp ); - if ( testdir.isDirectory() ) { - Util.err.log(ErrorManager.WARNING, "---> Adding test dir: " + testdir + " for " + getCodeNameBase()); - File [] jars = testdir.listFiles( Util.jarFilter() ); - if ( jars != null ) { - for ( int j = 0; j < jars.length; j++ ) { - // add all jar files - classp.add( new JarFile( jars[j] ) ); - } - } - // add dir itself - classp.add ( (Object) testdir ); - } - } - } - } - - if (reloadable) { - ensurePhysicalJar(); - classp.add(new JarFile(physicalJar)); - } else { - classp.add(new JarFile(jar)); - } - // URLClassLoader would not otherwise find these, so: - for (it = localeVariants.iterator(); it.hasNext(); ) { - classp.add(new JarFile((File)it.next())); - } - for (it = localeExtensions.iterator(); it.hasNext(); ) { - File act = (File)it.next(); - classp.add(act.isDirectory() ? (Object)act : new JarFile(act)); - } - for( it = plainExtensions.iterator(); it.hasNext(); ) { - File act = (File)it.next(); - classp.add(act.isDirectory() ? (Object)act : new JarFile(act)); - } - try { - classloader = new OneModuleClassLoader(classp, loaders); - } catch (IllegalArgumentException iae) { - // Should not happen, but just in case. - IOException ioe = new IOException(iae.toString()); - Util.err.annotate(ioe, iae); - throw ioe; - } - } - /** Turn off the classloader and release all resources. */ - void classLoaderDown() { - if (isFixed()) return; // don't touch it - if (classloader instanceof ProxyClassLoader) { - // Remove references to it from other places, i.e. ModuleClassLoader: - ((ProxyClassLoader)classloader).destroy(); - } - classloader = null; - Util.err.log("classLoaderDown on " + this + ": releaseCount=" + releaseCount + " released=" + released); - released = false; - System.gc(); // hope OneModuleClassLoader.finalize() is called... - // but probably it won't be. See #4405807. - if (! released) { - Util.err.log("Warning: not all resources associated with module " + jar + " were successfully released."); - released = true; - } else { - Util.err.log ("All resources associated with module " + jar + " were successfully released."); - } - destroyPhysicalJar(); - } - /** For compat only! */ - void cleanup() {} - void destroy() {} - - /** Get the JAR manifest. - * Should never be null, even if disabled. - * Might change if a module is reloaded. - * It is not guaranteed that change events will be fired - * for changes in this property. - */ - public Manifest getManifest() { - return manifest; - } - - /** Get a set of {@link org.openide.modules.Dependency} objects representing missed dependencies. - * This module is examined to see - * why it would not be installable. - * If it is enabled, there are no problems. - * If it is in fact installable (possibly only - * by also enabling some other managed modules which are currently disabled), and - * all of its non-module dependencies are met, the returned set will be empty. - * Otherwise it will contain a list of reasons why this module cannot be installed: - * non-module dependencies which are not met; and module dependencies on modules - * which either do not exist in the managed set, or are the wrong version, - * or themselves cannot be installed - * for some reason or another (which may be separately examined). - * Note that in the (illegal) situation of two or more modules forming a cyclic - * dependency cycle, none of them will be installable, and the missing dependencies - * for each will be stated as the dependencies on the others. Again other modules - * dependent on modules in the cycle will list failed dependencies on the cyclic modules. - * Missing package dependencies are not guaranteed to be reported unless an install - * of the module has already been attempted, and failed due to them. - * The set may also contain {@link InvalidException}s representing known failures - * of the module to be installed, e.g. due to classloader problems, missing runtime - * resources, or failed ad-hoc dependencies. Again these are not guaranteed to be - * reported unless an install has already been attempted and failed due to them. - */ - public Set getProblems() { - if (! isValid()) throw new IllegalStateException("Not valid: " + this); // NOI18N - if (isEnabled()) return Collections.EMPTY_SET; - return Collections.unmodifiableSet(mgr.missingDependencies(this)); - } - - // Access from ChangeFirer: - final void firePropertyChange0(String prop, Object old, Object nue) { - if (Util.err.isLoggable(ErrorManager.UNKNOWN)) { - Util.err.log("Module.propertyChange: " + this + " " + prop + ": " + old + " -> " + nue); - } - firePropertyChange(prop, old, nue); - } - - /** Get the history object representing what has happened to this module before. - * @see ModuleHistory - */ - public final Object getHistory() { - return history; - } - - /** String representation for debugging. */ - public String toString() { - String s = "Module[" + getCodeNameBase() + "]"; // NOI18N - if (!isValid()) s += "[invalid]"; // NOI18N - return s; - } - - /** PermissionCollection with an instance of AllPermission. */ - private static PermissionCollection modulePermissions; - /** @return initialized @see #modulePermission */ - private static synchronized PermissionCollection getAllPermission() { - if (modulePermissions == null) { - modulePermissions = new Permissions(); - modulePermissions.add(new AllPermission()); - modulePermissions.setReadOnly(); - } - return modulePermissions; - } - - /** Class loader to load a single module. - * Auto-localizing, multi-parented, permission-granting, the works. - */ - private class OneModuleClassLoader extends JarClassLoader implements Util.ModuleProvider, Util.PackageAccessibleClassLoader { - private int rc; - /** Create a new loader for a module. - * @param classp the List of all module jars of code directories; - * includes the module itself, its locale variants, - * variants of extensions and Class-Path items from Manifest. - * The items are JarFiles for jars and Files for directories - * @param parents a set of parent classloaders (from other modules) - */ - public OneModuleClassLoader(List classp, ClassLoader[] parents) throws IllegalArgumentException { - super(classp, parents); - rc = releaseCount++; - } - - public Module getModule() { - return Module.this; - } - - /** Inherited. - * @param cs is ignored - * @return PermissionCollection with an AllPermission instance - */ - protected PermissionCollection getPermissions(CodeSource cs) { - return getAllPermission(); - } - /** look for JNI libraries also in modules/bin/ */ - protected String findLibrary(String libname) { - String mapped = System.mapLibraryName(libname); - File lib = new File(new File(jar.getParentFile(), "bin"), mapped); // NOI18N - if (lib.isFile()) { - return lib.getAbsolutePath(); - } else { - return null; - } - } - public String toString() { - return super.toString() + "[" + getCodeNameBase() + "]"; // NOI18N - } - - protected void finalize() throws Throwable { - super.finalize(); - Util.err.log("Finalize for " + this + ": rc=" + rc + " releaseCount=" + releaseCount + " released=" + released); // NOI18N - if (rc == releaseCount) { - // Hurrah! release() worked. - released = true; - } else { - Util.err.log("Now resources for " + getCodeNameBase() + " have been released."); // NOI18N - } - } - } - -} Index: nb_all/xtest/src/org/netbeans/xtest/NbMultiTaskDef.java =================================================================== RCS file: /cvs/xtest/src/org/netbeans/xtest/NbMultiTaskDef.java,v retrieving revision 1.5 diff -u -r1.5 NbMultiTaskDef.java --- nb_all/xtest/src/org/netbeans/xtest/NbMultiTaskDef.java 22 May 2002 14:40:31 -0000 1.5 +++ nb_all/xtest/src/org/netbeans/xtest/NbMultiTaskDef.java 13 Aug 2002 23:39:11 -0000 @@ -24,7 +24,7 @@ import java.util.LinkedList; import java.util.Iterator; -import org.openide.TopManager; +//import org.openide.TopManager; /** * @@ -72,7 +72,9 @@ public void execute () throws BuildException { if (null != System.getProperty("test.ant.file")) { log("Using Netbeans classloader.", Project.MSG_DEBUG); - loader = TopManager.getDefault().currentClassLoader(); + //loader = org.openide.TopManager.getDefault().currentClassLoader(); + loader = Thread.currentThread().getContextClassLoader(); + System.out.println("NetBeans class loader: "+loader); } if (classpath != null) { Index: nb_all/xtest/src/org/netbeans/xtest/XTestErrorManager.java =================================================================== RCS file: nb_all/xtest/src/org/netbeans/xtest/XTestErrorManager.java diff -N nb_all/xtest/src/org/netbeans/xtest/XTestErrorManager.java --- nb_all/xtest/src/org/netbeans/xtest/XTestErrorManager.java 17 May 2002 12:19:11 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,157 +0,0 @@ -/* - * XTestErrorManager.java - * - * Created on April 24, 2002, 3:52 PM - */ - -package org.netbeans.xtest; - -import org.openide.ErrorManager; -import org.openide.ErrorManager.Annotation; -import org.openide.TopManager; -import org.netbeans.core.TopLogging; -import java.util.*; -import java.io.*; -import java.lang.ref.*; - -/** - * - * @author mb115822 - */ -public class XTestErrorManager extends ErrorManager { - - - - // here's XTest ErrorManager - private static ErrorManager errorManager = null; - - - // here are stored notifications - private static StringBuffer errorLog = new StringBuffer(); - - // getter for notifications - public static synchronized String getNotifications() { - if (errorLog.length() > 0) { - return errorLog.toString(); - } else { - return null; - } - } - - // clear stuff for notifications - public static synchronized void clearNotifications() { - errorLog = new StringBuffer(); - } - - - // get if there were any notifications and clear the status - public static synchronized boolean anyNotifications() { - if (getNotifications() == null) { - return false; - } else { - clearNotifications(); - return true; - } - } - - - - /** Creates new NbExceptionManager. */ - public XTestErrorManager() { - if (errorManager == null) { - errorManager = this; - } - } - - - - public org.openide.ErrorManager getInstance(String name) { - return getInstance(); - } - - public static org.openide.ErrorManager getInstance() { - if (errorManager == null) { - errorManager = new XTestErrorManager(); - } - return errorManager; - } - - /** Adds these values. All the - * previous annotations are kept and this new is added at - * the top of the annotation stack (index 0 of the annotation - * array). - * - * @param severity integer describing severity (one of const values - * from this class) - * @param date date or null - * @param message message to attach to the exception or null - * @param localizedMessage localized message for the user or null - * @param stackTrace exception representing the stack trace or null - */ - public synchronized Throwable annotate( - Throwable t, - int severity, String message, String localizedMessage, - Throwable stackTrace, java.util.Date date - ) { - return null; - } - - - /** Associates annotations with this thread. - * - * @param arr array of annotations (or null) - */ - public synchronized Throwable attachAnnotations(Throwable t, Annotation[] arr) { - return null; - } - - /** Notifies all the exceptions associated with - * this thread. - * @param clear should the current exception be cleared or not? - */ - public synchronized void notify(int severity, Throwable t) { - // synchronized to ensure that only one exception is - // written to the thread - - - if (severity > ErrorManager.USER ) { - // let's print the stuff to theByteArray .... - - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - - PrintWriter ps = new PrintWriter(bs); - - ps.println("*********** Exception occured ************"); // NOI18N - - // log into the byte array - t.printStackTrace(ps); - - ps.flush(); - - ps.close(); - - // add the notification to the string buffer - errorLog.append(bs.toString()+"\n"); - /* - ErrorManager.getDefault().log(ErrorManager.ERROR,"#\n#\n############# XTestEM notification: "+t+"\n#\n#\n"); - */ - } - } - - - /** Finds annotations associated with given exception. - * @param t the exception - * @return array of annotations or null - */ - public synchronized Annotation[] findAnnotations(Throwable t) { - return null; - } - - // log !!! - public void log(int severity, String s) { - } - - - - -} Index: nb_all/xtest/src/org/netbeans/xtest/ide/Main.java =================================================================== RCS file: nb_all/xtest/src/org/netbeans/xtest/ide/Main.java diff -N nb_all/xtest/src/org/netbeans/xtest/ide/Main.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/xtest/src/org/netbeans/xtest/ide/Main.java 13 Aug 2002 23:39:11 -0000 @@ -0,0 +1,673 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.xtest.ide; + +import java.util.*; +import java.awt.EventQueue; +import java.awt.Toolkit; +import java.awt.AWTEvent; +import java.awt.event.MouseEvent; +import java.awt.event.*; +import org.openide.*; +import org.openide.filesystems.*; +import org.openide.filesystems.FileSystem; // override java.io.FileSystem +import org.openide.loaders.*; +import org.openide.nodes.*; +import org.openide.execution.*; +import org.openide.util.*; +import org.openide.util.actions.*; + +import org.netbeans.core.output.OutputSettings; +import org.netbeans.core.execution.TopSecurityManager; + +// flag file stuff +import java.io.*; + +// native kill stuff +import org.netbeans.xtest.util.JNIKill; + +/** + * + * @author jchalupa + */ +public class Main extends Object { + + // terminate code :-) + public static final int TERMINATE_CODE = 666; + // terminate command :-) + public static final String TERMINATE_NAME = "kill"; + + private static ErrorManager errMan; + + // ide running flag file + private static File ideRunning = null; + + + + // flag whether IDE was interrupted + private static boolean ideInterrupted = false; + + + // finds terminate process action in the action array + private static SystemAction findTerminateAction(SystemAction[] actions) { + if (actions == null) { + throw new IllegalArgumentException(); + } + // I need to get the string from resource bundle + // bundle = org.netbeans.core.execution.Bundle.properties + // key = terminateProcess + String terminateString = NbBundle.getMessage(org.netbeans.core.execution.ProcessNode.class,"terminateProcess"); + for (int i=0; i 0) { + // better sleep for a sec, so they can be really killed + try { + Thread.sleep(5000); + } catch (InterruptedException ie) { + // nothing + } + } + return notTerminatedProcesses; + } + + + /** Installs XTestErrorManager to NetBeans + * + */ + private static boolean installXTestErrorManager() { + try { + System.out.println("Installing XTestErrorManager"); + FileSystem systemFS = TopManager.getDefault().getRepository().findFileSystem("SystemFileSystem"); + DataFolder emFolder = DataFolder.findFolder(systemFS.getRoot().getFileObject("Services").getFileObject("Hidden")); + InstanceDataObject xem = InstanceDataObject.create(emFolder,"xem","org.netbeans.xtest.ide.XTestErrorManager"); + // sleep for a sec, so ErrorManager gets installed + Thread.sleep(1000); + System.out.println("XTestErrorManager Installed"); + return true; + } catch (NullPointerException npe) { + // cannot install custom ErrorManager + return false; + } catch (IOException ioe) { + return false; + } catch (InterruptedException ie) { + return true; + } + } + + private static void prepareModuleLoaderClassPath() { + String moduleLoaderName = System.getProperty("xtest.useclassloader"); + if (moduleLoaderName != null) { + System.out.println("Using module "+moduleLoaderName+" classloader to load tests"); + String testbagClassPath = System.getProperty("tbag.classpath"); + if (testbagClassPath != null) { + // set appropriate property + String patchesProperty = "netbeans.patches."+moduleLoaderName; + System.out.println("Setting system property "+patchesProperty+" to "+testbagClassPath); + System.setProperty(patchesProperty, testbagClassPath); + } else { + System.out.println("TestBag classpath (tbag.classpath) property not defined - there is nothing to load"); + } + } + } + + + /** Starts the IDE. + * @param args the command line arguments + */ + public static void main(String args[]) { + // need to initialize org.openide.TopManager, not org.netbeans.core.Plain + System.getProperties().put ( + "org.openide.TopManager", // NOI18N + "org.netbeans.core.Main" // NOI18N + ); + + // create the IDE flag file + String workdir = System.getProperty("xtest.workdir"); + if (workdir!=null) { + // create flag file indicating running tests + ideRunning = new File(workdir,"ide.flag"); + File idePID = new File(workdir,"ide.pid"); + PrintWriter writer = null; + try { + ideRunning.createNewFile(); + idePID.createNewFile(); + writer = new PrintWriter(new FileOutputStream(idePID)); + // get my pid + JNIKill kill = new JNIKill(); + long myPID = kill.getMyPID(); + System.out.println("IDE is running under PID:"+myPID); + writer.println(myPID); + } catch (IOException ioe) { + System.out.println("cannot create flag file:"+ideRunning); + ideRunning = null; + } catch (Throwable e) { + System.out.println("There was a problem: "+e); + } finally { + if (writer != null) { + writer.close(); + } + } + } else { + System.out.println("cannot get xtest.workdir property - it has to be set to a valid working directory"); + } + + // prepare module's classpath + prepareModuleLoaderClassPath(); + + // do the expected stuff + try { + org.netbeans.core.Main.main(args); + } + catch (Exception e) { + e.printStackTrace(); + exit(); + } + + // install XTest error manager (only if xtest.error.manager=true) + // and openide version > 2 + + // get openide version - if sys property is not found - assume it is version 0 + float openideVersion = 0; + try { + openideVersion = Float.parseFloat(System.getProperty("org.openide.specification.version","0")); + } catch (NumberFormatException nfe) { + // property is not found - go on with 0 + } + + if (System.getProperty("xtest.error.manager","false").equals("true")) { + if (openideVersion > 2.0) { + boolean result = installXTestErrorManager(); + if (result==false) { + System.out.println("Cannot install XTestErrorManager"); + } else { + System.setProperty("xtest.error.manager","installed"); + } + } else { + System.out.println("OpenIDE version must be over 2.0 to use XTestErrorManager"); + System.out.println("Current version is "+openideVersion); + } + } + + + + + + // get the static ErrorManager instance + errMan = TopManager.getDefault().getErrorManager(); + + // some threads may be still active, wait for the event queue to become quiet + Thread initThread = new Thread(new Runnable() { + public void run() { + try { + new QueueEmpty().waitEventQueueEmpty(2000); + } + catch (Exception ex) { + TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex); + } + } + }); + // start the init thread + initThread.start(); + try { + initThread.join(60000L); // wait 1 minute at the most + } + catch (InterruptedException iex) { + errMan.notify(ErrorManager.EXCEPTION, iex); + + } + if (initThread.isAlive()) { + // time-out expired, event queue still busy -> interrupt the init thread + errMan.log(ErrorManager.USER, new Date().toString() + ": EventQueue still busy, starting anyway."); + initThread.interrupt(); + } + // ok. The IDE should be up and fully initialized + // let's run the test now + try { + doTestPart(); + } + catch (RuntimeException ex) { + ex.printStackTrace(); + } + } + + + private static final String TEST_CLASS = "test.class"; + private static final String TEST_CLASSPATH = "test.classpath"; + private static final String TEST_ARGS = "test.arguments"; + private static final String TEST_EXECUTOR = "test.executor"; + private static final String TEST_EXIT = "test.exit"; + private static final String TEST_FINISHED = "test.finished"; + private static final String TEST_TIMEOUT = "test.timeout"; + private static final String TEST_REDIRECT = "test.output.redirect"; + private static final String TEST_REUSE_IDE = "test.reuse.ide"; + + private static final long DEFAULT_TIMEOUT = 30; + + private static void doTestPart() { + + long testTimeout; + + // do nothing if no TEST_CLASS specified + if (System.getProperty(TEST_CLASS) == null) + return; + + // Yarda Tulach's line - is this good for anything ? + Object jarda = org.openide.filesystems.Repository.getDefault (); + + if (System.getProperty(TEST_REDIRECT) != null && System.getProperty(TEST_REDIRECT).equals("true")) { + ((OutputSettings) Lookup.getDefault().lookup( OutputSettings.class )).setRedirection(true); + } + + + try { + // default timeout is 30 minutes + testTimeout = Long.parseLong(System.getProperty(TEST_TIMEOUT, "30")); + } + catch (NumberFormatException ex) { + testTimeout = DEFAULT_TIMEOUT; + } + if (testTimeout <= 0) { + testTimeout = DEFAULT_TIMEOUT; + } + // convert to milis + testTimeout *= 60000L; + + StringTokenizer st = new StringTokenizer(System.getProperty(TEST_ARGS, "")); + final String[] params = new String[st.countTokens()]; + int i = 0; + while (st.hasMoreTokens()) { + params[i++] = st.nextToken(); + } + + final long startTime = System.currentTimeMillis(); + final long testTime = testTimeout; + Thread testThread = new Thread( new Runnable() { + public void run() { + try { + + // setup the repository + if (System.getProperty(TEST_CLASSPATH) != null && + System.getProperty(TEST_REUSE_IDE, "false").equals("false")) { + mountFileSystems(); + } + + setNodeProperties(); + + ExecInfo ei = new org.openide.execution.ExecInfo(System.getProperty(TEST_CLASS), params); + Executor exec = (Executor)Class.forName(System.getProperty(TEST_EXECUTOR, "org.openide.execution.ThreadExecutor")).newInstance(); + + if (exec != null) { + System.setProperty(TEST_FINISHED, "false"); + ExecutorTask task = exec.execute(ei); + + while (System.getProperty(TEST_FINISHED).equals("false")) { + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + long currentTime = System.currentTimeMillis(); + if (startTime + testTime + 10000 > currentTime) { + break; + } + else { + errMan.log(ErrorManager.USER, new Date().toString() + ": False InterruptedException. Continuing running tests"); + } + } + } + } + } + catch (Exception ex) { + TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex); + } + } + }); + + errMan.log(ErrorManager.USER, new Date().toString() + ": just starting."); + // start the test thread + testThread.start(); + try { + testThread.join(testTimeout); + } + catch (InterruptedException iex) { + errMan.notify(ErrorManager.EXCEPTION, iex); + } + if (testThread.isAlive()) { + // time-out expired, test not finished -> interrupt + errMan.log(ErrorManager.USER, new Date().toString() + ": time-out expired - interrupting! ***"); + ideInterrupted = true; + testThread.interrupt(); + } + + // we're leaving IDE + // delete the flag file (if ide was not interrupted) + if (ideRunning!=null) { + if (!ideInterrupted) { + if (ideRunning.delete()==false) { + System.out.println("Cannot delete the flag file "+ideRunning); + } + } + } + + // close IDE + if (System.getProperty(TEST_EXIT, "false").equals("true")) { + Thread exitThread = new Thread(new Runnable() { + public void run() { + // terminate all running processes + try { + terminateProcesses(); + } catch (Exception e) { + System.out.println("Exception when terminating processes started from IDE"); + e.printStackTrace(); + } + TopManager.getDefault().exit(); + } + }); + // try to exit nicely first + errMan.log(ErrorManager.USER, new Date().toString() + ": soft exit attempt."); + exitThread.start(); + try { + // wait 90 seconds for the IDE to exit + exitThread.join(90000); + } + catch (InterruptedException iex) { + errMan.notify(ErrorManager.EXCEPTION, iex); + } + if (exitThread.isAlive()) { + // IDE refuses to shutdown, terminate unconditionally + errMan.log(ErrorManager.USER, new Date().toString() + ": hard exit attempt!!!."); + exitThread.interrupt(); + exit(); + } + } + } + + private static void exit() { + try { + Class param[] = new Class[1]; + param[0] = int.class; + Class c = org.netbeans.core.execution.TopSecurityManager.class; + java.lang.reflect.Method m = c.getMethod("exit",param); + Integer intparam[] = {new Integer(1)}; + errMan.log(ErrorManager.USER, new Date().toString() + ": using TopSecurityManager.exit(1) to exit IDE."); + // exit + m.invoke(null,intparam); + } + catch (Exception e) { + errMan.log(ErrorManager.USER, new Date().toString() + ": using System.exit(1) to exit IDE."); + // exit + System.exit(1); + } + } + + + private static void mountFileSystems() { + Repository repo = TopManager.getDefault().getRepository(); + + // unmount the currently mounted filesystems + // (could be more sofisticated some day) + Enumeration all = repo.getFileSystems(); + while (all.hasMoreElements()) { + FileSystem fs = (FileSystem)all.nextElement(); + // preserve the hidden and default filesystems + if (!fs.isHidden() && !fs.isDefault()) + repo.removeFileSystem(fs); + } + // mount new filesystems as specified in TEST_CLASSPATH + StringTokenizer stok = new StringTokenizer(System.getProperty(TEST_CLASSPATH), System.getProperty("path.separator")); + while (stok.hasMoreElements()) { + String pathelem = stok.nextToken(); + try { + if (pathelem.endsWith(".jar") || pathelem.endsWith(".zip")) { + JarFileSystem jfs = new JarFileSystem(); + jfs.setJarFile(new java.io.File(pathelem)); + repo.addFileSystem(jfs); + } + else { + LocalFileSystem lfs = new LocalFileSystem(); + lfs.setRootDirectory(new java.io.File(pathelem)); + repo.addFileSystem(lfs); + } + } + catch (Exception ex) { + TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex); + } + } + } + + + private static void setNodeProperties() { + FileObject fo = TopManager.getDefault().getRepository().findResource(System.getProperty(TEST_CLASS) + ".java"); + if (fo != null) { + try { + DataObject obj = DataObject.find(fo); + Node nod = obj.getNodeDelegate(); + Node.PropertySet[] psets = nod.getPropertySets(); + Node.Property[] props = null; + + // get the Execution property set + for (int i = 0; i < psets.length; i++) { + if (psets[i].getName().equals("Execution")) { + props = psets[i].getProperties(); + break; + } + } + // get the "params" property and try to set it + if (props != null) { + for (int i = 0; i < props.length; i++) { + if (props[i].getName().equals("params")) { + if (System.getProperty(TEST_ARGS) != null) { + props[i].setValue(System.getProperty(TEST_ARGS)); + } + } + } + } + } + catch (java.lang.Exception ex) { + // ok, not able to set the Arguments property + // it's still worth trying to proceed with the test + // the FileObject may just be read-only + } + + } + + } + + + private static class QueueEmpty implements java.awt.event.AWTEventListener { + + private long eventDelayTime = 100; // 100 millis + private long lastEventTime; + + /** Creates a new QueueEmpty instance */ + public QueueEmpty() { + } + + /** method called every time when AWT Event is dispatched + * @param event event dispatched from AWT Event Queue + */ + public void eventDispatched(java.awt.AWTEvent awtEvent) { + lastEventTime = System.currentTimeMillis(); + } + + /** constructor with user defined value + * @param eventdelaytime maximum delay between two events of one redraw action + */ + public synchronized void waitEventQueueEmpty(long eventDelayTime) throws InterruptedException { + this.eventDelayTime = eventDelayTime; + waitEventQueueEmpty(); + } + + /** Waits until the AWTEventQueue is empty for a specified interval + */ + public synchronized void waitEventQueueEmpty() throws InterruptedException { + // store current time as the start time + long startTime = System.currentTimeMillis(); + // register itself as an AWTEventListener + Toolkit.getDefaultToolkit().addAWTEventListener(this, + AWTEvent.ACTION_EVENT_MASK | + AWTEvent.ADJUSTMENT_EVENT_MASK | + AWTEvent.COMPONENT_EVENT_MASK | + AWTEvent.CONTAINER_EVENT_MASK | + AWTEvent.FOCUS_EVENT_MASK | + AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK | + AWTEvent.HIERARCHY_EVENT_MASK | + AWTEvent.INPUT_METHOD_EVENT_MASK | + AWTEvent.INVOCATION_EVENT_MASK | + AWTEvent.ITEM_EVENT_MASK | + AWTEvent.KEY_EVENT_MASK | + AWTEvent.MOUSE_EVENT_MASK | + AWTEvent.MOUSE_MOTION_EVENT_MASK | + AWTEvent.PAINT_EVENT_MASK | + AWTEvent.TEXT_EVENT_MASK | + AWTEvent.WINDOW_EVENT_MASK); + + // set last event time to the current time + lastEventTime=System.currentTimeMillis(); + // get the thread to be put asleep + Thread t = Thread.currentThread(); + // get current AWT Event Queue + EventQueue queue=Toolkit.getDefaultToolkit().getSystemEventQueue(); + + try { + + // while AWT Event Queue is not empty and timedelay from last event is shorter then eventdelaytime + + //wait till the queue is empty + while ( queue.peekEvent() != null ) Thread.currentThread().sleep(100); + //test it - post my own task and wait for it + synchronized(this){ + Runnable r = new Runnable() { + public void run() { + synchronized(QueueEmpty.this){QueueEmpty.this.notifyAll();} + } + }; + queue.invokeLater(r); + wait(); + } + //now 2 sec continuously should be silence + while (System.currentTimeMillis() - lastEventTime < eventDelayTime) { + //sleep for the rest of eventDelay time + t.sleep(eventDelayTime + lastEventTime - System.currentTimeMillis()); + } + + //if (queue.peekEvent()==null) System.out.println("The AWT event queue seems to be empty."); + //else System.out.println("Ops, in the AWT event queue still seems to be some tasks!"); + + } + catch (InterruptedException ex) { + throw ex; + } + finally { + //removing from listeners + Toolkit.getDefaultToolkit().removeAWTEventListener(this); + } + } + + + } +} + Index: nb_all/xtest/src/org/netbeans/xtest/ide/XTestErrorManager.java =================================================================== RCS file: nb_all/xtest/src/org/netbeans/xtest/ide/XTestErrorManager.java diff -N nb_all/xtest/src/org/netbeans/xtest/ide/XTestErrorManager.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ nb_all/xtest/src/org/netbeans/xtest/ide/XTestErrorManager.java 13 Aug 2002 23:39:11 -0000 @@ -0,0 +1,157 @@ +/* + * XTestErrorManager.java + * + * Created on April 24, 2002, 3:52 PM + */ + +package org.netbeans.xtest.ide; + +import org.openide.ErrorManager; +import org.openide.ErrorManager.Annotation; +import org.openide.TopManager; +import org.netbeans.core.TopLogging; +import java.util.*; +import java.io.*; +import java.lang.ref.*; + +/** + * + * @author mb115822 + */ +public class XTestErrorManager extends ErrorManager { + + + + // here's XTest ErrorManager + private static ErrorManager errorManager = null; + + + // here are stored notifications + private static StringBuffer errorLog = new StringBuffer(); + + // getter for notifications + public static synchronized String getNotifications() { + if (errorLog.length() > 0) { + return errorLog.toString(); + } else { + return null; + } + } + + // clear stuff for notifications + public static synchronized void clearNotifications() { + errorLog = new StringBuffer(); + } + + + // get if there were any notifications and clear the status + public static synchronized boolean anyNotifications() { + if (getNotifications() == null) { + return false; + } else { + clearNotifications(); + return true; + } + } + + + + /** Creates new NbExceptionManager. */ + public XTestErrorManager() { + if (errorManager == null) { + errorManager = this; + } + } + + + + public org.openide.ErrorManager getInstance(String name) { + return getInstance(); + } + + public static org.openide.ErrorManager getInstance() { + if (errorManager == null) { + errorManager = new XTestErrorManager(); + } + return errorManager; + } + + /** Adds these values. All the + * previous annotations are kept and this new is added at + * the top of the annotation stack (index 0 of the annotation + * array). + * + * @param severity integer describing severity (one of const values + * from this class) + * @param date date or null + * @param message message to attach to the exception or null + * @param localizedMessage localized message for the user or null + * @param stackTrace exception representing the stack trace or null + */ + public synchronized Throwable annotate( + Throwable t, + int severity, String message, String localizedMessage, + Throwable stackTrace, java.util.Date date + ) { + return null; + } + + + /** Associates annotations with this thread. + * + * @param arr array of annotations (or null) + */ + public synchronized Throwable attachAnnotations(Throwable t, Annotation[] arr) { + return null; + } + + /** Notifies all the exceptions associated with + * this thread. + * @param clear should the current exception be cleared or not? + */ + public synchronized void notify(int severity, Throwable t) { + // synchronized to ensure that only one exception is + // written to the thread + + + if (severity > ErrorManager.USER ) { + // let's print the stuff to theByteArray .... + + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + + PrintWriter ps = new PrintWriter(bs); + + ps.println("*********** Exception occured ************"); // NOI18N + + // log into the byte array + t.printStackTrace(ps); + + ps.flush(); + + ps.close(); + + // add the notification to the string buffer + errorLog.append(bs.toString()+"\n"); + /* + ErrorManager.getDefault().log(ErrorManager.ERROR,"#\n#\n############# XTestEM notification: "+t+"\n#\n#\n"); + */ + } + } + + + /** Finds annotations associated with given exception. + * @param t the exception + * @return array of annotations or null + */ + public synchronized Annotation[] findAnnotations(Throwable t) { + return null; + } + + // log !!! + public void log(int severity, String s) { + } + + + + +} Index: nbextra/xtest/build.xml =================================================================== RCS file: /nbextra/xtest/build.xml,v retrieving revision 1.6 diff -u -r1.6 build.xml --- nbextra/xtest/build.xml 2002/02/20 11:07:53 1.6 +++ nbextra/xtest/build.xml 2002/08/13 23:37:16 @@ -17,11 +17,11 @@ debug="${build.compiler.debug}"> + - - + Index: nbextra/xtest/lib/xtest-ext.jar =================================================================== RCS file: /nbextra/xtest/lib/xtest-ext.jar,v retrieving revision 1.17 diff -u -r1.17 xtest-ext.jar Binary files /tmp/cvsBAABiaWjl and xtest-ext.jar differ Index: nbextra/xtest/src/org/netbeans/xtest/junit/.cvsignore =================================================================== RCS file: .cvsignore diff -N .cvsignore --- /dev/null Thu Oct 4 12:06:47 2001 +++ .cvsignore Tue Aug 13 16:37:16 2002 @@ -0,0 +1 @@ +*.class Index: nbextra/xtest/src/org/netbeans/xtest/pe/junit/.cvsignore =================================================================== RCS file: .cvsignore diff -N .cvsignore --- /dev/null Thu Oct 4 12:06:47 2001 +++ .cvsignore Tue Aug 13 16:37:16 2002 @@ -0,0 +1 @@ +*.class Index: nbextra/xtest/src/org/netbeans/xtest/pe/junit/JUnitResultsReporter.java =================================================================== RCS file: /nbextra/xtest/src/org/netbeans/xtest/pe/junit/JUnitResultsReporter.java,v retrieving revision 1.10 diff -u -r1.10 JUnitResultsReporter.java --- nbextra/xtest/src/org/netbeans/xtest/pe/junit/JUnitResultsReporter.java 2002/07/26 11:40:26 1.10 +++ nbextra/xtest/src/org/netbeans/xtest/pe/junit/JUnitResultsReporter.java 2002/08/13 23:37:16 @@ -19,7 +19,7 @@ package org.netbeans.xtest.pe.junit; -import org.netbeans.xtest.XTestErrorManager; +import org.netbeans.xtest.ide.XTestErrorManager; import org.netbeans.xtest.junit.*; import org.netbeans.xtest.pe.xmlbeans.*; import org.netbeans.xtest.pe.*; Index: nbextra/xtest/src/org/netbeans/xtest/util/.cvsignore =================================================================== RCS file: .cvsignore diff -N .cvsignore --- /dev/null Thu Oct 4 12:06:47 2001 +++ .cvsignore Tue Aug 13 16:37:16 2002 @@ -0,0 +1 @@ +*.class