Please use the Apache issue tracking system for new NetBeans issues (https://issues.apache.org/jira/projects/NETBEANS0/issues) !!
View | Details | Raw Unified | Return to bug 19443 | Differences between
and this patch

Collapse All | Expand All

(-)nb_all/core/build.xml (-2 / +19 lines)
 Lines 48-65    Link Here 
48
      </classpath>
48
      </classpath>
49
    </javac>
49
    </javac>
50
  </target>
50
  </target>
51
  
52
  <target name="boot">
53
    <javac srcdir="src" destdir="src" deprecation="${build.compiler.deprecation}" debug="${build.compiler.debug}" 
54
        includes="org/netbeans/*java"
55
    />    
56
    
57
    <mkdir dir="netbeans/lib/ext" />
58
    <jar jarfile="netbeans/lib/ext/boot.jar"
59
            basedir="src"
60
            excludesfile="../nbbuild/standard-jar-excludes.txt"
61
            includes="org/netbeans/*class" 
62
	    compress="false">
63
    </jar>
64
  </target>
51
65
52
  <target name="jars" depends="compile">
66
  <target name="jars" depends="compile,boot">
53
    <mkdir dir="netbeans/lib"/>
67
    <mkdir dir="netbeans/lib/ext" />
54
    <filter token="BUILD_NUMBER_SUBST" value="${buildnumber}"/>
68
    <filter token="BUILD_NUMBER_SUBST" value="${buildnumber}"/>
55
    <copy file="manifest.mf" tofile="manifest-subst.mf" filtering="on"/>
69
    <copy file="manifest.mf" tofile="manifest-subst.mf" filtering="on"/>
56
    <locjar jarfile="netbeans/lib/core.jar"
70
    <locjar jarfile="netbeans/lib/core.jar"
57
            basedir="src"
71
            basedir="src"
58
            manifest="manifest-subst.mf"
72
            manifest="manifest-subst.mf"
59
            excludesfile="../nbbuild/standard-jar-excludes.txt"
73
            excludesfile="../nbbuild/standard-jar-excludes.txt"
74
            excludes="org/netbeans/*class"
60
	    compress="false">
75
	    compress="false">
61
      <locale name="ja"/>
76
      <locale name="ja"/>
62
    </locjar>
77
    </locjar>
78
    
79
    
63
    <locjar jarfile="netbeans/lib/ext/terminalemulator.jar"
80
    <locjar jarfile="netbeans/lib/ext/terminalemulator.jar"
64
            basedir="libsrc"
81
            basedir="libsrc"
65
            excludesfile="../nbbuild/standard-jar-excludes.txt"
82
            excludesfile="../nbbuild/standard-jar-excludes.txt"
(-)nb_all/core/exelauncher/runide.cpp (-2 / +2 lines)
 Lines 515-522    Link Here 
515
    strcat(strcpy(buf, idehome), "\\lib\\locale");
515
    strcat(strcpy(buf, idehome), "\\lib\\locale");
516
    addAllFilesToClassPath(buf, "*.jar");
516
    addAllFilesToClassPath(buf, "*.jar");
517
517
518
    strcat(strcpy(buf, idehome), "\\lib");
518
//    strcat(strcpy(buf, idehome), "\\lib");
519
    addAllFilesToClassPath(buf, "*.jar");
519
//    addAllFilesToClassPath(buf, "*.jar");
520
    
520
    
521
    strcat(strcpy(buf, idehome), "\\lib\\ext\\locale");
521
    strcat(strcpy(buf, idehome), "\\lib\\ext\\locale");
522
    addAllFilesToClassPath(buf, "*.jar");
522
    addAllFilesToClassPath(buf, "*.jar");
(-)nb_all/core/release/bin/runide.sh (-4 / +4 lines)
 Lines 256-266    Link Here 
256
build_cp() {
256
build_cp() {
257
    base="$1"
257
    base="$1"
258
258
259
    append_jars_to_cp "${base}/lib/patches/locale"
259
#    append_jars_to_cp "${base}/lib/patches/locale"
260
    append_jars_to_cp "${base}/lib/patches"
260
#    append_jars_to_cp "${base}/lib/patches"
261
261
262
    append_jars_to_cp "${base}/lib/locale"
262
#    append_jars_to_cp "${base}/lib/locale"
263
    append_jars_to_cp "${base}/lib"
263
#    append_jars_to_cp "${base}/lib"
264
264
265
    append_jars_to_cp "${base}/lib/ext/locale"
265
    append_jars_to_cp "${base}/lib/ext/locale"
266
    append_jars_to_cp "${base}/lib/ext"
266
    append_jars_to_cp "${base}/lib/ext"
(-)nb_all/core/src/org/netbeans/JarClassLoader.java (+427 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans;
15
16
import java.net.URL;
17
import java.util.jar.JarFile;
18
import java.util.jar.Manifest;
19
import java.util.jar.Attributes;
20
import java.util.jar.Attributes.Name;
21
import java.util.zip.ZipEntry;
22
import java.io.*;
23
import java.net.MalformedURLException;
24
import java.security.*;
25
import java.security.cert.Certificate;
26
import java.util.*;
27
import java.lang.reflect.Field;
28
import java.lang.reflect.Modifier;
29
30
/**
31
 * A ProxyClassLoader capable of loading classes from a set of jar files
32
 * and local directories.
33
 *
34
 * @author  Petr Nejedly
35
 */
36
public class JarClassLoader extends ProxyClassLoader {
37
    private Source[] sources;
38
    /** temp copy JARs which ought to be deleted */
39
    private Set deadJars = null; // Set<JarFile>
40
    
41
    /** Creates new JarClassLoader */
42
    public JarClassLoader (List files, ClassLoader[] parents) {
43
        super(parents);
44
45
        sources = new Source[files.size()];
46
        try {
47
            int i=0;
48
            for (Iterator it = files.iterator(); it.hasNext(); i++ ) {
49
                Object act = it.next();
50
                if (act instanceof File) {
51
                    sources[i] = new DirSource((File)act);
52
                } else {
53
                    sources[i] = new JarSource((JarFile)act);
54
                }
55
            }
56
        } catch (MalformedURLException exc) {
57
            throw new IllegalArgumentException(exc.getMessage());
58
        }
59
            
60
    }
61
62
    /** Allows to specify the right permissions, OneModuleClassLoader does it differently.
63
     */
64
    protected PermissionCollection getPermissions( CodeSource cs ) {           
65
        return Policy.getPolicy().getPermissions(cs);       
66
    }        
67
    
68
    
69
    protected Package definePackage(String name, Manifest man, URL url)
70
	throws IllegalArgumentException
71
    {
72
        if (man == null ) {
73
            return definePackage(name, null, null, null, null, null, null, null);
74
        }
75
        
76
	String path = name.replace('.', '/').concat("/"); // NOI18N
77
	Attributes spec = man.getAttributes(path);
78
        Attributes main = man.getMainAttributes();
79
	
80
        String specTitle = getAttr(spec, main, Name.SPECIFICATION_TITLE);
81
        String implTitle = getAttr(spec, main, Name.IMPLEMENTATION_TITLE);
82
        String specVersion = getAttr(spec, main, Name.SPECIFICATION_VERSION);
83
        String implVersion = getAttr(spec, main, Name.IMPLEMENTATION_VERSION);
84
        String specVendor = getAttr(spec, main, Name.SPECIFICATION_VENDOR);
85
        String implVendor = getAttr(spec, main, Name.IMPLEMENTATION_VENDOR);
86
        String sealed      = getAttr(spec, main, Name.SEALED);
87
88
        URL sealBase = "true".equalsIgnoreCase(sealed) ? url : null; // NOI18N
89
	return definePackage(name, specTitle, specVersion, specVendor,
90
			     implTitle, implVersion, implVendor, sealBase);
91
    }
92
93
    private static String getAttr(Attributes spec, Attributes main, Name name) {
94
        String val = null;
95
        if (spec != null) val = spec.getValue (name);
96
        if (val == null && main != null) val = main.getValue (name);
97
        return val;
98
    }
99
100
    protected Class simpleFindClass(String name, String path) {
101
        // look up the Sources and return a class based on their content
102
        for( int i=0; i<sources.length; i++ ) {
103
            Source src = sources[i];
104
            byte[] data = src.getClassData(name, path);
105
            if (data == null) continue;
106
            
107
            // do the enhancing
108
            byte[] d = PatchByteCode.patch (data);
109
            data = d;
110
            
111
            int j = name.lastIndexOf('.');
112
            String pkgName = name.substring(0, j);
113
            Package pkg = getPackage(pkgName);
114
            
115
            if (pkg != null) {
116
                // XXX full sealing check, URLClassLoader does something more
117
                if (pkg.isSealed() && !pkg.isSealed(src.getURL())) throw new SecurityException("sealing violation"); // NOI18N
118
            } else {
119
                Manifest man = src.getManifest();
120
                definePackage (pkgName, man, src.getURL());
121
            }
122
123
            return defineClass (name, data, 0, data.length, src.getProtectionDomain());
124
        } 
125
        return null;
126
    }
127
    // look up the jars and return a resource based on a content of jars
128
    protected URL findResource(String name) {
129
        for( int i=0; i<sources.length; i++ ) {
130
            URL item = sources[i].getResource(name);
131
            if (item != null) return item;
132
        }
133
	return null;
134
    }
135
136
    protected Enumeration simpleFindResources(String name) {
137
        Vector v = new Vector(3);
138
        // look up the jars and return a resource based on a content of jars
139
140
        for( int i=0; i<sources.length; i++ ) {
141
            URL item = sources[i].getResource(name);
142
            if (item != null) v.add(item);
143
        }
144
        return v.elements();
145
    }
146
147
    /** Try to release any JAR locks held by this classloader.
148
     * @see #21114
149
     */
150
    public final void releaseLocks() {
151
        if (deadJars != null) throw new IllegalStateException();
152
        deadJars = new HashSet(); // Set<JarFile>
153
        try {
154
            for (int i = 0; i < sources.length; i++) {
155
                if (sources[i] instanceof JarSource) {
156
                    JarFile origJar = ((JarSource)sources[i]).getJarFile();
157
                    File orig = new File(origJar.getName());
158
                    if (!orig.isFile()) {
159
                        // Can happen when a test module is deleted:
160
                        // the physical JAR has already been deleted
161
                        // when the module was disabled. In this case it
162
                        // is possible that a classloader request for something
163
                        // in the JAR could still come in. Does it matter?
164
                        // See comment in Module.cleanup.
165
                        continue;
166
                    }
167
                    String name = orig.getName();
168
                    String prefix, suffix;
169
                    int idx = name.lastIndexOf('.');
170
                    if (idx == -1) {
171
                        prefix = name;
172
                        suffix = null;
173
                    } else {
174
                        prefix = name.substring(0, idx);
175
                        suffix = name.substring(idx);
176
                    }
177
                    while (prefix.length() < 3) prefix += "x"; // NOI18N
178
                    File temp = File.createTempFile(prefix, suffix);
179
                    temp.deleteOnExit();
180
                    InputStream is = new FileInputStream(orig);
181
                    try {
182
                        OutputStream os = new FileOutputStream(temp);
183
                        try {
184
                            byte[] buf = new byte[4096];
185
                            int j;
186
                            while ((j = is.read(buf)) != -1) {
187
                                os.write(buf, 0, j);
188
                            }
189
                        } finally {
190
                            os.close();
191
                        }
192
                    } finally {
193
                        is.close();
194
                    }
195
                    // Don't use OPEN_DELETE even though it sounds like a good idea.
196
                    // Can cause real problems under 1.4; see Module.java.
197
                    JarFile tempJar = new JarFile(temp);
198
                    origJar.close();
199
                    forceRelease(orig);
200
                    deadJars.add(tempJar);
201
                    sources[i] = new JarSource(tempJar);
202
                    log("#21114: replacing " + orig + " with " + temp);
203
                }
204
            }
205
        } catch (IOException ioe) {
206
            JarClassLoader.notify(0, ioe);
207
        }
208
    }
209
    
210
    /** Release jar: locks when the classloader is shut down.
211
     * Should help reloading modules with changed resources.
212
     */
213
    public void destroy() {
214
        super.destroy();
215
        for (int i = 0; i < sources.length; i++) {
216
            if (sources[i] instanceof JarSource) {
217
                JarFile j = ((JarSource)sources[i]).getJarFile();
218
                File f = new File(j.getName());
219
                forceRelease(f);
220
            }
221
        }
222
    }
223
    
224
    /** Delete any temporary JARs we were holding on to.
225
     * Also close any other JARs in our list.
226
     */
227
    protected void finalize() throws Throwable {
228
        super.finalize();
229
        for (int i = 0; i < sources.length; i++) {
230
            if (sources[i] instanceof JarSource) {
231
                JarFile j = ((JarSource)sources[i]).getJarFile();
232
                File f = new File(j.getName());
233
                j.close();
234
                forceRelease(f);
235
                if (deadJars != null && deadJars.contains(j)) {
236
                    log("#21114: closing and deleting temporary JAR " + f);
237
                    if (f.isFile() && !f.delete()) {
238
                        log("(but failed to delete it)");
239
                    }
240
                }
241
            }
242
        }
243
    }
244
    
245
    /** Make sure the Java runtime's jar: URL cache is not holding
246
     * onto the specified file.
247
     * Workaround for JDK bug #4646668.
248
     */
249
    private static void forceRelease(File f) {
250
        if (fileCache == null || factory == null) return;
251
        try {
252
            synchronized (factory) {
253
                Iterator it = fileCache.values().iterator();
254
                while (it.hasNext()) {
255
                    JarFile j = (JarFile)it.next();
256
                    if (f.equals(new File(j.getName()))) {
257
                        j.close();
258
                        it.remove();
259
                        log("Removing jar: cache for " + f + " as workaround for JDK #4646668");
260
                    }
261
                }
262
            }
263
        } catch (Exception e) {
264
            JarClassLoader.annotate(e, 0, "Could not remove jar: cache for " + f, null, null, null);
265
            JarClassLoader.notify(0, e);
266
        }
267
    }
268
    private static Object factory = null;
269
    private static HashMap fileCache = null;
270
    static {
271
        try {
272
            Class juc = Class.forName("sun.net.www.protocol.jar.JarURLConnection"); // NOI18N
273
            Field factoryF = juc.getDeclaredField("factory"); // NOI18N
274
            factoryF.setAccessible(true);
275
            factory = factoryF.get(null);
276
            Class jff = Class.forName("sun.net.www.protocol.jar.JarFileFactory"); // NOI18N
277
            if (!jff.isInstance(factory)) throw new ClassCastException(factory.getClass().getName());
278
            Field fileCacheF = jff.getDeclaredField("fileCache"); // NOI18N
279
            fileCacheF.setAccessible(true);
280
            if (Modifier.isStatic(fileCacheF.getModifiers())) {
281
                // JDK 1.3.1 or 1.4 seems to have it static.
282
                fileCache = (HashMap)fileCacheF.get(null);
283
            } else {
284
                // But in 1.3.0 it appears to be an instance var.
285
                fileCache = (HashMap)fileCacheF.get(factory);
286
            }
287
            log("Workaround for JDK #4646668 active as part of IZ #21114");
288
        } catch (Exception e) {
289
            JarClassLoader.annotate(e, 0, "Workaround for JDK #4646668 as part of IZ #21114 failed", null, null, null);
290
            JarClassLoader.notify(0, e);
291
        }
292
    }
293
294
    abstract class Source {
295
        private URL url;
296
        private ProtectionDomain pd;
297
        
298
        public Source(URL url) {
299
            this.url = url;
300
            CodeSource cs = new CodeSource(url, new Certificate[0]);
301
            pd = new ProtectionDomain(cs, getPermissions(cs));
302
        }
303
        
304
        public final URL getURL() {
305
            return url;
306
        }
307
        
308
        public final ProtectionDomain getProtectionDomain() {
309
            return pd;
310
        }
311
  
312
        public final URL getResource(String name) {
313
            try {
314
                return doGetResource(name);
315
            } catch (MalformedURLException e) {
316
                log(e.toString());
317
            }
318
            return null;
319
        }
320
        
321
        protected abstract URL doGetResource(String name) throws MalformedURLException;
322
        
323
        public final byte[] getClassData(String name, String path) {
324
            try {
325
                return readClass(name, path);
326
            } catch (IOException e) {
327
                log(e.toString());
328
            }
329
            return null;
330
        }
331
332
        protected abstract byte[] readClass(String name, String path) throws IOException;
333
334
        public Manifest getManifest() {
335
            return null;
336
        }
337
    }
338
339
    class JarSource extends Source {
340
        JarFile src;
341
        
342
        public JarSource(JarFile file) throws MalformedURLException {
343
            super(new URL("file:" + file.getName()));
344
            src = file;
345
        }
346
347
        public Manifest getManifest() {
348
            try {
349
                return src.getManifest();
350
            } catch (IOException e) {
351
                return null;
352
            }
353
        }
354
        
355
        JarFile getJarFile() {
356
            return src;
357
        }
358
        
359
        protected URL doGetResource(String name) throws MalformedURLException {
360
            ZipEntry ze = src.getEntry(name);
361
            return ze == null ? null : new URL("jar:file:" + src.getName() + "!/" + ze.getName()); // NOI18N
362
        }
363
        
364
        protected byte[] readClass(String name, String path) throws IOException {
365
            ZipEntry ze = src.getEntry(path);
366
            if (ze == null) return null;
367
            
368
            int len = (int)ze.getSize();
369
            byte[] data = new byte[len];
370
            InputStream is = src.getInputStream(ze);
371
            int count = 0;
372
            while (count < len) {
373
                count += is.read(data, count, len-count);
374
            }
375
            return data;
376
        }
377
    }
378
379
    class DirSource extends Source {
380
        File dir;
381
        
382
        public DirSource(File file) throws MalformedURLException {
383
            super(file.toURL());
384
            dir = file;
385
        }
386
387
        protected URL doGetResource(String name) throws MalformedURLException {
388
            File resFile = new File(dir, name);
389
            return resFile.exists() ? resFile.toURL() : null;
390
        }
391
        
392
        protected byte[] readClass(String name, String path) throws IOException {
393
            File clsFile = new File(dir, path.replace('/', File.separatorChar));
394
            if (!clsFile.exists()) return null;
395
            
396
            int len = (int)clsFile.length();
397
            byte[] data = new byte[len];
398
            InputStream is = new FileInputStream(clsFile);
399
            int count = 0;
400
            while (count < len) {
401
                count += is.read(data, count, len-count);
402
            }
403
            return data;
404
        }
405
        
406
    }
407
    
408
    
409
    //
410
    // ErrorManager's methods
411
    //
412
    
413
    static void log (String msg) {
414
        System.err.println(msg);
415
    }
416
    
417
    static Throwable annotate (
418
        Throwable t, int x, String s, Object o1, Object o2, Object o3
419
    ) {
420
        System.err.println("annotated: " + t.getMessage () + " - " + s);
421
        return t;
422
    }
423
    
424
    static void notify (int x, Throwable t) {
425
        t.printStackTrace();
426
    }
427
}
(-)nb_all/core/src/org/netbeans/Main.java (-3 / +80 lines)
 Lines 13-18    Link Here 
13
13
14
package org.netbeans;
14
package org.netbeans;
15
15
16
import java.io.File;
17
import java.net.URL;
18
import java.net.URLClassLoader;
19
import java.util.ArrayList;
20
import java.util.StringTokenizer;
21
import java.lang.reflect.Method;
22
import java.util.Collection;
16
import org.netbeans.core.perftool.StartLog;
23
import org.netbeans.core.perftool.StartLog;
17
24
18
/** The Corona's main class. Starts up the IDE.
25
/** The Corona's main class. Starts up the IDE.
 Lines 23-30    Link Here 
23
    /** Starts the IDE.
30
    /** Starts the IDE.
24
    * @param args the command line arguments
31
    * @param args the command line arguments
25
    */
32
    */
26
    public static void main (String args[]) {
33
    public static void main (String args[]) throws Exception {
27
	StartLog.logStart( "Forwarding to topThreadGroup" ); // NOI18N
34
        ArrayList list = new ArrayList ();
28
        org.netbeans.core.Main.start(args);
35
36
        String user = System.getProperty("netbeans.user"); // NOI18N
37
        if (user != null) {
38
            build_cp (new File (user), list);
39
        }
40
        
41
        String home = System.getProperty ("netbeans.home"); // NOI18N
42
        if (home != null) {
43
            build_cp (new File (home), list);
44
        }
45
        
46
        java.util.ListIterator it = list.listIterator();
47
        while (it.hasNext()) {
48
            File f = (File)it.next();
49
            it.set(new java.util.jar.JarFile (f));
50
        }
51
        
52
            
53
        ClassLoader loader = new JarClassLoader (list, new ClassLoader[] {
54
            Main.class.getClassLoader()
55
        });
56
        
57
        String className = System.getProperty(
58
            "netbeans.mainclass", "org.netbeans.core.Main" // NOI18N
59
        );
60
        
61
	Class c = loader.loadClass(className);
62
        Method m = c.getMethod ("main", new Class[] { String[].class }); // NOI18N
63
        
64
        Thread.currentThread().setContextClassLoader (loader);
65
        m.invoke (null, new Object[] { args });
66
    }
67
    
68
    
69
    private static void append_jars_to_cp (File dir, Collection toAdd) {
70
        /*
71
        for ex in jar zip ; do
72
            if [ "`echo "${dir}"/*.$ex`" != "${dir}/*.$ex" ] ; then
73
                for x in "${dir}"/*.$ex ; do
74
                    # XXX also filter out lib/locale/updater*.jar to make Japanese startup faster
75
                    # (and put it back in below when building ${updatercp}
76
                    if [ "$x" != "$idehome/lib/updater.jar" -a "$x" != "$userdir/lib/updater.jar" ] ; then
77
                        if [ ! -z "$cp" ] ; then cp="$cp:" ; fi
78
                        cp="$cp$x"
79
                    fi
80
                done
81
            fi
82
        done
83
         */
84
        
85
        if (!dir.isDirectory()) return;
86
        
87
        File[] arr = dir.listFiles();
88
        for (int i = 0; i < arr.length; i++) {
89
            String n = arr[i].getName ();
90
            if (n.endsWith("jar") || n.endsWith ("zip")) { // NOI18N
91
                toAdd.add (arr[i]);
92
            }
93
        }
94
    }
95
        
96
    
97
    private static void build_cp(File base, Collection toAdd) {
98
        append_jars_to_cp (new File (base, "lib/patches/locale"), toAdd);
99
        append_jars_to_cp (new File (base, "lib/patches"), toAdd);
100
101
        append_jars_to_cp (new File (base, "lib/locale"), toAdd);
102
        append_jars_to_cp (new File (base, "lib"), toAdd);
103
104
        //append_jars_to_cp (new File (base, "lib/ext/locale"), toAdd);
105
        //append_jars_to_cp (new File (base, "lib/ext"), toAdd);
29
    }
106
    }
30
}
107
}
(-)nb_all/core/src/org/netbeans/PatchByteCode.java (+426 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans;
15
16
import java.io.*;
17
18
/** Class that can enhance bytecode with information about alternative
19
 * superclass and also extract this information later when the class
20
 * is about to be loaded into the VM.
21
 *
22
 * @author  Jaroslav Tulach
23
 */
24
public final class PatchByteCode {
25
    private static final String ATTR_SUPERCLASS = "org.netbeans.superclass"; // NOI18N
26
    private static final byte[] BYTE_SUPERCLASS;
27
    static {
28
        try {
29
            BYTE_SUPERCLASS = ATTR_SUPERCLASS.getBytes("utf-8"); // NOI18N
30
        } catch (java.io.UnsupportedEncodingException ex) {
31
            throw new IllegalStateException (ex.getMessage());
32
        }
33
    }
34
    
35
    
36
    private byte[] arr;
37
    
38
    private int cpCount;
39
    private int cpEnd;
40
    private int atCount;
41
    private int atEnd;
42
    
43
    /** the index of a string that matches the searched attribute */
44
    private int superClassNameIndex;
45
    /** the possiton of found attribute */
46
    private int superClassNameAttr;
47
    
48
    /** Creates a new instance of PatchByteCode */
49
    private PatchByteCode(byte[] arr) {
50
        this.arr = arr;
51
        scan ();
52
    }
53
    
54
55
    /** Generates patch attribute into the classfile to
56
     * allow method <code>patch</code> to modify the superclass of this 
57
     * class.
58
     *
59
     * @param arr the bytecode to change
60
     * @param superClass name of the new superclass like java/awt/Button
61
     * @return new version of the bytecode if changed, otherwise null to signal that
62
     * no change has been made
63
     */
64
    public static byte[] enhance (byte[] arr, String superClass) {
65
        if (isPatched (arr)) {
66
            // already patched
67
            return null;
68
        }
69
        
70
        PatchByteCode pc = new PatchByteCode (arr); 
71
        
72
        if (superClass != null) {
73
            int x = pc.addClass (superClass);
74
75
76
            byte[] sup = new byte[2];
77
            writeU2 (sup, 0, x);
78
            pc.addAttribute (ATTR_SUPERCLASS, sup);
79
            
80
            byte[] patch = { 
81
                'n', 'b' // identification at the end of class file
82
            };
83
84
            pc.addAttribute ("org.netbeans.enhanced", patch);
85
        }
86
        
87
        // if we patch the class then it is supposed to be public
88
        if (!pc.makePublic () && superClass == null) {
89
            // if it already was public and no superclass change
90
            return null;
91
        }
92
        
93
        
94
        // otherwise do the patching
95
        return pc.getClassFile ();
96
    }
97
    
98
    /** Checks if the class has previously been enhanced by the 
99
     * change of superclass attribute and if so, changes the bytecode
100
     * to reflect the change.
101
     * 
102
     * @param arr the bytecode
103
     * @return the enhanced bytecode
104
     */
105
    public static byte[] patch (byte[] arr) {
106
        if (!isPatched (arr)) return arr;
107
108
        PatchByteCode pc = new PatchByteCode (arr);
109
        if (pc.superClassNameAttr > 0) {
110
            // let's patch
111
            int classindex = pc.readU2 (pc.superClassNameAttr + 6);
112
            
113
            writeU2 (pc.getClassFile(), pc.cpEnd + 4, classindex);
114
        }
115
        
116
        return pc.getClassFile ();
117
    }
118
    
119
    
120
    /** Check if the byte code is patched.
121
     * @param arr the bytecode
122
     * @return true if patched
123
     */
124
    private static boolean isPatched (byte[] arr) {
125
        if (arr == null || arr.length < 2) return false;
126
        
127
        int base = arr.length - 2;
128
        if (arr[base + 1] != 'b') return false;
129
        if (arr[base + 0] != 'n') return false;
130
        
131
        //
132
        // ok, looks like enhanced byte code
133
        //
134
        return true;
135
    }
136
    
137
    
138
    
139
    
140
    
141
    
142
    
143
    /** Gets the current byte array of the actual class file.
144
     * @return bytes of the class file
145
     */
146
    private byte[] getClassFile () {
147
        return arr;
148
    }
149
    
150
    /** Creates new contant pool entry representing given class.
151
     * @param c name of the class
152
     * @return index of the entry
153
     */
154
    private int addClass (String s) {
155
        int x = addConstant (s);
156
        
157
        byte[] t = { 7, 0, 0 };
158
        writeU2 (t, 1, x);
159
        
160
        return addPool (t);
161
    }
162
    
163
    /** Adds a new string constant to the constant pool.
164
     * @param s the string to add
165
     * @return index of the constant
166
     */
167
    private int addConstant (String s) {
168
        byte[] t;
169
        
170
        try {
171
            t = s.getBytes("utf-8"); // NOI18N
172
        } catch (java.io.UnsupportedEncodingException ex) {
173
            throw new IllegalStateException ("UTF-8 shall be always supported"); // NOI18N
174
        }
175
        
176
        byte[] add = new byte[t.length + 3];
177
        System.arraycopy (t, 0, add, 3, t.length);
178
        add[0] = 1; // UTF8 contant
179
        writeU2 (add, 1, t.length);
180
        
181
        return addPool (add);
182
    }
183
        
184
    /** Adds this array of bytes as another entry into the constant pool */
185
    private int addPool (byte[] add) {
186
        byte[] res = new byte[arr.length + add.length];
187
     
188
        System.arraycopy (arr, 0, res, 0, cpEnd);
189
        // increments number of objects in contant pool
190
        int index = readU2 (cpCount);
191
        writeU2 (res, cpCount, index + 1);
192
        
193
        // adds the content
194
        System.arraycopy (add, 0, res, cpEnd, add.length);
195
        
196
        // and now add the rest of the original array
197
        System.arraycopy (arr, cpEnd, res, cpEnd + add.length, arr.length - cpEnd);
198
        
199
        arr = res;
200
        
201
        cpEnd += add.length;
202
        atCount += add.length;
203
        atEnd += add.length;
204
        
205
        // the index
206
        return index;
207
    }
208
    
209
    /** Ensures that the class is public 
210
     * @return true if really patched, false if not
211
     */
212
    private boolean makePublic () {
213
        int x = readU2 (cpEnd);
214
        
215
        if ((x & 0x0001) != 0) {
216
            return false;
217
        }
218
        
219
        x |= 0x0001; // adds public field
220
        writeU2 (arr, cpEnd, x);
221
        
222
        return true;
223
    }
224
    
225
    /** Adds an attribute to the class file.
226
     * @param name name of the attribute to add
227
     * @param b the bytes representing the attribute
228
     */
229
    private void addAttribute (String name, byte[] b) {
230
        int index;
231
        if (ATTR_SUPERCLASS.equals (name) && superClassNameIndex > 0) {
232
            index = superClassNameIndex;
233
        } else {
234
            // register new attribute
235
            index = addConstant (name);
236
        }
237
        
238
        byte[] res = new byte[arr.length + b.length + 6];
239
        
240
        System.arraycopy(arr, 0, res, 0, arr.length);
241
        
242
        writeU2 (res, arr.length, index);
243
        writeU4 (res, arr.length + 2, b.length);
244
        
245
        int begin = arr.length + 6;
246
        System.arraycopy(b, 0, res, begin, b.length);
247
        
248
        atEnd += b.length + 6;
249
        
250
        writeU2 (res, atCount, readU2 (atCount) + 1);
251
        
252
        arr = res;
253
    }
254
    
255
    
256
    /** Gets i-th element from the array.
257
     */
258
    private int get (int pos) {
259
        if (pos >= arr.length) {
260
            throw new ArrayIndexOutOfBoundsException ("Size: " + arr.length + " index: " + pos);
261
        }
262
        
263
        int x = arr[pos];
264
        return x >= 0 ? x : 256 + x;
265
    }
266
267
    /** Scans the file to find out important possitions
268
     * @return size of the bytecode
269
     */
270
    private void scan () {
271
        if (get (0) != 0xCA && get (1) != 0xFE && get (2) != 0xBA && get (3) != 0xBE) {
272
            throw new IllegalStateException ("Not a class file!"); // NOI18N
273
        }
274
        
275
        int pos = 10;
276
        // count of items in CP is here
277
        cpCount = 8;
278
        
279
        int cp = readU2 (8);
280
        for (int[] i = { 1 }; i[0] < cp; i[0]++) {
281
            // i[0] can be incremented in constantPoolSize
282
            int len = constantPoolSize (pos, i);
283
            pos += len;
284
        }
285
        
286
        // list item in constant pool
287
        cpEnd = pos;
288
        
289
        pos += 6;
290
        // now add interfaces
291
        pos += 2 * readU2 (pos);
292
        // to add also the integer with interfaces
293
        pos += 2;
294
        
295
        // fields
296
        int fields = readU2 (pos);
297
        pos += 2;
298
        while (fields-- > 0) {
299
            pos += fieldSize (pos);
300
        }
301
        
302
        int methods = readU2 (pos);
303
        pos += 2;
304
        while (methods-- > 0) {
305
            pos += methodSize (pos);
306
        }
307
308
        // count of items in Attributes is here
309
        atCount = pos;
310
        int attrs = readU2 (pos);
311
        pos += 2;
312
        while (attrs-- > 0) {
313
            pos += attributeSize (pos);
314
        }
315
316
        // end of attributes
317
        atEnd = pos;
318
    }
319
    
320
    private int readU2 (int pos) {
321
        int b1 = get (pos);
322
        int b2 = get (pos + 1);
323
        
324
        return b1 * 256 + b2;
325
    }
326
    
327
    private int readU4 (int pos) {
328
        return readU2 (pos) * 256 * 256 + readU2 (pos + 2);
329
    }
330
331
    private static void writeU2 (byte[] arr, int pos, int value) {
332
        int v1 = (value & 0xff00) >> 8;
333
        int v2 = value & 0xff;
334
        
335
        if (v1 < 0) v1 += 256;
336
        if (v2 < 0) v2 += 256;
337
        
338
        arr[pos] = (byte)v1;
339
        arr[pos + 1] = (byte)v2;
340
    }
341
    
342
    private static void writeU4 (byte[] arr, int pos, int value) {
343
        writeU2 (arr, pos, (value & 0xff00) >> 16);
344
        writeU2 (arr, pos + 2, value & 0x00ff);
345
    }
346
    
347
    /** @param pos position to read from
348
     * @param cnt[0] index in the pool that we are now reading
349
     */
350
    private int constantPoolSize (int pos, int[] cnt) {
351
        switch (get (pos)) {
352
            case 7: // CONSTANT_Class 
353
            case 8: // CONSTANT_String 
354
                return 3;
355
            case 9: // CONSTANT_Fieldref 
356
            case 10: // CONSTANT_Methodref 
357
            case 11: // CONSTANT_InterfaceMethodref 
358
            case 3: // CONSTANT_Integer
359
            case 4: // CONSTANT_Float
360
            case 12: // CONSTANT_NameAndType
361
                return 5;
362
            case 5: // CONSTANT_Long
363
            case 6: // CONSTANT_Double
364
                // after long and double the next entry in CP is unusable
365
                cnt[0]++;
366
                return 9;
367
            case 1: // CONSTANT_Utf8
368
                int len = readU2 (pos + 1);
369
                
370
                if (BYTE_SUPERCLASS.length == len) {
371
                    int base = pos + 3;
372
                    // we are searching for an attribute with given name
373
                    for (int i = 0; i < BYTE_SUPERCLASS.length; i++) {
374
                        if (BYTE_SUPERCLASS[i] != arr[base + i]) {
375
                            // regular exit
376
                            return len + 3;
377
                        }
378
                    }
379
                    
380
                    // we have found the attribute
381
                    if (superClassNameIndex != 0) {
382
                        throw new IllegalStateException (ATTR_SUPERCLASS + " registered for the second time!"); // NOI18N
383
                    }
384
                    
385
                    superClassNameIndex = cnt[0];
386
                }
387
388
                // ok, exit
389
                return len + 3;
390
            default:
391
                throw new IllegalStateException ("Unknown pool type: " + get (pos)); // NOI18N
392
        }
393
    }
394
    
395
    private int fieldSize (int pos) {
396
        int s = 8;
397
        int cnt = readU2 (pos + 6);
398
        while (cnt-- > 0) {
399
            s += attributeSize (pos + s);
400
        }
401
        return s;
402
    }
403
    
404
    private int methodSize (int pos) {
405
        return fieldSize (pos);
406
    }
407
    
408
    private int attributeSize (int pos) {
409
        if (superClassNameIndex > 0) {
410
            // index to the name attr
411
            int name = readU2 (pos);
412
            
413
            if (name == superClassNameIndex) {
414
                if (superClassNameAttr > 0) {
415
                    throw new IllegalStateException ("Two attributes with name " + ATTR_SUPERCLASS); // NOI18N
416
                }
417
                
418
                // we found the attribute
419
                superClassNameAttr = pos;
420
            }
421
        }
422
        
423
        int len = readU4 (pos + 2);
424
        return len + 6;
425
    }
426
}
(-)nb_all/core/src/org/netbeans/ProxyClassLoader.java (+608 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans;
15
16
import java.util.*;
17
import java.net.URL;
18
import java.io.IOException;
19
20
/**
21
 * A class loader that has multiple parents and uses them for loading
22
 * classes and resources. It can be used in tree hierarchy, where it
23
 * can exploit its capability to not throw ClassNotFoundException when
24
 * communicating with other ProxyClassLoader.
25
 * It itself doesn't load classes or resources, but allows subclasses
26
 * to add such functionality.
27
 *
28
 * @author  Petr Nejedly, Jesse Glick
29
 */
30
public class ProxyClassLoader extends ClassLoader {
31
    /** empty enumeration */
32
    private static final Enumeration EMPTY = new ArrayEnumeration (new Object[0]);
33
    
34
    
35
    // Map<String,ClassLoader>
36
    // packages are given in format "org/netbeans/modules/foo/"
37
    private final Map domainsByPackage = new HashMap(); 
38
    // Map<String,Package>
39
    private HashMap packages = new HashMap();
40
41
    // All parentf of this classloader, including their parents recursively
42
    private ClassLoader[] parents;
43
44
    /** if true, we have been destroyed */
45
    private boolean dead = false;
46
    
47
    /** Create a multi-parented classloader.
48
     * @param parents list of parent classloaders. 
49
     * @throws IllegalArgumentException if there are any nulls or duplicate
50
     * parent loaders or cycles.
51
     */
52
    public ProxyClassLoader( ClassLoader[] parents ) {
53
        if (parents.length == 0) {
54
            throw new IllegalArgumentException ("ProxyClassLoader must have a parent"); // NOI18N
55
        }
56
        
57
        Set check = new HashSet(Arrays.asList(parents)); // Set<ClassLoader>
58
        if (check.size() < parents.length) throw new IllegalArgumentException("duplicate parents"); // NOI18N
59
        if (check.contains(null)) throw new IllegalArgumentException("null parent"); // NOI18N
60
61
        this.parents = coalesceParents(parents);
62
    }
63
    
64
    // this is used only by system classloader, maybe we can redesign it a bit
65
    // to live without this functionality, then destroy may also go away
66
    /** Add new parents dynamically.
67
     * @param parents the new parents to add (append to list)
68
     * @throws IllegalArgumentException in case of a null or cyclic parent (duplicate OK)
69
     */
70
    public synchronized void append(ClassLoader[] nueparents) throws IllegalArgumentException {
71
        // XXX should this be synchronized?
72
        if (nueparents == null) throw new IllegalArgumentException("null parents array"); // NOI18N
73
        for (int i = 0; i < nueparents.length; i++) {
74
            if (nueparents[i] == null) throw new IllegalArgumentException("null parent"); // NOI18N
75
        }
76
        
77
        parents = coalesceAppend(parents, nueparents);
78
    }
79
80
    
81
    
82
    /** Try to destroy this classloader.
83
     * Subsequent attempts to use it will log an error (at most one though).
84
     */
85
    public void destroy() {
86
        dead = true;
87
    }
88
89
    private void zombieCheck(String hint) {
90
        if (dead) {
91
            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
92
            JarClassLoader.notify(0, ise);
93
            // don't warn again for same loader... this was enough
94
            dead = false;
95
        }
96
    }
97
98
    /**
99
     * Loads the class with the specified name.  The implementation of
100
     * this method searches for classes in the following order:<p>
101
     * <ol>
102
     * <li> Calls {@link #findLoadedClass(String)} to check if the class has
103
     *      already been loaded.
104
     * <li> Checks the caches whether another class from the same package
105
     *      was already loaded and uses the same classloader
106
     * <li> Tries to find the class using parent loaders in their order.
107
     * <li> Calls the {@link #simpleFindClass(String,String)} method to find
108
     *      the class using this class loader.
109
     * </ol>
110
     *
111
     * @param     name the name of the class
112
     * @param     resolve if <code>true</code> then resolve the class
113
     * @return	  the resulting <code>Class</code> object
114
     * @exception ClassNotFoundException if the class could not be found
115
     */
116
    protected synchronized final Class loadClass(String name, boolean resolve)
117
                                            throws ClassNotFoundException {
118
        zombieCheck(name);
119
        // XXX this section is a candidate for local optimization:
120
        String filename = name.replace('.', '/').concat(".class"); // NOI18N
121
        int idx = filename.lastIndexOf('/'); // NOI18N
122
        if (idx == -1) throw new ClassNotFoundException("Will not load classes from default package"); // NOI18N
123
        String pkg = filename.substring(0, idx + 1); // "org/netbeans/modules/foo/"
124
        Class c = smartLoadClass(name, filename, pkg);
125
        if(c == null) throw new ClassNotFoundException(name);
126
        if (resolve) resolveClass(c);
127
        return c;
128
    }
129
    
130
    /** This ClassLoader can't load anything itself. Subclasses
131
     * may override this method to do some class loading themselves. The
132
     * implementation should not throw any exception, just return
133
     * <CODE>null</CODE> if it can't load required class.
134
     *
135
     * @param  name the name of the class
136
     * @param  fileName the expected filename of the classfile, like
137
     *      <CODE>java/lang/Object.class</CODE> for <CODE>java.lang.Object</CODE>
138
     *      The ClassLoader implementation may or may not use it, depending
139
     *      whether it is usefull to it.
140
     * @return the resulting <code>Class</code> object or <code>null</code>
141
     */
142
    protected Class simpleFindClass(String name, String fileName) {
143
        return null;
144
    }
145
    
146
147
    /**
148
     * Finds the resource with the given name. The implementation of
149
     * this method searches for resources in the following order:<p>
150
     * <ol>
151
     * <li> Checks the caches whether another resource or class from the same
152
     *      package was already loaded and uses the same classloader.
153
     * <li> Tries to find the resources using parent loaders in their order.
154
     * <li> Calls the {@link #findResource(String)} method to find
155
     *      the resources using this class loader.
156
     * </ol>
157
     *
158
     * @param  name a "/"-separated path name that identifies the resource.
159
     * @return a URL for reading the resource, or <code>null</code> if
160
     *      the resource could not be found.
161
     * @see #findResource(String)
162
     */
163
    public final URL getResource(final String name) {
164
        zombieCheck(name);
165
        
166
        final int slashIdx = name.lastIndexOf('/');
167
        if (slashIdx == -1) return null;    // won't load from the default package
168
        final String pkg = name.substring(0, slashIdx + 1);
169
170
        if (isSpecialResource(pkg)) {
171
            // Disable domain cache for this one, do a simple check.
172
            for (int i = 0; i < parents.length; i++) {
173
                if (!shouldDelegateResource(pkg, parents[i])) continue;
174
                URL u;
175
                if (parents[i] instanceof ProxyClassLoader) {
176
                    u = ((ProxyClassLoader)parents[i]).findResource(name);
177
                } else {
178
                    u = parents[i].getResource(name);
179
                }
180
                if (u != null) return u;
181
            }
182
            return findResource(name);
183
        }
184
        
185
        ClassLoader owner = (ClassLoader)domainsByPackage.get(pkg);
186
187
        if (owner != null) { // known package
188
            // Note that shouldDelegateResource should already be true for this!
189
            if (owner instanceof ProxyClassLoader) {
190
                return ((ProxyClassLoader)owner).findResource(name); // we have its parents, skip them
191
	    } else {
192
                return owner.getResource(name);     // know nothing about this loader and his structure
193
            }
194
        } 
195
        
196
        // virgin package
197
        URL retVal = null;
198
        for (int i = 0; i < parents.length; i++) {
199
            owner = parents[i];
200
            if (!shouldDelegateResource(pkg, owner)) continue;
201
            if (owner instanceof ProxyClassLoader) {
202
                retVal = ((ProxyClassLoader)owner).findResource(name); // skip parents (checked already)
203
            } else {
204
                retVal = owner.getResource(name); // know nothing about this loader and his structure
205
            }
206
            if (retVal != null) {
207
                domainsByPackage.put(pkg, owner);
208
                return retVal;
209
            }
210
        }
211
        
212
        // try it ourself
213
        retVal = findResource(name);
214
        if (retVal != null) {
215
            domainsByPackage.put(pkg, this);
216
        }
217
        return retVal;
218
    }
219
220
    /** This ClassLoader can't load anything itself. Subclasses
221
     * may override this method to do some resource loading themselves.
222
     *
223
     * @param  name the resource name
224
     * @return a URL for reading the resource, or <code>null</code>
225
     *      if the resource could not be found.
226
     */
227
    protected URL findResource(String name) {
228
	return null;
229
    }
230
231
    /**
232
     * Finds all the resource with the given name. The implementation of
233
     * this method uses the {@link #simpleFindResources(String)} method to find
234
     * all the resources available from this classloader and adds all the 
235
     * resources from all the parents.
236
     *
237
     * @param  name the resource name
238
     * @return an Enumeration of URLs for the resources
239
     * @throws IOException if I/O errors occur
240
     */    
241
    protected final synchronized Enumeration findResources(String name) throws IOException {
242
        zombieCheck(name);
243
        final int slashIdx = name.lastIndexOf('/');
244
        if (slashIdx == -1) return EMPTY; // won't load from the default package
245
        final String pkg = name.substring(0, slashIdx + 1);
246
247
        // Don't bother optimizing this call by domains.
248
        // It is mostly used for resources for which isSpecialResource would be true anyway.
249
        Enumeration[] es = new Enumeration[parents.length + 1];
250
        for (int i = 0; i < parents.length; i++) {
251
            if (!shouldDelegateResource(pkg, parents[i])) {
252
                es[i] = EMPTY;
253
                continue;
254
            }
255
            if (parents[i] instanceof ProxyClassLoader) {
256
                es[i] = ((ProxyClassLoader)parents[i]).simpleFindResources(name);
257
            } else {
258
                es[i] = parents[i].getResources(name);
259
            }
260
        }
261
        es[parents.length] = simpleFindResources(name);
262
        // Should not be duplicates, assuming the parent loaders are properly distinct
263
        // from one another and do not overlap in JAR usage, which they ought not.
264
        // Anyway MetaInfServicesLookup, the most important client of this method, does
265
        // its own duplicate filtering already.
266
        return new AAEnum (es);
267
    }
268
269
    /** This ClassLoader can't load anything itself. Subclasses
270
     * may override this method to do some resource loading themselves, this
271
     * implementation simply delegates to findResources method of the superclass
272
     * that should return empty Enumeration.
273
     *
274
     * @param  name the resource name
275
     * @return an Enumeration of URLs for the resources
276
     * @throws IOException if I/O errors occur
277
     */
278
    protected Enumeration simpleFindResources(String name) throws IOException {
279
        return super.findResources(name);
280
    }
281
282
    
283
    /**
284
     * Returns a Package that has been defined by this class loader or any
285
     * of its parents.
286
     *
287
     * @param  name the package name
288
     * @return the Package corresponding to the given name, or null if not found
289
     */
290
    protected Package getPackage(String name) {
291
        zombieCheck(name);
292
        
293
        int idx = name.lastIndexOf('.');
294
        if (idx == -1) return null;
295
        String spkg = name.substring(0, idx + 1).replace('.', '/');
296
        
297
	synchronized (packages) {
298
	    Package pkg = (Package)packages.get(name);
299
            if (pkg != null) return pkg;
300
            
301
            for (int i = 0; i < parents.length; i++) {
302
                ClassLoader par = parents[i];
303
                if (par instanceof ProxyClassLoader && shouldDelegateResource(spkg, par)) {
304
                    pkg = ((ProxyClassLoader)par).getPackage(name);
305
                    if(pkg != null) break;
306
                }
307
            }
308
            // do our own lookup
309
            if (pkg == null) pkg = super.getPackage(name);
310
            // cache results
311
            if (pkg != null) packages.put(name, pkg);
312
313
            return pkg;
314
	}
315
    }
316
317
    /** This is here just for locking serialization purposes.
318
     * Delegates to super.definePackage with proper locking.
319
     */
320
    protected Package definePackage(String name, String specTitle,
321
                String specVersion, String specVendor, String implTitle,
322
		String implVersion, String implVendor, URL sealBase )
323
		throws IllegalArgumentException {
324
	synchronized (packages) {
325
	    return super.definePackage (name, specTitle, specVersion, specVendor, implTitle,
326
			implVersion, implVendor, sealBase);
327
	}
328
    }
329
330
    /**
331
     * Returns all of the Packages defined by this class loader and its parents.
332
     *
333
     * @return the array of <code>Package</code> objects defined by this
334
     * <code>ClassLoader</code>
335
     */
336
    protected synchronized Package[] getPackages() {
337
        zombieCheck(null);
338
        Map all = new HashMap(); // Map<String,Package>
339
        addPackages(all, super.getPackages());
340
        for (int i = 0; i < parents.length; i++) {
341
            ClassLoader par = parents[i];
342
            if (par instanceof ProxyClassLoader) {
343
                // XXX should ideally use shouldDelegateResource here...
344
                addPackages(all, ((ProxyClassLoader)par).getPackages());
345
            }
346
        }
347
        synchronized (packages) {
348
            Iterator it = all.entrySet().iterator();
349
            while (it.hasNext()) {
350
                Map.Entry entry = (Map.Entry)it.next();
351
                Object name = entry.getKey();
352
                if (! packages.containsKey(name)) {
353
                    packages.put(name, entry.getValue());
354
                }
355
            }
356
        }
357
        return (Package[])all.values().toArray(new Package[all.size()]);
358
    }
359
    
360
    public Package getPackageAccessibly(String name) {
361
        return getPackage(name);
362
    }
363
    
364
    public Package[] getPackagesAccessibly() {
365
        return getPackages();
366
    }
367
368
    
369
    
370
    /** Coalesce parent classloaders into an optimized set.
371
     * This means that all parents of the specified classloaders
372
     * are also added recursively, removing duplicates along the way.
373
     * Search order should be preserved (parents before children, stable w.r.t. inputs).
374
     * @param loaders list of suggested parents (no nulls or duplicates permitted)
375
     * @return optimized list of parents (no nulls or duplicates)
376
     * @throws IllegalArgumentException if there are cycles
377
     */
378
    private ClassLoader[] coalesceParents(ClassLoader[] loaders) throws IllegalArgumentException {
379
        int likelySize = loaders.length * 3 + 1;
380
        Set resultingUnique = new HashSet(likelySize); // Set<ClassLoader>
381
        List resulting = new ArrayList(likelySize); // List<ClassLoader>
382
        for (int i = 0; i < loaders.length; i++) {
383
            addRec(resultingUnique, resulting, loaders[i]);
384
        }
385
        ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]);
386
        return ret;
387
    }
388
    
389
    /** Coalesce a new set of loaders into the existing ones.
390
     */
391
    private ClassLoader[] coalesceAppend(ClassLoader[] existing, ClassLoader[] appended) throws IllegalArgumentException {
392
        int likelySize = existing.length + 3;
393
        Set resultingUnique = new HashSet(likelySize);
394
        List existingL = Arrays.asList(existing);
395
        resultingUnique.addAll(existingL);
396
        if (resultingUnique.containsAll(Arrays.asList(appended))) {
397
            // No change required.
398
            return existing;
399
        }
400
        List resulting = new ArrayList(likelySize);
401
        resulting.addAll(existingL);
402
        int fromIdx = resulting.size();
403
        for (int i = 0; i < appended.length; i++) {
404
            addRec(resultingUnique, resulting, appended[i]);
405
        }
406
        ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]);
407
        return ret;
408
    }
409
    
410
    private void addRec(Set resultingUnique, List resulting, ClassLoader loader) throws IllegalArgumentException {
411
        if (loader == this) throw new IllegalArgumentException("cycle in parents"); // NOI18N
412
        if (resultingUnique.contains(loader)) return;
413
        if (loader instanceof ProxyClassLoader) {
414
            ClassLoader[] parents = ((ProxyClassLoader)loader).parents;
415
            for (int i = 0; i < parents.length; i++) {
416
                addRec(resultingUnique, resulting, parents[i]);
417
            }
418
        }
419
        resultingUnique.add(loader);
420
        resulting.add(loader);
421
    }
422
423
    /** A method that finds a class either in itself or in parents.
424
     * It uses dual signaling for class not found: it can either return null
425
     * or throw CNFE itself.
426
     * @param name class name, e.g. "org.netbeans.modules.foo.Clazz"
427
     * @param fileName resource name, e.g. "org/netbeans/modules/foo/Clazz.class"
428
     * @param pkg package component, e.g. "org/netbeans/modules/foo/"
429
     * @return a class or null if not found. It can also throw an exception.
430
     * @throws ClassNotFoundException in case it doesn't found a class
431
     * and a parent eglible for loading it thrown it already.
432
     */
433
    private final Class smartLoadClass(String name, String fileName, String pkg) throws ClassNotFoundException {
434
	// First, check if the class has already been loaded
435
	Class c = findLoadedClass(name);
436
	if(c != null) return c;
437
        
438
        final ClassLoader owner = isSpecialResource(pkg) ? null : (ClassLoader)domainsByPackage.get(pkg);
439
        if (owner == this) {
440
            return simpleFindClass(name,fileName);
441
        }
442
        if (owner != null) {
443
            // Note that shouldDelegateResource should already be true as we hit this pkg before.
444
            if (owner instanceof ProxyClassLoader) {
445
                return ((ProxyClassLoader)owner).fullFindClass(name,fileName);
446
            } else {
447
                return owner.loadClass(name); // May throw CNFE, will be propagated
448
            }
449
        }
450
        
451
        // Virgin package, do the parent scan 
452
        c = loadInOrder(name, fileName, pkg);
453
454
        if (c != null) {
455
            final ClassLoader owner2 = c.getClassLoader(); // who got it?
456
            domainsByPackage.put(pkg, owner2);
457
        }
458
        return c;
459
    }
460
    
461
    
462
    private final Class loadInOrder( String name, String fileName, String pkg ) throws ClassNotFoundException {
463
        ClassNotFoundException cached = null;
464
        for (int i = 0; i < parents.length; i++) {
465
	    ClassLoader par = parents[i];
466
            if (!shouldDelegateResource(pkg, par)) continue;
467
	    if (par instanceof ProxyClassLoader) {
468
		Class c = ((ProxyClassLoader)par).fullFindClass(name,fileName);
469
                if (c != null) return c;
470
	    } else {
471
		try {
472
		    return par.loadClass(name);
473
		} catch( ClassNotFoundException cnfe ) {
474
                    cached = cnfe;
475
                }
476
	    }
477
	}
478
479
        Class c = simpleFindClass(name,fileName); // Try it ourselves
480
        if (c != null) return c;
481
        if (cached != null) throw cached;
482
	return null;
483
    }
484
485
    private synchronized Class fullFindClass(String name, String fileName) {
486
	Class c = findLoadedClass(name);
487
	return (c == null) ? simpleFindClass(name, fileName) : c;
488
    }    
489
490
    private void addPackages(Map all, Package[] pkgs) {
491
        // Would be easier if Package.equals() was just defined sensibly...
492
        for (int i = 0; i < pkgs.length; i++) {
493
            all.put(pkgs[i].getName(), pkgs[i]);
494
        }
495
    }
496
    
497
    /** Test whether a given resource name is something that any JAR might
498
     * have, and for which the domain cache should be disabled.
499
     * The result must not change from one call to the next with the same argument.
500
     * By default the domain cache is disabled only for META-INF/* JAR information.
501
     * @param pkg the package component of the resource path ending with a slash,
502
     *        e.g. "org/netbeans/modules/foo/"
503
     * @return true if it is a special resource, false for normal domain-cached resource
504
     * @since org.netbeans.core/1 1.3
505
     */
506
    protected boolean isSpecialResource(String pkg) {
507
        if (pkg.startsWith("META-INF/")) return true; // NOI18N
508
        return false;
509
    }
510
    
511
    /** Test whether a given resource request (for a class or not) should be
512
     * searched for in the specified parent classloader or not.
513
     * The result must not change from one call to the next with the same arguments.
514
     * By default, always true. Subclasses may override to "mask" certain
515
     * packages from view, possibly according to the classloader chain.
516
     * @param pkg the package component of the resource path ending with a slash,
517
     *        e.g. "org/netbeans/modules/foo/"
518
     * @param parent a classloader which is a direct or indirect parent of this one
519
     * @return true if the request should be delegated to this parent; false to
520
     *         only search elsewhere (other parents, this loader's own namespace)
521
     * @since org.netbeans.core/1 1.3
522
     */
523
    protected boolean shouldDelegateResource(String pkg, ClassLoader parent) {
524
        return true;
525
    }
526
    
527
    
528
    private static final class ArrayEnumeration implements Enumeration {
529
        /** The array */
530
        private Object[] array;
531
        /** Current index in the array */
532
        private int index = 0;
533
534
        /** Constructs a new ArrayEnumeration for specified array */
535
        public ArrayEnumeration (Object[] array) {
536
            this.array = array;
537
        }
538
539
        /** Tests if this enumeration contains more elements.
540
        * @return  <code>true</code> if this enumeration contains more elements;
541
        *          <code>false</code> otherwise.
542
        */
543
        public boolean hasMoreElements() {
544
            return (index < array.length);
545
        }
546
547
        /** Returns the next element of this enumeration.
548
        * @return     the next element of this enumeration.
549
        * @exception  NoSuchElementException  if no more elements exist.
550
        */
551
        public Object nextElement() {
552
            try {
553
                return array[index++];
554
            } catch (ArrayIndexOutOfBoundsException e) {
555
                throw new NoSuchElementException();
556
            }
557
        }
558
    }
559
    
560
    private static final class AAEnum implements Enumeration {
561
        /** The array */
562
        private Enumeration[] array;
563
        /** Current index in the array */
564
        private int index = 0;
565
566
        /** Constructs a new ArrayEnumeration for specified array */
567
        public AAEnum (Enumeration[] array) {
568
            this.array = array;
569
        }
570
571
        /** Tests if this enumeration contains more elements.
572
        * @return  <code>true</code> if this enumeration contains more elements;
573
        *          <code>false</code> otherwise.
574
        */
575
        public boolean hasMoreElements() {
576
            for (;;) {
577
                if (index == array.length) {
578
                    return false;
579
                }
580
581
                if (array[index].hasMoreElements ()) {
582
                    return true;
583
                }
584
                
585
                index++;
586
            }
587
        }
588
589
        /** Returns the next element of this enumeration.
590
        * @return     the next element of this enumeration.
591
        * @exception  NoSuchElementException  if no more elements exist.
592
        */
593
        public Object nextElement() {
594
            try {
595
                return array[index].nextElement ();
596
            } catch (NoSuchElementException ex) {
597
                if (hasMoreElements ()) {
598
                    // try once more
599
                    return nextElement ();
600
                }
601
                throw ex;
602
            } catch (ArrayIndexOutOfBoundsException e) {
603
                throw new NoSuchElementException();
604
            }
605
        }
606
    }
607
    
608
}
(-)nb_all/core/src/org/netbeans/core/Main.java (-2 / +2 lines)
 Lines 121-127    Link Here 
121
  /** Starts TopThreadGroup which properly overrides uncaughtException
121
  /** Starts TopThreadGroup which properly overrides uncaughtException
122
   * Further - new thread in the group execs main
122
   * Further - new thread in the group execs main
123
   */
123
   */
124
  public static void start(String[] argv) {
124
  public static void main (String[] argv) {
125
    TopThreadGroup tg = new TopThreadGroup ("IDE Main", argv); // NOI18N - programatic name
125
    TopThreadGroup tg = new TopThreadGroup ("IDE Main", argv); // NOI18N - programatic name
126
    tg.start ();
126
    tg.start ();
127
  }
127
  }
 Lines 356-362    Link Here 
356
  /**
356
  /**
357
  * @exception SecurityException if it is called multiple times
357
  * @exception SecurityException if it is called multiple times
358
  */
358
  */
359
  public static void main(String[] args) throws SecurityException {
359
  static void start (String[] args) throws SecurityException {
360
    long time = System.currentTimeMillis();
360
    long time = System.currentTimeMillis();
361
    
361
    
362
    StartLog.logEnd ("Forwarding to topThreadGroup"); // NOI18N
362
    StartLog.logEnd ("Forwarding to topThreadGroup"); // NOI18N
(-)nb_all/core/src/org/netbeans/core/TopThreadGroup.java (-1 / +1 lines)
 Lines 78-84    Link Here 
78
78
79
    public void run() {
79
    public void run() {
80
        try {
80
        try {
81
            Main.main(args);
81
            Main.start (args);
82
        } catch (Throwable t) {
82
        } catch (Throwable t) {
83
            // XXX is this not handled by uncaughtException?
83
            // XXX is this not handled by uncaughtException?
84
            ErrorManager.getDefault().notify(t);
84
            ErrorManager.getDefault().notify(t);
(-)nb_all/core/src/org/netbeans/core/modules/JarClassLoader.java (-401 lines)
Removed Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.core.modules;
15
16
import java.net.URL;
17
import java.util.jar.JarFile;
18
import java.util.jar.Manifest;
19
import java.util.jar.Attributes;
20
import java.util.jar.Attributes.Name;
21
import java.util.zip.ZipEntry;
22
import java.io.*;
23
import java.net.MalformedURLException;
24
import java.security.*;
25
import java.security.cert.Certificate;
26
import java.util.*;
27
import java.lang.reflect.Field;
28
import java.lang.reflect.Modifier;
29
30
import org.openide.ErrorManager;
31
32
/**
33
 * A ProxyClassLoader capable of loading classes from a set of jar files
34
 * and local directories.
35
 *
36
 * @author  Petr Nejedly
37
 */
38
public class JarClassLoader extends ProxyClassLoader {
39
    private Source[] sources;
40
    /** temp copy JARs which ought to be deleted */
41
    private Set deadJars = null; // Set<JarFile>
42
    
43
    /** Creates new JarClassLoader */
44
    public JarClassLoader (List files, ClassLoader[] parents) {
45
        super(parents);
46
47
        sources = new Source[files.size()];
48
        try {
49
            int i=0;
50
            for (Iterator it = files.iterator(); it.hasNext(); i++ ) {
51
                Object act = it.next();
52
                if (act instanceof File) {
53
                    sources[i] = new DirSource((File)act);
54
                } else {
55
                    sources[i] = new JarSource((JarFile)act);
56
                }
57
            }
58
        } catch (MalformedURLException exc) {
59
            throw new IllegalArgumentException(exc.getMessage());
60
        }
61
            
62
    }
63
64
    protected PermissionCollection getPermissions( CodeSource cs ) {
65
        return Policy.getPolicy().getPermissions(cs);
66
    }    
67
68
    protected Package definePackage(String name, Manifest man, URL url)
69
	throws IllegalArgumentException
70
    {
71
        if (man == null ) {
72
            return definePackage(name, null, null, null, null, null, null, null);
73
        }
74
        
75
	String path = name.replace('.', '/').concat("/"); // NOI18N
76
	Attributes spec = man.getAttributes(path);
77
        Attributes main = man.getMainAttributes();
78
	
79
        String specTitle = getAttr(spec, main, Name.SPECIFICATION_TITLE);
80
        String implTitle = getAttr(spec, main, Name.IMPLEMENTATION_TITLE);
81
        String specVersion = getAttr(spec, main, Name.SPECIFICATION_VERSION);
82
        String implVersion = getAttr(spec, main, Name.IMPLEMENTATION_VERSION);
83
        String specVendor = getAttr(spec, main, Name.SPECIFICATION_VENDOR);
84
        String implVendor = getAttr(spec, main, Name.IMPLEMENTATION_VENDOR);
85
        String sealed      = getAttr(spec, main, Name.SEALED);
86
87
        URL sealBase = "true".equalsIgnoreCase(sealed) ? url : null; // NOI18N
88
	return definePackage(name, specTitle, specVersion, specVendor,
89
			     implTitle, implVersion, implVendor, sealBase);
90
    }
91
92
    private static String getAttr(Attributes spec, Attributes main, Name name) {
93
        String val = null;
94
        if (spec != null) val = spec.getValue (name);
95
        if (val == null && main != null) val = main.getValue (name);
96
        return val;
97
    }
98
99
    protected Class simpleFindClass(String name, String path) {
100
        // look up the Sources and return a class based on their content
101
        for( int i=0; i<sources.length; i++ ) {
102
            Source src = sources[i];
103
            byte[] data = src.getClassData(name, path);
104
            if (data == null) continue;
105
            
106
            int j = name.lastIndexOf('.');
107
            String pkgName = name.substring(0, j);
108
            Package pkg = getPackage(pkgName);
109
            
110
            if (pkg != null) {
111
                // XXX full sealing check, URLClassLoader does something more
112
                if (pkg.isSealed() && !pkg.isSealed(src.getURL())) throw new SecurityException("sealing violation"); // NOI18N
113
            } else {
114
                Manifest man = src.getManifest();
115
                definePackage (pkgName, man, src.getURL());
116
            }
117
            
118
            return defineClass (name, data, 0, data.length, src.getProtectionDomain());
119
        }
120
        return null;
121
    }
122
    // look up the jars and return a resource based on a content of jars
123
    protected URL findResource(String name) {
124
        for( int i=0; i<sources.length; i++ ) {
125
            URL item = sources[i].getResource(name);
126
            if (item != null) return item;
127
        }
128
	return null;
129
    }
130
131
    protected Enumeration simpleFindResources(String name) {
132
        Vector v = new Vector(3);
133
        // look up the jars and return a resource based on a content of jars
134
135
        for( int i=0; i<sources.length; i++ ) {
136
            URL item = sources[i].getResource(name);
137
            if (item != null) v.add(item);
138
        }
139
        return v.elements();
140
    }
141
142
    /** Try to release any JAR locks held by this classloader.
143
     * @see #21114
144
     */
145
    void releaseLocks() {
146
        if (deadJars != null) throw new IllegalStateException();
147
        deadJars = new HashSet(); // Set<JarFile>
148
        try {
149
            for (int i = 0; i < sources.length; i++) {
150
                if (sources[i] instanceof JarSource) {
151
                    JarFile origJar = ((JarSource)sources[i]).getJarFile();
152
                    File orig = new File(origJar.getName());
153
                    if (!orig.isFile()) {
154
                        // Can happen when a test module is deleted:
155
                        // the physical JAR has already been deleted
156
                        // when the module was disabled. In this case it
157
                        // is possible that a classloader request for something
158
                        // in the JAR could still come in. Does it matter?
159
                        // See comment in Module.cleanup.
160
                        continue;
161
                    }
162
                    String name = orig.getName();
163
                    String prefix, suffix;
164
                    int idx = name.lastIndexOf('.');
165
                    if (idx == -1) {
166
                        prefix = name;
167
                        suffix = null;
168
                    } else {
169
                        prefix = name.substring(0, idx);
170
                        suffix = name.substring(idx);
171
                    }
172
                    while (prefix.length() < 3) prefix += "x"; // NOI18N
173
                    File temp = File.createTempFile(prefix, suffix);
174
                    temp.deleteOnExit();
175
                    InputStream is = new FileInputStream(orig);
176
                    try {
177
                        OutputStream os = new FileOutputStream(temp);
178
                        try {
179
                            byte[] buf = new byte[4096];
180
                            int j;
181
                            while ((j = is.read(buf)) != -1) {
182
                                os.write(buf, 0, j);
183
                            }
184
                        } finally {
185
                            os.close();
186
                        }
187
                    } finally {
188
                        is.close();
189
                    }
190
                    // Don't use OPEN_DELETE even though it sounds like a good idea.
191
                    // Can cause real problems under 1.4; see Module.java.
192
                    JarFile tempJar = new JarFile(temp);
193
                    origJar.close();
194
                    forceRelease(orig);
195
                    deadJars.add(tempJar);
196
                    sources[i] = new JarSource(tempJar);
197
                    Util.err.log("#21114: replacing " + orig + " with " + temp);
198
                }
199
            }
200
        } catch (IOException ioe) {
201
            Util.err.notify(ErrorManager.INFORMATIONAL, ioe);
202
        }
203
    }
204
    
205
    /** Release jar: locks when the classloader is shut down.
206
     * Should help reloading modules with changed resources.
207
     */
208
    public void destroy() {
209
        super.destroy();
210
        for (int i = 0; i < sources.length; i++) {
211
            if (sources[i] instanceof JarSource) {
212
                JarFile j = ((JarSource)sources[i]).getJarFile();
213
                File f = new File(j.getName());
214
                forceRelease(f);
215
            }
216
        }
217
    }
218
    
219
    /** Delete any temporary JARs we were holding on to.
220
     * Also close any other JARs in our list.
221
     */
222
    protected void finalize() throws Throwable {
223
        super.finalize();
224
        for (int i = 0; i < sources.length; i++) {
225
            if (sources[i] instanceof JarSource) {
226
                JarFile j = ((JarSource)sources[i]).getJarFile();
227
                File f = new File(j.getName());
228
                j.close();
229
                forceRelease(f);
230
                if (deadJars != null && deadJars.contains(j)) {
231
                    Util.err.log("#21114: closing and deleting temporary JAR " + f);
232
                    if (f.isFile() && !f.delete()) {
233
                        Util.err.log("(but failed to delete it)");
234
                    }
235
                }
236
            }
237
        }
238
    }
239
    
240
    /** Make sure the Java runtime's jar: URL cache is not holding
241
     * onto the specified file.
242
     * Workaround for JDK bug #4646668.
243
     */
244
    private static void forceRelease(File f) {
245
        if (fileCache == null || factory == null) return;
246
        try {
247
            synchronized (factory) {
248
                Iterator it = fileCache.values().iterator();
249
                while (it.hasNext()) {
250
                    JarFile j = (JarFile)it.next();
251
                    if (f.equals(new File(j.getName()))) {
252
                        j.close();
253
                        it.remove();
254
                        Util.err.log("Removing jar: cache for " + f + " as workaround for JDK #4646668");
255
                    }
256
                }
257
            }
258
        } catch (Exception e) {
259
            Util.err.annotate(e, ErrorManager.UNKNOWN, "Could not remove jar: cache for " + f, null, null, null);
260
            Util.err.notify(ErrorManager.INFORMATIONAL, e);
261
        }
262
    }
263
    private static Object factory = null;
264
    private static HashMap fileCache = null;
265
    static {
266
        try {
267
            Class juc = Class.forName("sun.net.www.protocol.jar.JarURLConnection"); // NOI18N
268
            Field factoryF = juc.getDeclaredField("factory"); // NOI18N
269
            factoryF.setAccessible(true);
270
            factory = factoryF.get(null);
271
            Class jff = Class.forName("sun.net.www.protocol.jar.JarFileFactory"); // NOI18N
272
            if (!jff.isInstance(factory)) throw new ClassCastException(factory.getClass().getName());
273
            Field fileCacheF = jff.getDeclaredField("fileCache"); // NOI18N
274
            fileCacheF.setAccessible(true);
275
            if (Modifier.isStatic(fileCacheF.getModifiers())) {
276
                // JDK 1.3.1 or 1.4 seems to have it static.
277
                fileCache = (HashMap)fileCacheF.get(null);
278
            } else {
279
                // But in 1.3.0 it appears to be an instance var.
280
                fileCache = (HashMap)fileCacheF.get(factory);
281
            }
282
            Util.err.log("Workaround for JDK #4646668 active as part of IZ #21114");
283
        } catch (Exception e) {
284
            Util.err.annotate(e, ErrorManager.UNKNOWN, "Workaround for JDK #4646668 as part of IZ #21114 failed", null, null, null);
285
            Util.err.notify(ErrorManager.INFORMATIONAL, e);
286
        }
287
    }
288
289
    abstract class Source {
290
        private URL url;
291
        private ProtectionDomain pd;
292
        
293
        public Source(URL url) {
294
            this.url = url;
295
            CodeSource cs = new CodeSource(url, new Certificate[0]);
296
            pd = new ProtectionDomain(cs, getPermissions(cs));
297
        }
298
        
299
        public final URL getURL() {
300
            return url;
301
        }
302
        
303
        public final ProtectionDomain getProtectionDomain() {
304
            return pd;
305
        }
306
  
307
        public final URL getResource(String name) {
308
            try {
309
                return doGetResource(name);
310
            } catch (MalformedURLException e) {
311
                Util.err.log(e.toString());
312
            }
313
            return null;
314
        }
315
        
316
        protected abstract URL doGetResource(String name) throws MalformedURLException;
317
        
318
        public final byte[] getClassData(String name, String path) {
319
            try {
320
                return readClass(name, path);
321
            } catch (IOException e) {
322
                Util.err.log(e.toString());
323
            }
324
            return null;
325
        }
326
327
        protected abstract byte[] readClass(String name, String path) throws IOException;
328
329
        public Manifest getManifest() {
330
            return null;
331
        }
332
    }
333
334
    class JarSource extends Source {
335
        JarFile src;
336
        
337
        public JarSource(JarFile file) throws MalformedURLException {
338
            super(new URL("file:" + file.getName()));
339
            src = file;
340
        }
341
342
        public Manifest getManifest() {
343
            try {
344
                return src.getManifest();
345
            } catch (IOException e) {
346
                return null;
347
            }
348
        }
349
        
350
        JarFile getJarFile() {
351
            return src;
352
        }
353
        
354
        protected URL doGetResource(String name) throws MalformedURLException {
355
            ZipEntry ze = src.getEntry(name);
356
            return ze == null ? null : new URL("jar:file:" + src.getName() + "!/" + ze.getName()); // NOI18N
357
        }
358
        
359
        protected byte[] readClass(String name, String path) throws IOException {
360
            ZipEntry ze = src.getEntry(path);
361
            if (ze == null) return null;
362
            
363
            int len = (int)ze.getSize();
364
            byte[] data = new byte[len];
365
            InputStream is = src.getInputStream(ze);
366
            int count = 0;
367
            while (count < len) {
368
                count += is.read(data, count, len-count);
369
            }
370
            return data;
371
        }
372
    }
373
374
    class DirSource extends Source {
375
        File dir;
376
        
377
        public DirSource(File file) throws MalformedURLException {
378
            super(file.toURL());
379
            dir = file;
380
        }
381
382
        protected URL doGetResource(String name) throws MalformedURLException {
383
            File resFile = new File(dir, name);
384
            return resFile.exists() ? resFile.toURL() : null;
385
        }
386
        
387
        protected byte[] readClass(String name, String path) throws IOException {
388
            File clsFile = new File(dir, path.replace('/', File.separatorChar));
389
            
390
            int len = (int)clsFile.length();
391
            byte[] data = new byte[len];
392
            InputStream is = new FileInputStream(clsFile);
393
            int count = 0;
394
            while (count < len) {
395
                count += is.read(data, count, len-count);
396
            }
397
            return data;
398
        }
399
        
400
    }
401
}
(-)nb_all/core/src/org/netbeans/core/modules/Module.java (-8 / +48 lines)
 Lines 30-35    Link Here 
30
import org.openide.modules.SpecificationVersion;
30
import org.openide.modules.SpecificationVersion;
31
import org.openide.modules.Dependency;
31
import org.openide.modules.Dependency;
32
import org.openide.util.WeakSet;
32
import org.openide.util.WeakSet;
33
import org.netbeans.JarClassLoader;
34
import org.netbeans.ProxyClassLoader;
33
35
34
/** Object representing one module, possibly installed.
36
/** Object representing one module, possibly installed.
35
 * Responsible for opening of module JAR file; reading
37
 * Responsible for opening of module JAR file; reading
 Lines 797-811    Link Here 
797
        // #9273: load any modules/patches/this-code-name/*.jar files first:
799
        // #9273: load any modules/patches/this-code-name/*.jar files first:
798
        File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
800
        File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
799
                                 getCodeNameBase().replace('.', '-')); // NOI18N
801
                                 getCodeNameBase().replace('.', '-')); // NOI18N
800
        if (patchdir.isDirectory()) {
802
        
801
            File[] jars = patchdir.listFiles(Util.jarFilter());
803
        scanFilesInADir (patchdir, classp);
802
            if (jars != null) {
804
        
803
                for (int j = 0; j < jars.length; j++) {
805
        String patchesClassPath = System.getProperty ("netbeans.patches." + getCodeNameBase ()); // NOI18N
804
                    ev.log(Events.PATCH, jars[j]);
806
        if (patchesClassPath != null) {
805
                    classp.add(new JarFile(jars[j]));
807
            //scanFilesInADir (new File (dir), classp);
808
            StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator);
809
            while (tokenizer.hasMoreElements()) {
810
                String element = (String) tokenizer.nextElement();
811
                File fileElement = new File(element);
812
                if (fileElement.isDirectory()) {
813
                    // adding directory
814
                    Util.err.log("module patches: adding directory "+fileElement+" for "+getCodeNameBase());
815
                    File[] jars = fileElement.listFiles(Util.jarFilter());
816
                    if (jars != null) {
817
                        for (int j=0; j < jars.length; j++) {
818
                            // add jar files
819
                            System.out.println("adding jar file:"+jars[j]);
820
                            classp.add( new JarFile(jars[j]));
821
                        }
822
                    }
823
                    // add also dir
824
                    System.out.println("adding directory:"+fileElement);
825
                    classp.add((Object) fileElement);
806
                }
826
                }
807
            } else {
808
                Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir);
809
            }
827
            }
810
        }
828
        }
811
        if (reloadable) {
829
        if (reloadable) {
 Lines 829-834    Link Here 
829
            File act = (File)it.next();
847
            File act = (File)it.next();
830
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act));
848
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act));
831
        }
849
        }
850
        
851
        if (loaders.isEmpty()) {
852
            loaders.add (Module.class.getClassLoader());
853
        }
854
        
832
        try {
855
        try {
833
            classloader = new OneModuleClassLoader(classp, (ClassLoader[])loaders.toArray(new ClassLoader[loaders.size()]));
856
            classloader = new OneModuleClassLoader(classp, (ClassLoader[])loaders.toArray(new ClassLoader[loaders.size()]));
834
        } catch (IllegalArgumentException iae) {
857
        } catch (IllegalArgumentException iae) {
 Lines 839-844    Link Here 
839
        }
862
        }
840
        oldClassLoaders.add(classloader);
863
        oldClassLoaders.add(classloader);
841
    }
864
    }
865
    
866
    /** Scans content of a directory */
867
    private void scanFilesInADir (File patchdir, List classp) throws IOException {
868
        if (!patchdir.isDirectory()) {
869
            return;
870
        }
871
        File[] jars = patchdir.listFiles(Util.jarFilter());
872
        if (jars != null) {
873
            for (int j = 0; j < jars.length; j++) {
874
                ev.log(Events.PATCH, jars[j]);
875
                classp.add(new JarFile(jars[j]));
876
            }
877
        } else {
878
            Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir);
879
        }
880
    }
881
    
842
    /** Turn off the classloader and release all resources. */
882
    /** Turn off the classloader and release all resources. */
843
    void classLoaderDown() {
883
    void classLoaderDown() {
844
        if (isFixed()) return; // don't touch it
884
        if (isFixed()) return; // don't touch it
(-)nb_all/core/src/org/netbeans/core/modules/ModuleManager.java (-2 / +6 lines)
 Lines 31-36    Link Here 
31
import org.openide.modules.SpecificationVersion;
31
import org.openide.modules.SpecificationVersion;
32
import org.openide.modules.Dependency;
32
import org.openide.modules.Dependency;
33
import org.openide.ErrorManager;
33
import org.openide.ErrorManager;
34
import org.netbeans.ProxyClassLoader;
34
35
35
/** Manages a collection of modules.
36
/** Manages a collection of modules.
36
 * Must use {@link #mutex} to access its important methods.
37
 * Must use {@link #mutex} to access its important methods.
 Lines 56-62    Link Here 
56
    
57
    
57
    private final ModuleInstaller installer;
58
    private final ModuleInstaller installer;
58
    
59
    
59
    private SystemClassLoader classLoader = new SystemClassLoader(new ClassLoader[0]);
60
    private SystemClassLoader classLoader = new SystemClassLoader(new ClassLoader[] {ModuleManager.class.getClassLoader()});
60
    private final Object classLoaderLock = "ModuleManager.classLoaderLock"; // NOI18N
61
    private final Object classLoaderLock = "ModuleManager.classLoaderLock"; // NOI18N
61
    
62
    
62
    private final Events ev;
63
    private final Events ev;
 Lines 233-245    Link Here 
233
            }
234
            }
234
            parents.add(m.getClassLoader());
235
            parents.add(m.getClassLoader());
235
        }
236
        }
237
        if (parents.isEmpty()) {
238
            parents.add (ModuleManager.class.getClassLoader());
239
        }
236
        ClassLoader[] parentCLs = (ClassLoader[])parents.toArray(new ClassLoader[parents.size()]);
240
        ClassLoader[] parentCLs = (ClassLoader[])parents.toArray(new ClassLoader[parents.size()]);
237
        SystemClassLoader nue;
241
        SystemClassLoader nue;
238
        try {
242
        try {
239
            nue = new SystemClassLoader(parentCLs);
243
            nue = new SystemClassLoader(parentCLs);
240
        } catch (IllegalArgumentException iae) {
244
        } catch (IllegalArgumentException iae) {
241
            Util.err.notify(iae);
245
            Util.err.notify(iae);
242
            nue = new SystemClassLoader(new ClassLoader[0]);
246
            nue = new SystemClassLoader(new ClassLoader[] {ModuleManager.class.getClassLoader()});
243
        }
247
        }
244
        synchronized (classLoaderLock) {
248
        synchronized (classLoaderLock) {
245
            classLoader = nue;
249
            classLoader = nue;
(-)nb_all/core/src/org/netbeans/core/modules/ProxyClassLoader.java (-527 lines)
Removed Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.core.modules;
15
16
import java.util.*;
17
import java.net.URL;
18
import java.io.IOException;
19
import org.openide.ErrorManager;
20
import org.openide.util.WeakSet;
21
import org.openide.util.enum.*;
22
23
/**
24
 * A class loader that has multiple parents and uses them for loading
25
 * classes and resources. It can be used in tree hierarchy, where it
26
 * can exploit its capability to not throw ClassNotFoundException when
27
 * communicating with other ProxyClassLoader.
28
 * It itself doesn't load classes or resources, but allows subclasses
29
 * to add such functionality.
30
 *
31
 * @author  Petr Nejedly, Jesse Glick
32
 */
33
public class ProxyClassLoader extends ClassLoader {
34
    
35
    // Map<String,ClassLoader>
36
    // packages are given in format "org/netbeans/modules/foo/"
37
    private final Map domainsByPackage = new HashMap(); 
38
    // Map<String,Package>
39
    private HashMap packages = new HashMap();
40
41
    // All parentf of this classloader, including their parents recursively
42
    private ClassLoader[] parents;
43
44
    /** if true, we have been destroyed */
45
    private boolean dead = false;
46
    
47
    /** Create a multi-parented classloader.
48
     * @param parents list of parent classloaders. 
49
     * @throws IllegalArgumentException if there are any nulls or duplicate
50
     * parent loaders or cycles.
51
     */
52
    public ProxyClassLoader( ClassLoader[] parents ) {
53
        if (parents.length == 0) {
54
            parents = new ClassLoader[] { ProxyClassLoader.class.getClassLoader() };
55
        }
56
        
57
        Set check = new HashSet(Arrays.asList(parents)); // Set<ClassLoader>
58
        if (check.size() < parents.length) throw new IllegalArgumentException("duplicate parents"); // NOI18N
59
        if (check.contains(null)) throw new IllegalArgumentException("null parent"); // NOI18N
60
61
        this.parents = coalesceParents(parents);
62
    }
63
    
64
    // this is used only by system classloader, maybe we can redesign it a bit
65
    // to live without this functionality, then destroy may also go away
66
    /** Add new parents dynamically.
67
     * @param parents the new parents to add (append to list)
68
     * @throws IllegalArgumentException in case of a null or cyclic parent (duplicate OK)
69
     */
70
    public synchronized void append(ClassLoader[] nueparents) throws IllegalArgumentException {
71
        // XXX should this be synchronized?
72
        if (nueparents == null) throw new IllegalArgumentException("null parents array"); // NOI18N
73
        for (int i = 0; i < nueparents.length; i++) {
74
            if (nueparents[i] == null) throw new IllegalArgumentException("null parent"); // NOI18N
75
        }
76
        
77
        parents = coalesceAppend(parents, nueparents);
78
    }
79
80
    
81
    
82
    /** Try to destroy this classloader.
83
     * Subsequent attempts to use it will log an error (at most one though).
84
     */
85
    public void destroy() {
86
        dead = true;
87
    }
88
89
    private void zombieCheck(String hint) {
90
        if (dead) {
91
            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
92
            ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ise);
93
            // don't warn again for same loader... this was enough
94
            dead = false;
95
        }
96
    }
97
98
    /**
99
     * Loads the class with the specified name.  The implementation of
100
     * this method searches for classes in the following order:<p>
101
     * <ol>
102
     * <li> Calls {@link #findLoadedClass(String)} to check if the class has
103
     *      already been loaded.
104
     * <li> Checks the caches whether another class from the same package
105
     *      was already loaded and uses the same classloader
106
     * <li> Tries to find the class using parent loaders in their order.
107
     * <li> Calls the {@link #simpleFindClass(String,String)} method to find
108
     *      the class using this class loader.
109
     * </ol>
110
     *
111
     * @param     name the name of the class
112
     * @param     resolve if <code>true</code> then resolve the class
113
     * @return	  the resulting <code>Class</code> object
114
     * @exception ClassNotFoundException if the class could not be found
115
     */
116
    protected synchronized final Class loadClass(String name, boolean resolve)
117
                                            throws ClassNotFoundException {
118
        zombieCheck(name);
119
        // XXX this section is a candidate for local optimization:
120
        String filename = name.replace('.', '/').concat(".class"); // NOI18N
121
        int idx = filename.lastIndexOf('/'); // NOI18N
122
        if (idx == -1) throw new ClassNotFoundException("Will not load classes from default package"); // NOI18N
123
        String pkg = filename.substring(0, idx + 1); // "org/netbeans/modules/foo/"
124
        Class c = smartLoadClass(name, filename, pkg);
125
        if(c == null) throw new ClassNotFoundException(name);
126
        if (resolve) resolveClass(c);
127
        return c;
128
    }
129
    
130
    /** This ClassLoader can't load anything itself. Subclasses
131
     * may override this method to do some class loading themselves. The
132
     * implementation should not throw any exception, just return
133
     * <CODE>null</CODE> if it can't load required class.
134
     *
135
     * @param  name the name of the class
136
     * @param  fileName the expected filename of the classfile, like
137
     *      <CODE>java/lang/Object.class</CODE> for <CODE>java.lang.Object</CODE>
138
     *      The ClassLoader implementation may or may not use it, depending
139
     *      whether it is usefull to it.
140
     * @return the resulting <code>Class</code> object or <code>null</code>
141
     */
142
    protected Class simpleFindClass(String name, String fileName) {
143
        return null;
144
    }
145
    
146
147
    /**
148
     * Finds the resource with the given name. The implementation of
149
     * this method searches for resources in the following order:<p>
150
     * <ol>
151
     * <li> Checks the caches whether another resource or class from the same
152
     *      package was already loaded and uses the same classloader.
153
     * <li> Tries to find the resources using parent loaders in their order.
154
     * <li> Calls the {@link #findResource(String)} method to find
155
     *      the resources using this class loader.
156
     * </ol>
157
     *
158
     * @param  name a "/"-separated path name that identifies the resource.
159
     * @return a URL for reading the resource, or <code>null</code> if
160
     *      the resource could not be found.
161
     * @see #findResource(String)
162
     */
163
    public final URL getResource(final String name) {
164
        zombieCheck(name);
165
        
166
        final int slashIdx = name.lastIndexOf('/');
167
        if (slashIdx == -1) return null;    // won't load from the default package
168
        final String pkg = name.substring(0, slashIdx + 1);
169
170
        if (isSpecialResource(pkg)) {
171
            // Disable domain cache for this one, do a simple check.
172
            for (int i = 0; i < parents.length; i++) {
173
                if (!shouldDelegateResource(pkg, parents[i])) continue;
174
                URL u;
175
                if (parents[i] instanceof ProxyClassLoader) {
176
                    u = ((ProxyClassLoader)parents[i]).findResource(name);
177
                } else {
178
                    u = parents[i].getResource(name);
179
                }
180
                if (u != null) return u;
181
            }
182
            return findResource(name);
183
        }
184
        
185
        ClassLoader owner = (ClassLoader)domainsByPackage.get(pkg);
186
187
        if (owner != null) { // known package
188
            // Note that shouldDelegateResource should already be true for this!
189
            if (owner instanceof ProxyClassLoader) {
190
                return ((ProxyClassLoader)owner).findResource(name); // we have its parents, skip them
191
	    } else {
192
                return owner.getResource(name);     // know nothing about this loader and his structure
193
            }
194
        } 
195
        
196
        // virgin package
197
        URL retVal = null;
198
        for (int i = 0; i < parents.length; i++) {
199
            owner = parents[i];
200
            if (!shouldDelegateResource(pkg, owner)) continue;
201
            if (owner instanceof ProxyClassLoader) {
202
                retVal = ((ProxyClassLoader)owner).findResource(name); // skip parents (checked already)
203
            } else {
204
                retVal = owner.getResource(name); // know nothing about this loader and his structure
205
            }
206
            if (retVal != null) {
207
                domainsByPackage.put(pkg, owner);
208
                return retVal;
209
            }
210
        }
211
        
212
        // try it ourself
213
        retVal = findResource(name);
214
        if (retVal != null) {
215
            domainsByPackage.put(pkg, this);
216
        }
217
        return retVal;
218
    }
219
220
    /** This ClassLoader can't load anything itself. Subclasses
221
     * may override this method to do some resource loading themselves.
222
     *
223
     * @param  name the resource name
224
     * @return a URL for reading the resource, or <code>null</code>
225
     *      if the resource could not be found.
226
     */
227
    protected URL findResource(String name) {
228
	return null;
229
    }
230
231
    /**
232
     * Finds all the resource with the given name. The implementation of
233
     * this method uses the {@link #simpleFindResources(String)} method to find
234
     * all the resources available from this classloader and adds all the 
235
     * resources from all the parents.
236
     *
237
     * @param  name the resource name
238
     * @return an Enumeration of URLs for the resources
239
     * @throws IOException if I/O errors occur
240
     */    
241
    protected final synchronized Enumeration findResources(String name) throws IOException {
242
        zombieCheck(name);
243
        final int slashIdx = name.lastIndexOf('/');
244
        if (slashIdx == -1) return EmptyEnumeration.EMPTY; // won't load from the default package
245
        final String pkg = name.substring(0, slashIdx + 1);
246
247
        // Don't bother optimizing this call by domains.
248
        // It is mostly used for resources for which isSpecialResource would be true anyway.
249
        Enumeration[] es = new Enumeration[parents.length + 1];
250
        for (int i = 0; i < parents.length; i++) {
251
            if (!shouldDelegateResource(pkg, parents[i])) {
252
                es[i] = EmptyEnumeration.EMPTY;
253
                continue;
254
            }
255
            if (parents[i] instanceof ProxyClassLoader) {
256
                es[i] = ((ProxyClassLoader)parents[i]).simpleFindResources(name);
257
            } else {
258
                es[i] = parents[i].getResources(name);
259
            }
260
        }
261
        es[parents.length] = simpleFindResources(name);
262
        // Should not be duplicates, assuming the parent loaders are properly distinct
263
        // from one another and do not overlap in JAR usage, which they ought not.
264
        // Anyway MetaInfServicesLookup, the most important client of this method, does
265
        // its own duplicate filtering already.
266
        return new SequenceEnumeration(new ArrayEnumeration(es));
267
    }
268
269
    /** This ClassLoader can't load anything itself. Subclasses
270
     * may override this method to do some resource loading themselves, this
271
     * implementation simply delegates to findResources method of the superclass
272
     * that should return empty Enumeration.
273
     *
274
     * @param  name the resource name
275
     * @return an Enumeration of URLs for the resources
276
     * @throws IOException if I/O errors occur
277
     */
278
    protected Enumeration simpleFindResources(String name) throws IOException {
279
        return super.findResources(name);
280
    }
281
282
    
283
    /**
284
     * Returns a Package that has been defined by this class loader or any
285
     * of its parents.
286
     *
287
     * @param  name the package name
288
     * @return the Package corresponding to the given name, or null if not found
289
     */
290
    protected Package getPackage(String name) {
291
        zombieCheck(name);
292
        
293
        int idx = name.lastIndexOf('.');
294
        if (idx == -1) return null;
295
        String spkg = name.substring(0, idx + 1).replace('.', '/');
296
        
297
	synchronized (packages) {
298
	    Package pkg = (Package)packages.get(name);
299
            if (pkg != null) return pkg;
300
            
301
            for (int i = 0; i < parents.length; i++) {
302
                ClassLoader par = parents[i];
303
                if (par instanceof ProxyClassLoader && shouldDelegateResource(spkg, par)) {
304
                    pkg = ((ProxyClassLoader)par).getPackage(name);
305
                    if(pkg != null) break;
306
                }
307
            }
308
            // do our own lookup
309
            if (pkg == null) pkg = super.getPackage(name);
310
            // cache results
311
            if (pkg != null) packages.put(name, pkg);
312
313
            return pkg;
314
	}
315
    }
316
317
    /** This is here just for locking serialization purposes.
318
     * Delegates to super.definePackage with proper locking.
319
     */
320
    protected Package definePackage(String name, String specTitle,
321
                String specVersion, String specVendor, String implTitle,
322
		String implVersion, String implVendor, URL sealBase )
323
		throws IllegalArgumentException {
324
	synchronized (packages) {
325
	    return super.definePackage (name, specTitle, specVersion, specVendor, implTitle,
326
			implVersion, implVendor, sealBase);
327
	}
328
    }
329
330
    /**
331
     * Returns all of the Packages defined by this class loader and its parents.
332
     *
333
     * @return the array of <code>Package</code> objects defined by this
334
     * <code>ClassLoader</code>
335
     */
336
    protected synchronized Package[] getPackages() {
337
        zombieCheck(null);
338
        Map all = new HashMap(); // Map<String,Package>
339
        addPackages(all, super.getPackages());
340
        for (int i = 0; i < parents.length; i++) {
341
            ClassLoader par = parents[i];
342
            if (par instanceof ProxyClassLoader) {
343
                // XXX should ideally use shouldDelegateResource here...
344
                addPackages(all, ((ProxyClassLoader)par).getPackages());
345
            }
346
        }
347
        synchronized (packages) {
348
            Iterator it = all.entrySet().iterator();
349
            while (it.hasNext()) {
350
                Map.Entry entry = (Map.Entry)it.next();
351
                Object name = entry.getKey();
352
                if (! packages.containsKey(name)) {
353
                    packages.put(name, entry.getValue());
354
                }
355
            }
356
        }
357
        return (Package[])all.values().toArray(new Package[all.size()]);
358
    }
359
    
360
    public Package getPackageAccessibly(String name) {
361
        return getPackage(name);
362
    }
363
    
364
    public Package[] getPackagesAccessibly() {
365
        return getPackages();
366
    }
367
368
    
369
    
370
    /** Coalesce parent classloaders into an optimized set.
371
     * This means that all parents of the specified classloaders
372
     * are also added recursively, removing duplicates along the way.
373
     * Search order should be preserved (parents before children, stable w.r.t. inputs).
374
     * @param loaders list of suggested parents (no nulls or duplicates permitted)
375
     * @return optimized list of parents (no nulls or duplicates)
376
     * @throws IllegalArgumentException if there are cycles
377
     */
378
    private ClassLoader[] coalesceParents(ClassLoader[] loaders) throws IllegalArgumentException {
379
        int likelySize = loaders.length * 3 + 1;
380
        Set resultingUnique = new HashSet(likelySize); // Set<ClassLoader>
381
        List resulting = new ArrayList(likelySize); // List<ClassLoader>
382
        for (int i = 0; i < loaders.length; i++) {
383
            addRec(resultingUnique, resulting, loaders[i]);
384
        }
385
        ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]);
386
        return ret;
387
    }
388
    
389
    /** Coalesce a new set of loaders into the existing ones.
390
     */
391
    private ClassLoader[] coalesceAppend(ClassLoader[] existing, ClassLoader[] appended) throws IllegalArgumentException {
392
        int likelySize = existing.length + 3;
393
        Set resultingUnique = new HashSet(likelySize);
394
        List existingL = Arrays.asList(existing);
395
        resultingUnique.addAll(existingL);
396
        if (resultingUnique.containsAll(Arrays.asList(appended))) {
397
            // No change required.
398
            return existing;
399
        }
400
        List resulting = new ArrayList(likelySize);
401
        resulting.addAll(existingL);
402
        int fromIdx = resulting.size();
403
        for (int i = 0; i < appended.length; i++) {
404
            addRec(resultingUnique, resulting, appended[i]);
405
        }
406
        ClassLoader[] ret = (ClassLoader[])resulting.toArray(new ClassLoader[resulting.size()]);
407
        return ret;
408
    }
409
    
410
    private void addRec(Set resultingUnique, List resulting, ClassLoader loader) throws IllegalArgumentException {
411
        if (loader == this) throw new IllegalArgumentException("cycle in parents"); // NOI18N
412
        if (resultingUnique.contains(loader)) return;
413
        if (loader instanceof ProxyClassLoader) {
414
            ClassLoader[] parents = ((ProxyClassLoader)loader).parents;
415
            for (int i = 0; i < parents.length; i++) {
416
                addRec(resultingUnique, resulting, parents[i]);
417
            }
418
        }
419
        resultingUnique.add(loader);
420
        resulting.add(loader);
421
    }
422
423
    /** A method that finds a class either in itself or in parents.
424
     * It uses dual signaling for class not found: it can either return null
425
     * or throw CNFE itself.
426
     * @param name class name, e.g. "org.netbeans.modules.foo.Clazz"
427
     * @param fileName resource name, e.g. "org/netbeans/modules/foo/Clazz.class"
428
     * @param pkg package component, e.g. "org/netbeans/modules/foo/"
429
     * @return a class or null if not found. It can also throw an exception.
430
     * @throws ClassNotFoundException in case it doesn't found a class
431
     * and a parent eglible for loading it thrown it already.
432
     */
433
    private final Class smartLoadClass(String name, String fileName, String pkg) throws ClassNotFoundException {
434
	// First, check if the class has already been loaded
435
	Class c = findLoadedClass(name);
436
	if(c != null) return c;
437
        
438
        final ClassLoader owner = isSpecialResource(pkg) ? null : (ClassLoader)domainsByPackage.get(pkg);
439
        if (owner == this) {
440
            return simpleFindClass(name,fileName);
441
        }
442
        if (owner != null) {
443
            // Note that shouldDelegateResource should already be true as we hit this pkg before.
444
            if (owner instanceof ProxyClassLoader) {
445
                return ((ProxyClassLoader)owner).fullFindClass(name,fileName);
446
            } else {
447
                return owner.loadClass(name); // May throw CNFE, will be propagated
448
            }
449
        }
450
        
451
        // Virgin package, do the parent scan 
452
        c = loadInOrder(name, fileName, pkg);
453
454
        if (c != null) {
455
            final ClassLoader owner2 = c.getClassLoader(); // who got it?
456
            domainsByPackage.put(pkg, owner2);
457
        }
458
        return c;
459
    }
460
    
461
    
462
    private final Class loadInOrder( String name, String fileName, String pkg ) throws ClassNotFoundException {
463
        ClassNotFoundException cached = null;
464
        for (int i = 0; i < parents.length; i++) {
465
	    ClassLoader par = parents[i];
466
            if (!shouldDelegateResource(pkg, par)) continue;
467
	    if (par instanceof ProxyClassLoader) {
468
		Class c = ((ProxyClassLoader)par).fullFindClass(name,fileName);
469
                if (c != null) return c;
470
	    } else {
471
		try {
472
		    return par.loadClass(name);
473
		} catch( ClassNotFoundException cnfe ) {
474
                    cached = cnfe;
475
                }
476
	    }
477
	}
478
479
        Class c = simpleFindClass(name,fileName); // Try it ourselves
480
        if (c != null) return c;
481
        if (cached != null) throw cached;
482
	return null;
483
    }
484
485
    private synchronized Class fullFindClass(String name, String fileName) {
486
	Class c = findLoadedClass(name);
487
	return (c == null) ? simpleFindClass(name, fileName) : c;
488
    }    
489
490
    private void addPackages(Map all, Package[] pkgs) {
491
        // Would be easier if Package.equals() was just defined sensibly...
492
        for (int i = 0; i < pkgs.length; i++) {
493
            all.put(pkgs[i].getName(), pkgs[i]);
494
        }
495
    }
496
    
497
    /** Test whether a given resource name is something that any JAR might
498
     * have, and for which the domain cache should be disabled.
499
     * The result must not change from one call to the next with the same argument.
500
     * By default the domain cache is disabled only for META-INF/* JAR information.
501
     * @param pkg the package component of the resource path ending with a slash,
502
     *        e.g. "org/netbeans/modules/foo/"
503
     * @return true if it is a special resource, false for normal domain-cached resource
504
     * @since org.netbeans.core/1 1.3
505
     */
506
    protected boolean isSpecialResource(String pkg) {
507
        if (pkg.startsWith("META-INF/")) return true; // NOI18N
508
        return false;
509
    }
510
    
511
    /** Test whether a given resource request (for a class or not) should be
512
     * searched for in the specified parent classloader or not.
513
     * The result must not change from one call to the next with the same arguments.
514
     * By default, always true. Subclasses may override to "mask" certain
515
     * packages from view, possibly according to the classloader chain.
516
     * @param pkg the package component of the resource path ending with a slash,
517
     *        e.g. "org/netbeans/modules/foo/"
518
     * @param parent a classloader which is a direct or indirect parent of this one
519
     * @return true if the request should be delegated to this parent; false to
520
     *         only search elsewhere (other parents, this loader's own namespace)
521
     * @since org.netbeans.core/1 1.3
522
     */
523
    protected boolean shouldDelegateResource(String pkg, ClassLoader parent) {
524
        return true;
525
    }
526
    
527
}
(-)nb_all/core/test/unit/src/org/netbeans/PatchByteCodeTest.java (+91 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans;
15
16
import junit.framework.AssertionFailedError;
17
import junit.textui.TestRunner;
18
import org.netbeans.junit.*;
19
import java.io.InputStream;
20
21
/** Test Plain top manager. Must be run externally.
22
 * @author Jesse Glick
23
 */
24
public class PatchByteCodeTest extends NbTestCase {
25
    
26
    public PatchByteCodeTest(String name) {
27
        super(name);
28
    }
29
    
30
    public static void main(String[] args) {
31
        TestRunner.run(new NbTestSuite(PatchByteCodeTest.class));
32
    }
33
    
34
    protected void setUp() throws Exception {
35
        super.setUp();
36
    }
37
38
    public void testBeanTreeViewLoad () throws Exception {
39
        checkPatching (
40
            "org.openide.explorer.view.BeanTreeView", 
41
            "BeanTreeView.data"
42
        );
43
    }
44
        
45
    private void checkPatching (
46
        String className, String resource
47
    ) throws Exception {
48
        InputStream is = getClass ().getResourceAsStream (resource);
49
        assertNotNull ("Resource has been found " + resource, is);
50
        
51
        byte[] arr = new byte[is.available ()];
52
        int l = is.read (arr);
53
        assertEquals ("Read exactly as much as expected", l, arr.length);
54
        
55
        String replaceName = PatchByteCodeTest.class.getName ();
56
        
57
        byte[] res = PatchByteCode.enhance(arr, replaceName.replace ('.', '/'));
58
        PatchClassLoader loader = new PatchClassLoader (className, res);
59
        
60
        Class c = loader.loadClass ("org.openide.explorer.view.BeanTreeView");
61
        
62
        assertEquals (
63
            "Superclass changed appropriatelly", 
64
            replaceName,
65
            c.getSuperclass().getName ()
66
        );
67
    }        
68
    
69
    
70
    private static final class PatchClassLoader extends ClassLoader {
71
        private String res;
72
        private byte[] arr;
73
        
74
        public PatchClassLoader (String res, byte[] arr) {
75
            super (PatchClassLoader.class.getClassLoader ());
76
            
77
            this.res = res;
78
            this.arr = arr;
79
        }
80
        
81
        protected synchronized Class loadClass(String name, boolean resolve) 
82
        throws ClassNotFoundException {
83
            if (res.equals (name)) {
84
                byte[] patch = PatchByteCode.patch(arr);
85
                return defineClass (name, patch, 0, patch.length);
86
            } else {
87
                return super.loadClass (name, resolve);
88
            }
89
        }
90
    }
91
}
(-)nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Postprocess.java (+1 lines)
 Lines 26-31    Link Here 
26
* though a little more customized for binary files.
26
* though a little more customized for binary files.
27
*
27
*
28
* @author Jaroslav Tulach
28
* @author Jaroslav Tulach
29
* @deprecated No longer used.
29
*/
30
*/
30
public class Postprocess extends Task {
31
public class Postprocess extends Task {
31
    /** file to post process */
32
    /** file to post process */
(-)nb_all/nbbuild/antsrc/org/netbeans/nbbuild/Preprocess.java (+1 lines)
 Lines 58-63    Link Here 
58
* more conservative changes. It should <em>not</em> be used as a general-purpose Java
58
* more conservative changes. It should <em>not</em> be used as a general-purpose Java
59
* preprocessor, we are not C++ programmers here!
59
* preprocessor, we are not C++ programmers here!
60
* @author Jaroslav Tulach, Jesse Glick
60
* @author Jaroslav Tulach, Jesse Glick
61
* @deprecated No longer used.
61
*/
62
*/
62
public class Preprocess extends MatchingTask {
63
public class Preprocess extends MatchingTask {
63
    /** the format of begining of substitution */
64
    /** the format of begining of substitution */
(-)nb_all/openide/.cvsignore (-1 lines)
 Lines 7-13    Link Here 
7
examplemodules
7
examplemodules
8
examplemodulereload
8
examplemodulereload
9
openide-13javac-workaround.jar
9
openide-13javac-workaround.jar
10
compatkit-work
11
standalone
10
standalone
12
nb-api-tutorial.zip
11
nb-api-tutorial.zip
13
openide.nbm
12
openide.nbm
(-)nb_all/openide/build.xml (-53 / +40 lines)
 Lines 27-34    Link Here 
27
27
28
  <property name="nbm_alias" value="nb_ide"/>
28
  <property name="nbm_alias" value="nb_ide"/>
29
29
30
  <taskdef name="preprocess" classname="org.netbeans.nbbuild.Preprocess" classpath="../nbbuild/nbantext.jar"/>
30
  <taskdef name="patchsuperclass" classname="org.netbeans.nbbuild.NbPatchSuperClass" classpath="../nbbuild/nbantext.jar"/>
31
  <taskdef name="postprocess" classname="org.netbeans.nbbuild.Postprocess" classpath="../nbbuild/nbantext.jar"/>
32
  <taskdef name="locjar" classname="org.netbeans.nbbuild.LocalizedJar" classpath="../nbbuild/nbantext.jar"/>
31
  <taskdef name="locjar" classname="org.netbeans.nbbuild.LocalizedJar" classpath="../nbbuild/nbantext.jar"/>
33
  <taskdef name="checklinks" classname="org.netbeans.nbbuild.CheckLinks" classpath="../nbbuild/nbantext.jar:${binroot}/core/release/lib/ext/regexp.jar"/>
32
  <taskdef name="checklinks" classname="org.netbeans.nbbuild.CheckLinks" classpath="../nbbuild/nbantext.jar:${binroot}/core/release/lib/ext/regexp.jar"/>
34
  <taskdef name="makenbm" classname="org.netbeans.nbbuild.MakeNBM" classpath="../nbbuild/nbantext.jar"/>
33
  <taskdef name="makenbm" classname="org.netbeans.nbbuild.MakeNBM" classpath="../nbbuild/nbantext.jar"/>
 Lines 84-135    Link Here 
84
-->      
83
-->      
85
    </javac>
84
    </javac>
86
  </target>
85
  </target>
87
    
88
  <target name="compile" depends="init-14,13javac-workaround,compile-regular,compile-preprocessed,compile-14"
89
          description="Compile all source files but do not package them."/>
90
  
86
  
91
  <target name="compile-preprocessed" depends="preprocess" >
87
  <target name="compile-compat" depends="compile-regular">
92
    <javac srcdir="compatkit-work" destdir="compatkit-work" deprecation="${build.compiler.deprecation}" debug="${build.compiler.debug}">
88
    <javac srcdir="compat/src" destdir="compat/src" deprecation="${build.compiler.deprecation}" debug="${build.compiler.debug}">
93
      <bootclasspath>
89
      <bootclasspath>
94
        <!-- XXX not nice to use undocumented property here: -->
90
        <!-- XXX not nice to use undocumented property here: -->
95
        <pathelement path="${sun.boot.class.path}"/>
91
        <pathelement path="${sun.boot.class.path}"/>
96
        <pathelement location="openide-13javac-workaround.jar"/>
92
        <pathelement location="openide-13javac-workaround.jar"/>
97
      </bootclasspath>
93
      </bootclasspath>
98
      <classpath>
94
      <classpath>
95
        <!-- could add regexp.jar, xml-apis.jar as needed -->
99
        <pathelement location="src"/>
96
        <pathelement location="src"/>
100
        <pathelement location="${binroot}/core/release/lib/ext/regexp.jar"/>
101
        <pathelement location="${binroot}/core/release/lib/ext/xml-apis.jar"/>
102
      </classpath>
97
      </classpath>
103
    </javac>
98
    </javac>
104
    <postprocess file="compatkit-work/org/openide/util/actions/SystemAction.class"
99
  </target>
105
                 old="g3t1c0n" new="getIcon"
100
  
106
                 min="0" max="1"/>
101
    
107
    <postprocess file="compatkit-work/org/openide/filesystems/AbstractFileSystem.class"
102
  <target name="compile" depends="init-14,13javac-workaround,compile-regular,compile-14,patchsuper"
108
                 old="r3fr3shR00t" new="refreshRoot"
103
          description="Compile all source files but do not package them."/>
109
                 min="0" max="1"/>
104
  
110
  </target>
105
111
106
  <target name="patchsuper" depends="compile-compat" >
112
  <target name="preprocess">
107
    <ant antfile="../core/build.xml" dir="../core" target="boot" />
113
    <mkdir dir="compatkit-work"/>
108
  
114
    <preprocess srcdir="src" destdir="compatkit-work">
109
    <patchsuperclass basedir="src" patchlibrary="../core/netbeans/lib/ext/boot.jar" >
115
      <switch name="compat" on="true"/>
110
	    <patch class="org/openide/nodes/AbstractNode" super="org/openide/nodes/AbstractNodePatch" /> 
116
      <!-- For efficiency and clarity and safety, we explicitly -->
111
	    <patch class="org/openide/explorer/view/BeanTreeView" super="org/openide/explorer/view/BeanTreeViewPatch" /> 
117
      <!-- list all files known to need preprocessing. -->
112
	    <patch class="org/openide/loaders/MultiDataObject" super="org/openide/loaders/MultiDataObjectPatch" /> 
118
      <include name="org/openide/loaders/DataLoaderPool.java"/>
113
	    <patch class="org/openide/compiler/ExternalCompiler" super="org/openide/compiler/ExternalCompilerPatch" /> 
119
      <include name="org/openide/loaders/MultiDataObject.java"/>
114
	    <patch class="org/openide/util/actions/SystemAction" super="org/openide/util/actions/SystemActionPatch" /> 
120
      <include name="org/openide/nodes/AbstractNode.java"/>
115
	    <patch class="org/openide/filesystems/Repository" super="org/openide/filesystems/RepositoryPatch" /> 
121
      <include name="org/openide/compiler/CompilerGroup.java"/>
116
	    <patch class="org/openide/filesystems/AbstractFileSystem" super="org/openide/filesystems/AbstractFileSystemPatch" /> 
122
      <include name="org/openide/compiler/ExternalCompiler.java"/>
117
	    <patch class="org/openide/filesystems/LocalFileSystem" super="org/openide/filesystems/LocalJarFSPatch" /> 
123
      <include name="org/openide/util/actions/SystemAction.java"/>
118
	    <patch class="org/openide/filesystems/JarFileSystem" super="org/openide/filesystems/LocalJarFSPatch" /> 
124
      <include name="org/openide/filesystems/LocalFileSystem.java"/>
119
            <patch class="org/openide/awt/Toolbar" super="org/openide/awt/ToolbarPatch" />
125
      <include name="org/openide/filesystems/JarFileSystem.java"/>
120
            
126
      <include name="org/openide/filesystems/AbstractFileSystem.java"/>
121
            <!-- no super change, just be public -->
127
      <include name="org/openide/filesystems/Repository.java"/>
122
128
      <include name="org/openide/explorer/propertysheet/PropertyDialogManager.java"/>
123
	    <patch class="org/openide/explorer/propertysheet/SetDefaultValueAction"  /> 
129
      <include name="org/openide/explorer/propertysheet/SetDefaultValueAction.java"/>
124
	    <patch class="org/openide/loaders/DataLoaderPool$$FolderLoader"  /> 
130
      <include name="org/openide/awt/Toolbar.java"/>
125
	    <patch class="org/openide/loaders/DataLoaderPool$$InstanceLoader"  /> 
131
      <include name="org/openide/explorer/view/BeanTreeView.java"/>
126
	    <patch class="org/openide/loaders/DataLoaderPool$$DefaultLoader"  /> 
132
    </preprocess>
127
	    <patch class="org/openide/loaders/DataLoaderPool$$ShadowLoader"  /> 
128
129
    </patchsuperclass>
133
  </target>
130
  </target>
134
131
135
  <target name="13javac-workaround">
132
  <target name="13javac-workaround">
 Lines 188-194    Link Here 
188
    <filter token="BUILD_NUMBER_SUBST" value="${buildnumber}"/>
185
    <filter token="BUILD_NUMBER_SUBST" value="${buildnumber}"/>
189
  </target>
186
  </target>
190
  
187
  
191
  <target name="jars" depends="compile,13javac-workaround,vers-prep" description="Create JAR files.">
188
  <target name="jars" depends="compile,13javac-workaround,vers-prep,patchsuper" description="Create JAR files.">
192
    <mkdir dir="netbeans/lib"/>
189
    <mkdir dir="netbeans/lib"/>
193
    <filter token="Class-Path" value="Class-Path"/>
190
    <filter token="Class-Path" value="Class-Path"/>
194
    <filter token="OpenIDE-Module" value="OpenIDE-Module"/>
191
    <filter token="OpenIDE-Module" value="OpenIDE-Module"/>
 Lines 218-230    Link Here 
218
    
215
    
219
    <!-- Create binary compatibility kit. NOBODY should compile against it unless they -->
216
    <!-- Create binary compatibility kit. NOBODY should compile against it unless they -->
220
    <!-- are trying to make their code obsolete! -->
217
    <!-- are trying to make their code obsolete! -->
221
    <mkdir dir="netbeans/lib/patches"/>
218
    <mkdir dir="netbeans/lib/ext"/>
222
    <!-- Use the same manifest to ensure that packages are defined correctly. -->
219
    <!-- Use the same manifest to ensure that packages are defined correctly. -->
223
    <filter token="Class-Path" value="X-Commented-Out-Class-Path"/>
220
    <filter token="Class-Path" value="X-Commented-Out-Class-Path"/>
224
    <filter token="OpenIDE-Module" value="X-Commented-Out-OpenIDE-Module"/>
221
    <filter token="OpenIDE-Module" value="X-Commented-Out-OpenIDE-Module"/>
225
    <copy file="manifest.mf" tofile="manifest-compat-subst.mf" filtering="on"/>
222
    <copy file="manifest.mf" tofile="manifest-compat-subst.mf" filtering="on"/>
226
    <jar jarfile="netbeans/lib/patches/openide-compat.jar"
223
    
227
         basedir="compatkit-work"
224
    <jar jarfile="netbeans/lib/openide-compat.jar"
225
         basedir="compat/src"
228
         manifest="manifest-compat-subst.mf"
226
         manifest="manifest-compat-subst.mf"
229
	 excludesfile="../nbbuild/standard-jar-excludes.txt"
227
	 excludesfile="../nbbuild/standard-jar-excludes.txt"
230
	 compress="false"/>
228
	 compress="false"/>
 Lines 301-316    Link Here 
301
    <!-- It also needs regexp.jar: -->
299
    <!-- It also needs regexp.jar: -->
302
    <copy file="${binroot}/core/release/lib/ext/regexp.jar" tofile="standalone/regexp.jar"/>
300
    <copy file="${binroot}/core/release/lib/ext/regexp.jar" tofile="standalone/regexp.jar"/>
303
    
301
    
304
    <!-- openide-compat.jar not really needed for standalone users:
305
    <mkdir dir="netbeans/lib/patches"/>
306
    <filter token="Class-Path" value="X-Commented-Out-Class-Path"/>
307
    <copy file="manifest.mf" tofile="manifest-compat-subst.mf" filtering="on"/>
308
    <jar jarfile="netbeans/lib/patches/openide-compat.jar"
309
         basedir="compatkit-work"
310
         manifest="manifest-compat-subst.mf"
311
	 excludesfile="../nbbuild/standard-jar-excludes.txt"
312
	 compress="false"/>
313
    -->
314
  </target>
302
  </target>
315
303
316
  <target name="netbeans" depends="jars" description="Build everything needed for inclusion in the IDE.">
304
  <target name="netbeans" depends="jars" description="Build everything needed for inclusion in the IDE.">
 Lines 875-881    Link Here 
875
    <delete file="OpenAPIs.tar.bz2"/>
863
    <delete file="OpenAPIs.tar.bz2"/>
876
    <delete file="nb-api-tutorial.zip"/>
864
    <delete file="nb-api-tutorial.zip"/>
877
    <delete dir="examplemodules"/>
865
    <delete dir="examplemodules"/>
878
    <delete dir="compatkit-work"/>
879
    <delete dir="standalone"/>
866
    <delete dir="standalone"/>
880
    <delete dir="Info"/>
867
    <delete dir="Info"/>
881
    <delete file="openide.nbm"/>
868
    <delete file="openide.nbm"/>
(-)nb_all/openide/api/doc/changes/apichanges.xml (+47 lines)
 Lines 130-135    Link Here 
130
    </change>
130
    </change>
131
131
132
    <change>
132
    <change>
133
      <api name="compiler"/>
134
      <summary>Listener methods are again overridable</summary>
135
      <date day="19" month="7" year="2002"/>
136
      <author login="jtulach"/>
137
      <compatibility modification="yes">
138
        This change reverts a prior binary-compatible, source-incompatible change,
139
        since the binary compatibility kit is no longer in use.
140
      </compatibility>
141
      <description>
142
        <code>addCompilerListener</code> and <code>removeCompilerListener</code>
143
        made not-final.
144
      </description>
145
      <class package="org.openide.compiler" name="CompilerGroup"/>
146
    </change>
147
148
    <change>
133
        <api name="filesystems"/>
149
        <api name="filesystems"/>
134
        <summary>Repository is not final</summary>
150
        <summary>Repository is not final</summary>
135
        <version major="3" minor="3"/>
151
        <version major="3" minor="3"/>
 Lines 161-166    Link Here 
161
        <class package="org.openide" name="TopManager"/>
177
        <class package="org.openide" name="TopManager"/>
162
    </change>
178
    </change>
163
    
179
    
180
  <changes>
181
    <change>
182
      <api name="util"/>
183
      <summary>New (even obsolete) fields in org.openide.awt.Toolbar</summary>
184
      <version major="3" minor="3"/>
185
      <date day="19" month="7" year="2002"/>
186
      <author login="jtulach" />
187
      <compatibility addition="yes"/>
188
      <description>
189
        Some fields appeared and/or were unfinalized in Toolbar and its innerclasses.
190
        These were there in old 3.0 version, but were remove later when preprocess
191
        task was introduced. The task is now replaced by patchsuperclass mechanism, 
192
        which is more clean, but works just for methods, not fields. Thus the fields
193
        in Toolbar were made changed to their previous state.
194
      </description>
195
      <class package="org.openide.awt" name="Toolbar"/>
196
    </change>
197
164
    <change>
198
    <change>
165
        <api name="actions"/>
199
        <api name="actions"/>
166
        <summary>Enhanced the <code>org.openide.awt.MenuBar</code>
200
        <summary>Enhanced the <code>org.openide.awt.MenuBar</code>
 Lines 3925-3930    Link Here 
3925
3959
3926
<hr/><h1><a name="compatkit">Binary Compatibility Kit</a></h1>
3960
<hr/><h1><a name="compatkit">Binary Compatibility Kit</a></h1>
3927
3961
3962
      <h2>Binary Compatibility up to NetBeans 3.4</h2>
3963
3928
<p>In most cases, when it is desirable from an architectural standpoint
3964
<p>In most cases, when it is desirable from an architectural standpoint
3929
to change an API in an incompatible way, the standard Java mechanism
3965
to change an API in an incompatible way, the standard Java mechanism
3930
of <code>@deprecated</code> tags in Javadoc suffices as a compromise:
3966
of <code>@deprecated</code> tags in Javadoc suffices as a compromise:
 Lines 3987-3992    Link Here 
3987
into an IDE installation that has had its
4023
into an IDE installation that has had its
3988
<samp>lib/patches/openide-compat.jar</samp> removed, to ensure that
4024
<samp>lib/patches/openide-compat.jar</samp> removed, to ensure that
3989
they are not depending on the deprecated APIs.</p>
4025
they are not depending on the deprecated APIs.</p>
4026
4027
      <h2>Binary Compatibility after NetBeans 3.4</h2>
4028
4029
      <p>
4030
        In releases after 3.4 (expected 4.0), the system used is slightly
4031
        different, though the effect is similar.
4032
        <samp>lib/openide-compat.jar</samp> is now the compatibility JAR
4033
        location. It contains fake superclasses for some classes; the fake
4034
        superclasses will be inserted into the inheritance tree at runtime and
4035
        include methods and interfaces which are not available in source code.
4036
      </p>
3990
4037
3991
    </body>
4038
    </body>
3992
  </htmlcontents>
4039
  </htmlcontents>
(-)nb_all/openide/compat/src/org/openide/awt/ToolbarPatch.java (+63 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.awt;
15
16
import java.awt.event.MouseEvent;
17
import javax.swing.JToolBar;
18
import javax.swing.event.MouseInputListener;
19
20
/** A fake class that holds methods that for compatibility reasons
21
 * should be public even in the definition are not.
22
 *
23
 * @author Jaroslav Tulach
24
 */
25
public abstract class ToolbarPatch extends JToolBar 
26
implements MouseInputListener {
27
    /** Constructor that delegates.
28
     */
29
    public ToolbarPatch() {
30
    }
31
    
32
    /** listener to delegate to */
33
    abstract MouseInputListener mouseDelegate ();
34
    
35
    public void mouseClicked(MouseEvent e) {
36
        mouseDelegate ().mouseClicked (e);
37
    }
38
    
39
    public void mouseDragged(MouseEvent e) {
40
        mouseDelegate ().mouseDragged (e);
41
    }
42
    
43
    public void mouseEntered(MouseEvent e) {
44
        mouseDelegate ().mouseEntered (e);
45
    }
46
    
47
    public void mouseExited(MouseEvent e) {
48
        mouseDelegate ().mouseExited (e);
49
    }
50
    
51
    public void mouseMoved(MouseEvent e) {
52
        mouseDelegate ().mouseMoved (e);
53
    }
54
    
55
    public void mousePressed(MouseEvent e) {
56
        mouseDelegate ().mousePressed (e);
57
    }
58
    
59
    public void mouseReleased(MouseEvent e) {
60
        mouseDelegate ().mouseReleased (e);
61
    }
62
    
63
}
(-)nb_all/openide/compat/src/org/openide/compiler/ExternalCompilerPatch.java (+28 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.compiler;
15
16
/** A fake class that holds methods that for compatibility reasons
17
 * should be public even in the definition are not.
18
 *
19
 * @author Jaroslav Tulach
20
 */
21
public abstract class ExternalCompilerPatch extends Compiler {
22
    /** Constructor that delegates.
23
     */
24
    public ExternalCompilerPatch() {
25
    }
26
27
    public abstract boolean isUpToDate();
28
}
(-)nb_all/openide/compat/src/org/openide/explorer/view/BeanTreeViewPatch.java (+36 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.explorer.view;
15
16
import java.beans.PropertyVetoException;
17
18
import org.openide.explorer.ExplorerManager;
19
import org.openide.nodes.Node;
20
21
/** A fake class that makes some methods public even they were not.
22
 *
23
 * @author Jaroslav Tulach
24
 */
25
public abstract class BeanTreeViewPatch extends TreeView {
26
    /** Default constructor.
27
     */
28
    public BeanTreeViewPatch() {
29
    }
30
    
31
    /** Defines the method to be public, so it will be public 
32
     * even if AbstractNode makes it protected.
33
     */
34
    public abstract void selectionChanged(Node[] nodes, ExplorerManager em) throws PropertyVetoException;
35
}
36
(-)nb_all/openide/compat/src/org/openide/filesystems/AbstractFileSystemPatch.java (+28 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.filesystems;
15
16
/** A fake class that holds methods that for compatibility reasons
17
 * should be public even in the definition are not.
18
 *
19
 * @author Jaroslav Tulach
20
 */
21
public abstract class AbstractFileSystemPatch extends FileSystem {
22
    // implemented in AbstractFileSystem
23
    abstract AbstractFileObject refreshRootImpl ();
24
    
25
    protected final AbstractFileObject refreshRoot () {
26
        return refreshRootImpl ();
27
    }
28
}
(-)nb_all/openide/compat/src/org/openide/filesystems/LocalJarFSPatch.java (+50 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.filesystems;
15
16
import java.io.IOException;
17
import java.io.InputStream;
18
import java.io.OutputStream;
19
20
/** A fake class that holds methods that for compatibility reasons
21
 * should be public even in the definition are not.
22
 *
23
 * @author Jaroslav Tulach
24
 */
25
public abstract class LocalJarFSPatch extends AbstractFileSystem 
26
implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change, AbstractFileSystem.Attr {
27
    public abstract java.util.Enumeration attributes(String name);
28
    public abstract void deleteAttributes(String name);
29
    public abstract Object readAttribute(String name, String attrName);
30
    public abstract void renameAttributes(String oldName, String newName);
31
    public abstract void writeAttribute(String name, String attrName, Object value) throws IOException;
32
    
33
    public abstract String[] children(String f);
34
35
    public abstract void createData(String name) throws IOException;
36
    public abstract void createFolder(String name) throws java.io.IOException;
37
    public abstract void delete(String name) throws IOException;
38
    public abstract boolean folder(String name);
39
40
    public abstract InputStream inputStream(String name) throws java.io.FileNotFoundException;
41
    public abstract java.util.Date lastModified(String name);
42
    public abstract void lock(String name) throws IOException;
43
    public abstract void markUnimportant(String name);
44
    public abstract String mimeType(String name);
45
    public abstract OutputStream outputStream(String name) throws java.io.IOException;
46
    public abstract boolean readOnly(String name);
47
    public abstract void rename(String oldName, String newName) throws IOException;
48
    public abstract long size(String name);
49
    public abstract void unlock(String name);
50
}
(-)nb_all/openide/compat/src/org/openide/filesystems/RepositoryPatch.java (+26 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.filesystems;
15
16
/** A fake class that holds methods that for compatibility reasons
17
 * should be public even in the definition are not.
18
 *
19
 * <P>
20
 * This class should implement Node.Cookie, so it does.
21
 *
22
 * @author Jaroslav Tulach
23
 */
24
public abstract class RepositoryPatch extends Object 
25
implements org.openide.nodes.Node.Cookie {
26
}
(-)nb_all/openide/compat/src/org/openide/loaders/MultiDataObjectPatch.java (+32 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.loaders;
15
16
/** A fake class that holds methods that for compatibility reasons
17
 * should be public even in the definition are not.
18
 *
19
 * @author Jaroslav Tulach
20
 */
21
public abstract class MultiDataObjectPatch extends DataObject {
22
    /** Constructor that delegates.
23
     */
24
    public MultiDataObjectPatch(
25
        org.openide.filesystems.FileObject fo, MultiFileLoader loader
26
    ) throws DataObjectExistsException {
27
        super (fo, loader);
28
    }
29
    
30
    public abstract org.openide.nodes.CookieSet getCookieSet ();
31
    public abstract void setCookieSet (org.openide.nodes.CookieSet s);
32
}
(-)nb_all/openide/compat/src/org/openide/nodes/AbstractNodePatch.java (+32 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.nodes;
15
16
/** A fake class that holds methods that were available in AbstractNode
17
 * and should not be anymore.
18
 *
19
 * @author Jaroslav Tulach
20
 */
21
public abstract class AbstractNodePatch extends Node {
22
    /** 
23
     */
24
    public AbstractNodePatch(Children ch) {
25
        super (ch);
26
    }
27
    
28
    /** Defines the method to be public, so it will be public 
29
     * even if AbstractNode makes it protected.
30
     */
31
    public abstract CookieSet getCookieSet ();
32
}
(-)nb_all/openide/compat/src/org/openide/util/actions/SystemActionPatch.java (+50 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.util.actions;
15
16
import javax.swing.Icon;
17
import javax.swing.ImageIcon;
18
import org.openide.util.Utilities;
19
20
/** A fake class that holds methods that for compatibility reasons
21
 * should be public even in the definition are not.
22
 *
23
 * @author Jaroslav Tulach
24
 */
25
public abstract class SystemActionPatch extends org.openide.util.SharedClassObject {
26
    /** Constructor that delegates.
27
     */
28
    public SystemActionPatch() {
29
    }
30
31
    // Will be define by SystemAction
32
    public abstract void setIcon (Icon icon);
33
    public abstract Icon getIcon (boolean flag);
34
35
    // used to be define
36
    public final void setIcon (ImageIcon icon) {
37
        setIcon ((Icon) icon);
38
    }
39
    public final ImageIcon getIcon () {
40
        Icon i = getIcon (false);
41
        if (i instanceof ImageIcon) {
42
            return ((ImageIcon) i);
43
        } else {
44
            // [PENDING] could try to translate Icon -> ImageIcon somehow,
45
            // but I have no idea how to do this (paint it, take Component
46
            // graphics, load the image data somehow??)
47
            return new ImageIcon(Utilities.loadImage("org/openide/resources/actions/empty.gif")); // NOI18N
48
        }
49
    }
50
}
(-)nb_all/openide/src/org/openide/awt/Toolbar.java (-65 / +10 lines)
 Lines 39-56    Link Here 
39
 *
39
 *
40
 * @author  David Peroutka, Libor Kramolis
40
 * @author  David Peroutka, Libor Kramolis
41
 */
41
 */
42
public class Toolbar extends JToolBar
42
public class Toolbar extends JToolBar {
43
/*nbif compat
43
    /** Basic toolbar height. Do not change. */
44
implements MouseInputListener
44
    public static int BASIC_HEIGHT = 34;
45
/*nbend*/
46
{
47
    /** Basic toolbar height. */
48
    public static
49
    /*nbif compat
50
    nbelse*/
51
    final
52
    /*nbend*/
53
    int BASIC_HEIGHT = 34;
54
45
55
    /** 5 pixels is tolerance of toolbar height so toolbar can be high (BASIC_HEIGHT + HEIGHT_TOLERANCE)
46
    /** 5 pixels is tolerance of toolbar height so toolbar can be high (BASIC_HEIGHT + HEIGHT_TOLERANCE)
56
        but it will be set to BASIC_HEIGHT high. */
47
        but it will be set to BASIC_HEIGHT high. */
 Lines 295-331    Link Here 
295
286
296
    } // end of inner class ToolbarMouseListener
287
    } // end of inner class ToolbarMouseListener
297
288
298
    /*nbif compat
289
    synchronized final MouseInputListener mouseDelegate () {
299
    public void mouseClicked (MouseEvent e) {
300
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
290
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
301
        mouseListener.mouseClicked (e);
291
        return mouseListener;
302
    }
292
    }
303
    public void mouseEntered (MouseEvent e) {
293
    
304
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
305
        mouseListener.mouseEntered (e);
306
    }
307
    public void mouseExited (MouseEvent e) {
308
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
309
        mouseListener.mouseExited (e);
310
    }
311
    public void mousePressed (MouseEvent e) {
312
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
313
        mouseListener.mousePressed (e);
314
    }
315
    public void mouseReleased (MouseEvent e) {
316
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
317
        mouseListener.mouseReleased (e);
318
    }
319
    public void mouseDragged (MouseEvent e) {
320
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
321
        mouseListener.mouseDragged (e);
322
    }
323
    public void mouseMoved (MouseEvent e) {
324
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
325
        mouseListener.mouseMoved (e);
326
    }
327
    /*nbend*/
328
329
    /**
294
    /**
330
     * This class can be used to produce a <code>Toolbar</code> instance from
295
     * This class can be used to produce a <code>Toolbar</code> instance from
331
     * the given <code>DataFolder</code>.
296
     * the given <code>DataFolder</code>.
 Lines 551-583    Link Here 
551
        public static final int DND_LINE = 3;
516
        public static final int DND_LINE = 3;
552
517
553
        /** Name of toolbar where event occured. */
518
        /** Name of toolbar where event occured. */
554
        /*nbif compat
519
        public String name;
555
        public
556
        nbelse*/
557
        private
558
        /*nbend*/
559
        String name;
560
        /** distance of horizontal dragging */
520
        /** distance of horizontal dragging */
561
        /*nbif compat
521
        public int dx;
562
        public
563
        nbelse*/
564
        private
565
        /*nbend*/
566
        int dx;
567
        /** distance of vertical dragging */
522
        /** distance of vertical dragging */
568
        /*nbif compat
523
        public int dy;
569
        public
570
        nbelse*/
571
        private
572
        /*nbend*/
573
        int dy;
574
        /** Type of event. */
524
        /** Type of event. */
575
        /*nbif compat
525
        public int type;
576
        public
577
        nbelse*/
578
        private
579
        /*nbend*/
580
        int type;
581
526
582
        static final long serialVersionUID =4389530973297716699L;
527
        static final long serialVersionUID =4389530973297716699L;
583
        public DnDEvent (Toolbar toolbar, String name, int dx, int dy, int type) {
528
        public DnDEvent (Toolbar toolbar, String name, int dx, int dy, int type) {
(-)nb_all/openide/src/org/openide/compiler/CompilerGroup.java (-12 / +2 lines)
 Lines 64-75    Link Here 
64
    /** Add a listener.
64
    /** Add a listener.
65
    * @param l the listener to add
65
    * @param l the listener to add
66
    */  
66
    */  
67
    public
67
    public synchronized void addCompilerListener (CompilerListener l) {
68
    /*nbif compat
69
    nbelse*/
70
    final
71
    /*nbend*/
72
    synchronized void addCompilerListener (CompilerListener l) {
73
        if (listeners == null ) {
68
        if (listeners == null ) {
74
            listeners = new javax.swing.event.EventListenerList();
69
            listeners = new javax.swing.event.EventListenerList();
75
        }
70
        }
 Lines 79-90    Link Here 
79
    /** Remove a listener.
74
    /** Remove a listener.
80
    * @param l the listener to remove
75
    * @param l the listener to remove
81
    */
76
    */
82
    public
77
    public synchronized void removeCompilerListener (CompilerListener l) {
83
    /*nbif compat
84
    nbelse*/
85
    final
86
    /*nbend*/
87
    synchronized void removeCompilerListener (CompilerListener l) {
88
        if (listeners == null) return;
78
        if (listeners == null) return;
89
        listeners.remove (org.openide.compiler.CompilerListener.class, l);
79
        listeners.remove (org.openide.compiler.CompilerListener.class, l);
90
    }
80
    }
(-)nb_all/openide/src/org/openide/compiler/ExternalCompiler.java (-6 / +1 lines)
 Lines 429-440    Link Here 
429
        }
429
        }
430
    }
430
    }
431
431
432
    /*nbif compat
432
    protected boolean isUpToDate() {
433
    public
434
    nbelse*/
435
    protected
436
    /*nbend*/
437
    boolean isUpToDate() {
438
        if (type == BUILD) {
433
        if (type == BUILD) {
439
            return false;
434
            return false;
440
        } else {
435
        } else {
(-)nb_all/openide/src/org/openide/explorer/propertysheet/SetDefaultValueAction.java (-3 lines)
 Lines 21-29    Link Here 
21
*
21
*
22
* @author Jan Jancura, Petr Hamernik, Ian Formanek
22
* @author Jan Jancura, Petr Hamernik, Ian Formanek
23
*/
23
*/
24
/*nbif compat
25
public
26
/*nbend*/
27
final class SetDefaultValueAction extends CallbackSystemAction {
24
final class SetDefaultValueAction extends CallbackSystemAction {
28
    /** generated Serialized Version UID */
25
    /** generated Serialized Version UID */
29
    static final long serialVersionUID = -1285705164427519181L;
26
    static final long serialVersionUID = -1285705164427519181L;
(-)nb_all/openide/src/org/openide/explorer/view/BeanTreeView.java (-7 / +1 lines)
 Lines 70-82    Link Here 
70
    * @param nodes nodes
70
    * @param nodes nodes
71
    * @param em explorer manager
71
    * @param em explorer manager
72
    */
72
    */
73
    /*nbif compat
73
    protected void selectionChanged(Node[] nodes, ExplorerManager em) throws PropertyVetoException {
74
    public
75
    nbelse*/
76
    protected
77
    /*nbend*/
78
    void selectionChanged(Node[] nodes, ExplorerManager em) throws PropertyVetoException {
79
80
        if (nodes.length > 0) {
74
        if (nodes.length > 0) {
81
            Node context = nodes[0].getParentNode ();
75
            Node context = nodes[0].getParentNode ();
82
            for (int i = 1; i < nodes.length; i++) {
76
            for (int i = 1; i < nodes.length; i++) {
(-)nb_all/openide/src/org/openide/filesystems/AbstractFileSystem.java (-6 lines)
 Lines 259-270    Link Here 
259
        return refreshRootImpl ();
259
        return refreshRootImpl ();
260
    }
260
    }
261
261
262
    /*nbif compat
263
    protected final AbstractFileObject r3fr3shR00t () {
264
        return refreshRootImpl ();
265
    }
266
    /*nbend*/
267
268
    /** Allows subclasses to fire that a change occured in a
262
    /** Allows subclasses to fire that a change occured in a
269
    * file or folder. The change can be "expected" when it is 
263
    * file or folder. The change can be "expected" when it is 
270
    * a result of an user action and the user knows that such
264
    * a result of an user action and the user knows that such
(-)nb_all/openide/src/org/openide/filesystems/JarFileSystem.java (-129 / +25 lines)
 Lines 37-47    Link Here 
37
* them, or (better) use delegation.
37
* them, or (better) use delegation.
38
* @author Jan Jancura, Jaroslav Tulach, Petr Hamernik, Radek Matous
38
* @author Jan Jancura, Jaroslav Tulach, Petr Hamernik, Radek Matous
39
*/
39
*/
40
public class JarFileSystem extends AbstractFileSystem
40
public class JarFileSystem extends AbstractFileSystem {
41
    /*nbif compat
42
    implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change, AbstractFileSystem.Attr
43
    /*nbend*/
44
{
45
    /** generated Serialized Version UID */
41
    /** generated Serialized Version UID */
46
    static final long serialVersionUID = -98124752801761145L;
42
    static final long serialVersionUID = -98124752801761145L;
47
43
 Lines 252-263    Link Here 
252
    // List
248
    // List
253
    //
249
    //
254
250
255
    /*nbif compat
251
    protected String[] children (String name) {
256
    public
257
    nbelse*/
258
    protected
259
    /*nbend*/
260
    String[] children (String name) {
261
        EntryCache tmpRootCache = getCacheOfRoot ();
252
        EntryCache tmpRootCache = getCacheOfRoot ();
262
        if (tmpRootCache == null) {
253
        if (tmpRootCache == null) {
263
            if ((tmpRootCache = parse (false)) == null) 
254
            if ((tmpRootCache = parse (false)) == null) 
 Lines 273-311    Link Here 
273
    // Change
264
    // Change
274
    //
265
    //
275
266
276
    /*nbif compat
267
    protected void createFolder (String name) throws java.io.IOException {
277
    public
278
    nbelse*/
279
    protected
280
    /*nbend*/
281
    void createFolder (String name) throws java.io.IOException {
282
        throw new IOException ();
268
        throw new IOException ();
283
    }
269
    }
284
270
285
    /*nbif compat
271
    protected void createData (String name) throws IOException {
286
    public
287
    nbelse*/
288
    protected
289
    /*nbend*/
290
    void createData (String name) throws IOException {
291
        throw new IOException ();
272
        throw new IOException ();
292
    }
273
    }
293
274
294
    /*nbif compat
275
    protected void rename(String oldName, String newName) throws IOException {
295
    public
296
    nbelse*/
297
    protected
298
    /*nbend*/
299
    void rename(String oldName, String newName) throws IOException {
300
        throw new IOException ();
276
        throw new IOException ();
301
    }
277
    }
302
278
303
    /*nbif compat
279
    protected void delete (String name) throws IOException {
304
    public
305
    nbelse*/
306
    protected
307
    /*nbend*/
308
    void delete (String name) throws IOException {
309
        throw new IOException ();
280
        throw new IOException ();
310
    }
281
    }
311
282
 Lines 313-335    Link Here 
313
    // Info
284
    // Info
314
    //
285
    //
315
286
316
    /*nbif compat
287
    protected java.util.Date lastModified(String name) {
317
    public
318
    nbelse*/
319
    protected
320
    /*nbend*/
321
    java.util.Date lastModified(String name) {
322
        /** JarEntry.getTime returns wrong value: already reported in bugtraq 4319781
288
        /** JarEntry.getTime returns wrong value: already reported in bugtraq 4319781
323
         *  Fixed in jdk1.4  */
289
         *  Fixed in jdk1.4  */
324
        return new java.util.Date (getEntry (name).getTime ());
290
        return new java.util.Date (getEntry (name).getTime ());
325
    }
291
    }
326
292
327
    /*nbif compat
293
    protected boolean folder (String name) {
328
    public
329
    nbelse*/
330
    protected
331
    /*nbend*/
332
    boolean folder (String name) {
333
        if ("".equals (name)) return true; // NOI18N
294
        if ("".equals (name)) return true; // NOI18N
334
        EntryCache tmpRootCache = getCacheOfRoot ();
295
        EntryCache tmpRootCache = getCacheOfRoot ();
335
        if (tmpRootCache == null) 
296
        if (tmpRootCache == null) 
 Lines 340-379    Link Here 
340
        return tmpCache.isFolder ();
301
        return tmpCache.isFolder ();
341
    }
302
    }
342
303
343
    /*nbif compat
304
    protected boolean readOnly (String name) {
344
    public
345
    nbelse*/
346
    protected
347
    /*nbend*/
348
    boolean readOnly (String name) {
349
        return true;
305
        return true;
350
    }
306
    }
351
307
352
    /*nbif compat
308
    protected String mimeType (String name) {
353
    public
354
    nbelse*/
355
    protected
356
    /*nbend*/
357
    String mimeType (String name) {
358
        return null;
309
        return null;
359
    }
310
    }
360
311
361
    /*nbif compat
312
    protected long size (String name) {
362
    public
363
    nbelse*/
364
    protected
365
    /*nbend*/
366
    long size (String name) {
367
        long retVal = getEntry (name).getSize ();
313
        long retVal = getEntry (name).getSize ();
368
        return  (retVal == -1) ? 0 : retVal;
314
        return  (retVal == -1) ? 0 : retVal;
369
    }
315
    }
370
316
371
    /*nbif compat
317
    protected InputStream inputStream (String name) throws java.io.FileNotFoundException {
372
    public
373
    nbelse*/
374
    protected
375
    /*nbend*/
376
  InputStream inputStream (String name) throws java.io.FileNotFoundException {
377
        InputStream is = null;
318
        InputStream is = null;
378
        AbstractFolder fo = null; 
319
        AbstractFolder fo = null; 
379
        try {
320
        try {
 Lines 429-474    Link Here 
429
        return in;
370
        return in;
430
    }
371
    }
431
    
372
    
432
    /*nbif compat
373
    protected OutputStream outputStream (String name) throws java.io.IOException {
433
    public
434
    nbelse*/
435
    protected
436
    /*nbend*/
437
    OutputStream outputStream (String name) throws java.io.IOException {
438
        throw new IOException ();
374
        throw new IOException ();
439
    }
375
    }
440
376
441
    /*nbif compat
377
    protected void lock (String name) throws IOException {
442
    public
443
    nbelse*/
444
    protected
445
    /*nbend*/
446
    void lock (String name) throws IOException {
447
        FSException.io ("EXC_CannotLock", name, getDisplayName (), name); // NOI18N
378
        FSException.io ("EXC_CannotLock", name, getDisplayName (), name); // NOI18N
448
    }
379
    }
449
380
450
    /*nbif compat
381
    protected void unlock (String name) {
451
    public
382
    }
452
    nbelse*/
383
453
    protected
384
    protected void markUnimportant (String name) {
454
    /*nbend*/
385
    }
455
    void unlock (String name) {
386
456
    }
387
    protected Object readAttribute(String name, String attrName) {
457
458
    /*nbif compat
459
    public
460
    nbelse*/
461
    protected
462
    /*nbend*/
463
    void markUnimportant (String name) {
464
    }
465
466
    /*nbif compat
467
    public
468
    nbelse*/
469
    protected
470
    /*nbend*/
471
    Object readAttribute(String name, String attrName) {
472
        Attributes attr = getManifest ().getAttributes (name);                
388
        Attributes attr = getManifest ().getAttributes (name);                
473
        try {
389
        try {
474
            return attr == null ? null : attr.getValue (attrName);
390
            return attr == null ? null : attr.getValue (attrName);
 Lines 477-497    Link Here 
477
        }        
393
        }        
478
    }
394
    }
479
395
480
    /*nbif compat
396
    protected void writeAttribute(String name, String attrName, Object value) throws IOException {
481
    public
482
    nbelse*/
483
    protected
484
    /*nbend*/
485
    void writeAttribute(String name, String attrName, Object value) throws IOException {
486
        throw new IOException ();
397
        throw new IOException ();
487
    }
398
    }
488
399
489
    /*nbif compat
400
    protected Enumeration attributes(String name) {
490
    public
491
    nbelse*/
492
    protected
493
    /*nbend*/
494
    Enumeration attributes(String name) {
495
        Attributes attr = getManifest ().getAttributes (name);
401
        Attributes attr = getManifest ().getAttributes (name);
496
        
402
        
497
        if (attr != null) {
403
        if (attr != null) {
 Lines 506-525    Link Here 
506
        }
412
        }
507
    }
413
    }
508
414
509
    /*nbif compat
415
    protected void renameAttributes (String oldName, String newName) {
510
    public
511
    nbelse*/
512
    protected
513
    /*nbend*/
514
    void renameAttributes (String oldName, String newName) {
515
    }
416
    }
516
417
517
    /*nbif compat
418
    protected void deleteAttributes (String name) {
518
    public
519
    nbelse*/
520
    protected
521
    /*nbend*/
522
    void deleteAttributes (String name) {
523
    }
419
    }
524
420
525
    /** Close the jar file when we go away...*/
421
    /** Close the jar file when we go away...*/
(-)nb_all/openide/src/org/openide/filesystems/LocalFileSystem.java (-95 / +16 lines)
 Lines 34-44    Link Here 
34
* as protected in this class. Do not call them! Subclasses might override
34
* as protected in this class. Do not call them! Subclasses might override
35
* them, or (better) use delegation.
35
* them, or (better) use delegation.
36
*/
36
*/
37
public class LocalFileSystem extends AbstractFileSystem
37
public class LocalFileSystem extends AbstractFileSystem {
38
    /*nbif compat
39
    implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change
40
    /*nbend*/
41
{
42
    /** generated Serialized Version UID */
38
    /** generated Serialized Version UID */
43
    private static final long serialVersionUID = -5355566113542272442L;
39
    private static final long serialVersionUID = -5355566113542272442L;
44
    
40
    
 Lines 155-166    Link Here 
155
    // List
151
    // List
156
    //
152
    //
157
153
158
    /*nbif compat
154
    protected String[] children (String name) {
159
    public
160
    nbelse*/
161
    protected
162
    /*nbend*/
163
    String[] children (String name) {
164
        File f = getFile (name);
155
        File f = getFile (name);
165
        if (f.isDirectory ()) {
156
        if (f.isDirectory ()) {
166
            return f.list ();
157
            return f.list ();
 Lines 173-184    Link Here 
173
    // Change
164
    // Change
174
    //
165
    //
175
166
176
    /*nbif compat
167
    protected void createFolder (String name) throws java.io.IOException {
177
    public
178
    nbelse*/
179
    protected
180
    /*nbend*/
181
    void createFolder (String name) throws java.io.IOException {
182
        File f = getFile (name);
168
        File f = getFile (name);
183
169
184
        if (name.equals ("")) { // NOI18N
170
        if (name.equals ("")) { // NOI18N
 Lines 219-230    Link Here 
219
    }
205
    }
220
206
221
207
222
    /*nbif compat
208
    protected void createData (String name) throws IOException {
223
    public
224
    nbelse*/
225
    protected
226
    /*nbend*/
227
    void createData (String name) throws IOException {
228
        File f = getFile (name);
209
        File f = getFile (name);
229
210
230
        if (!f.createNewFile ()) {
211
        if (!f.createNewFile ()) {
 Lines 245-256    Link Here 
245
        */
226
        */
246
    }
227
    }
247
228
248
    /*nbif compat
229
    protected void rename(String oldName, String newName) throws IOException {
249
    public
250
    nbelse*/
251
    protected
252
    /*nbend*/
253
    void rename(String oldName, String newName) throws IOException {
254
        File of = getFile (oldName);
230
        File of = getFile (oldName);
255
        File nf = getFile (newName);
231
        File nf = getFile (newName);
256
        
232
        
 Lines 260-271    Link Here 
260
        }
236
        }
261
    }
237
    }
262
238
263
    /*nbif compat
239
    protected void delete(String name) throws IOException {
264
    public
265
    nbelse*/
266
    protected
267
    /*nbend*/
268
    void delete(String name) throws IOException {
269
        File file = getFile(name);
240
        File file = getFile(name);
270
        if (deleteFile(file) != SUCCESS) {
241
        if (deleteFile(file) != SUCCESS) {
271
            if (file.exists())
242
            if (file.exists())
 Lines 323-371    Link Here 
323
    // Info
294
    // Info
324
    //
295
    //
325
296
326
    /*nbif compat
297
    protected java.util.Date lastModified(String name) {
327
    public
328
    nbelse*/
329
    protected
330
    /*nbend*/
331
    java.util.Date lastModified(String name) {
332
        return new java.util.Date (getFile (name).lastModified ());
298
        return new java.util.Date (getFile (name).lastModified ());
333
    }
299
    }
334
300
335
    /*nbif compat
301
    protected boolean folder (String name) {
336
    public
337
    nbelse*/
338
    protected
339
    /*nbend*/
340
    boolean folder (String name) {
341
        return getFile (name).isDirectory ();
302
        return getFile (name).isDirectory ();
342
    }
303
    }
343
304
344
    /*nbif compat
305
    protected boolean readOnly (String name) {
345
    public
346
    nbelse*/
347
    protected
348
    /*nbend*/
349
    boolean readOnly (String name) {
350
        File f = getFile (name);
306
        File f = getFile (name);
351
        return !f.canWrite () && f.exists ();
307
        return !f.canWrite () && f.exists ();
352
    }
308
    }
353
309
354
    /*nbif compat
310
    protected String mimeType (String name) {
355
    public
356
    nbelse*/
357
    protected
358
    /*nbend*/
359
    String mimeType (String name) {
360
        return null;
311
        return null;
361
    }
312
    }
362
313
363
    /*nbif compat
314
    protected long size (String name) {
364
    public
365
    nbelse*/
366
    protected
367
    /*nbend*/
368
    long size (String name) {
369
        return getFile (name).length ();
315
        return getFile (name).length ();
370
    }
316
    }
371
317
 Lines 399-410    Link Here 
399
    // ============================================================================
345
    // ============================================================================
400
    //  Begin of the original part
346
    //  Begin of the original part
401
347
402
    /*nbif compat
348
    protected InputStream inputStream (String name) throws java.io.FileNotFoundException {
403
    public
404
    nbelse*/
405
    protected
406
    /*nbend*/
407
    InputStream inputStream (String name) throws java.io.FileNotFoundException {
408
        FileInputStream fis;
349
        FileInputStream fis;
409
        File    file = null;
350
        File    file = null;
410
        
351
        
 Lines 419-442    Link Here 
419
        return fis;
360
        return fis;
420
    }
361
    }
421
362
422
    /*nbif compat
363
    protected OutputStream outputStream (String name) throws java.io.IOException {
423
    public
424
    nbelse*/
425
    protected
426
    /*nbend*/
427
    OutputStream outputStream (String name) throws java.io.IOException {
428
        return new FileOutputStream (getFile (name));
364
        return new FileOutputStream (getFile (name));
429
    }
365
    }
430
366
431
    //  End of the original part
367
    //  End of the original part
432
    // ============================================================================
368
    // ============================================================================
433
369
434
    /*nbif compat
370
    protected void lock (String name) throws IOException {
435
    public
436
    nbelse*/
437
    protected
438
    /*nbend*/
439
    void lock (String name) throws IOException {
440
        File file = getFile (name);
371
        File file = getFile (name);
441
        if ((!file.canWrite () && file.exists ()) ||
372
        if ((!file.canWrite () && file.exists ()) ||
442
            isReadOnly()) {
373
            isReadOnly()) {
 Lines 444-463    Link Here 
444
        }
375
        }
445
    }
376
    }
446
377
447
    /*nbif compat
378
    protected void unlock (String name) {
448
    public
449
    nbelse*/
450
    protected
451
    /*nbend*/
452
    void unlock (String name) {
453
    }
379
    }
454
380
455
    /*nbif compat
381
    protected void markUnimportant (String name) {
456
    public
457
    nbelse*/
458
    protected
459
    /*nbend*/
460
    void markUnimportant (String name) {
461
    }
382
    }
462
383
463
    /** Creates file for given string name.
384
    /** Creates file for given string name.
(-)nb_all/openide/src/org/openide/filesystems/Repository.java (-3 lines)
 Lines 38-46    Link Here 
38
* @author Jaroslav Tulach, Petr Hamernik
38
* @author Jaroslav Tulach, Petr Hamernik
39
*/
39
*/
40
public class Repository extends Object implements java.io.Serializable 
40
public class Repository extends Object implements java.io.Serializable 
41
/*nbif compat
42
, org.openide.nodes.Node.Cookie
43
/*nbend*/
44
{
41
{
45
    /** list of filesystems (FileSystem) */
42
    /** list of filesystems (FileSystem) */
46
    private ArrayList fileSystems;
43
    private ArrayList fileSystems;
(-)nb_all/openide/src/org/openide/loaders/DataLoaderPool.java (-19 lines)
 Lines 518-527    Link Here 
518
    //
518
    //
519
    
519
    
520
    /** Loader for folders, since 1.13 changed to UniFileLoader. */
520
    /** Loader for folders, since 1.13 changed to UniFileLoader. */
521
    /*nbif compat
522
    public
523
    nbelse*/
524
    /*nbend*/
525
    static class FolderLoader extends UniFileLoader {
521
    static class FolderLoader extends UniFileLoader {
526
        static final long serialVersionUID =-8325525104047820255L;
522
        static final long serialVersionUID =-8325525104047820255L;
527
        
523
        
 Lines 652-662    Link Here 
652
    /* Instance loader recognizing .ser and .instance files. It's placed at
648
    /* Instance loader recognizing .ser and .instance files. It's placed at
653
     * the end of loader pool among default loaders.
649
     * the end of loader pool among default loaders.
654
     */
650
     */
655
    /*nbif compat
656
    public
657
    nbelse*/
658
    private
659
    /*nbend*/
660
    static class InstanceLoader extends UniFileLoader {
651
    static class InstanceLoader extends UniFileLoader {
661
        static final long serialVersionUID =-3462727693843631328L;
652
        static final long serialVersionUID =-3462727693843631328L;
662
        
653
        
 Lines 770-780    Link Here 
770
    
761
    
771
    
762
    
772
    /** Loader for file objects not recognized by any other loader */
763
    /** Loader for file objects not recognized by any other loader */
773
    /*nbif compat
774
    public
775
    nbelse*/
776
    private
777
    /*nbend*/
778
    static class DefaultLoader extends MultiFileLoader {
764
    static class DefaultLoader extends MultiFileLoader {
779
        static final long serialVersionUID =-6761887227412396555L;
765
        static final long serialVersionUID =-6761887227412396555L;
780
        
766
        
 Lines 867-877    Link Here 
867
    }
853
    }
868
    
854
    
869
    /** Loader for shadows, since 1.13 changed to UniFileLoader. */
855
    /** Loader for shadows, since 1.13 changed to UniFileLoader. */
870
    /*nbif compat
871
    public
872
    nbelse*/
873
    private
874
    /*nbend*/
875
    static class ShadowLoader extends UniFileLoader {
856
    static class ShadowLoader extends UniFileLoader {
876
        static final long serialVersionUID =-11013405787959120L;
857
        static final long serialVersionUID =-11013405787959120L;
877
        
858
        
(-)nb_all/openide/src/org/openide/loaders/MultiDataObject.java (-12 / +2 lines)
 Lines 585-596    Link Here 
585
    * @param s the cookie set to use
585
    * @param s the cookie set to use
586
    * @deprecated just use getCookieSet().add(...) instead
586
    * @deprecated just use getCookieSet().add(...) instead
587
    */
587
    */
588
    /*nbif compat
588
    protected final void setCookieSet (CookieSet s) {
589
    public
590
    nbelse*/
591
    protected final
592
    /*nbend*/
593
    void setCookieSet (CookieSet s) {
594
        setCookieSet(s, true);
589
        setCookieSet(s, true);
595
    }
590
    }
596
591
 Lines 625-636    Link Here 
625
    *
620
    *
626
    * @return the cookie set (never <code>null</code>)
621
    * @return the cookie set (never <code>null</code>)
627
    */
622
    */
628
    /*nbif compat
623
    protected final CookieSet getCookieSet () {
629
    public
630
    nbelse*/
631
    protected final
632
    /*nbend*/
633
    CookieSet getCookieSet () {
634
        CookieSet s = cookieSet;
624
        CookieSet s = cookieSet;
635
        if (s != null) return s;
625
        if (s != null) return s;
636
        synchronized (cookieSetLock) {
626
        synchronized (cookieSetLock) {
(-)nb_all/openide/src/org/openide/nodes/AbstractNode.java (-6 / +1 lines)
 Lines 512-523    Link Here 
512
    *
512
    *
513
    * @return the cookie set created by {@link #setCookieSet}, or an empty set (never <code>null</code>)
513
    * @return the cookie set created by {@link #setCookieSet}, or an empty set (never <code>null</code>)
514
    */
514
    */
515
    /*nbif compat
515
    protected final CookieSet getCookieSet () {
516
    public
517
    nbelse*/
518
    protected
519
    /*nbend*/
520
    final CookieSet getCookieSet () {
521
        CookieSet s = cookieSet;
516
        CookieSet s = cookieSet;
522
        if (s != null) return s;
517
        if (s != null) return s;
523
        synchronized (this) {
518
        synchronized (this) {
(-)nb_all/openide/src/org/openide/util/actions/SystemAction.java (-17 lines)
 Lines 188-210    Link Here 
188
        return getIcon (false);
188
        return getIcon (false);
189
    }
189
    }
190
190
191
    /*nbif compat
192
    public final void setIcon (ImageIcon icon) {
193
        setIcon ((Icon) icon);
194
    }
195
    public final ImageIcon g3t1c0n () {
196
        Icon i = getIcon (false);
197
        if (i instanceof ImageIcon) {
198
            return ((ImageIcon) i);
199
        } else {
200
            // [PENDING] could try to translate Icon -> ImageIcon somehow,
201
            // but I have no idea how to do this (paint it, take Component
202
            // graphics, load the image data somehow??)
203
            return getBlankIcon();
204
        }
205
    }
206
    /*nbend*/
207
208
    /** Get the action's display icon, possibly creating a text label.
191
    /** Get the action's display icon, possibly creating a text label.
209
    * @param createLabel if <code>true</code>, create a textual icon if otherwise there
192
    * @param createLabel if <code>true</code>, create a textual icon if otherwise there
210
    * would be none; if <code>false</code>, create a blank icon
193
    * would be none; if <code>false</code>, create a blank icon
(-)nb_all/xtest/build.xml (+1 lines)
 Lines 39-44    Link Here 
39
          <include name="openide*.jar" />
39
          <include name="openide*.jar" />
40
        </fileset>
40
        </fileset>
41
	<pathelement location="../core/netbeans/lib/core.jar"/>
41
	<pathelement location="../core/netbeans/lib/core.jar"/>
42
	<pathelement location="../core/netbeans/lib/ext/boot.jar"/>
42
        <!-- XXX stop using this! Not to mention it should use ${binroot}. -->
43
        <!-- XXX stop using this! Not to mention it should use ${binroot}. -->
43
        <fileset dir="../../nbextra/ant/release/modules/ext">
44
        <fileset dir="../../nbextra/ant/release/modules/ext">
44
          <include name="ant.jar"/>
45
          <include name="ant.jar"/>
(-)nb_all/xtest/src/org/netbeans/core/modules/Module.java (-8 / +48 lines)
 Lines 29-34    Link Here 
29
import java.util.zip.ZipEntry;
29
import java.util.zip.ZipEntry;
30
import org.openide.modules.SpecificationVersion;
30
import org.openide.modules.SpecificationVersion;
31
import org.openide.modules.Dependency;
31
import org.openide.modules.Dependency;
32
import org.netbeans.JarClassLoader;
33
import org.netbeans.ProxyClassLoader;
32
34
33
/** Object representing one module, possibly installed.
35
/** Object representing one module, possibly installed.
34
 * Responsible for opening of module JAR file; reading
36
 * Responsible for opening of module JAR file; reading
 Lines 723-737    Link Here 
723
        // #9273: load any modules/patches/this-code-name/*.jar files first:
725
        // #9273: load any modules/patches/this-code-name/*.jar files first:
724
        File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
726
        File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
725
                                 getCodeNameBase().replace('.', '-')); // NOI18N
727
                                 getCodeNameBase().replace('.', '-')); // NOI18N
726
        if (patchdir.isDirectory()) {
728
        
727
            File[] jars = patchdir.listFiles(Util.jarFilter());
729
        scanFilesInADir (patchdir, classp);
728
            if (jars != null) {
730
        
729
                for (int j = 0; j < jars.length; j++) {
731
        String patchesClassPath = System.getProperty ("netbeans.patches." + getCodeNameBase ()); // NOI18N
730
                    ev.log(Events.PATCH, jars[j]);
732
        if (patchesClassPath != null) {
731
                    classp.add(new JarFile(jars[j]));
733
            //scanFilesInADir (new File (dir), classp);
734
            StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator);
735
            while (tokenizer.hasMoreElements()) {
736
                String element = (String) tokenizer.nextElement();
737
                File fileElement = new File(element);
738
                if (fileElement.isDirectory()) {
739
                    // adding directory
740
                    Util.err.log("module patches: adding directory "+fileElement+" for "+getCodeNameBase());
741
                    File[] jars = fileElement.listFiles(Util.jarFilter());
742
                    if (jars != null) {
743
                        for (int j=0; j < jars.length; j++) {
744
                            // add jar files
745
                            System.out.println("adding jar file:"+jars[j]);
746
                            classp.add( new JarFile(jars[j]));
747
                        }
748
                    }
749
                    // add also dir
750
                    System.out.println("adding directory:"+fileElement);
751
                    classp.add((Object) fileElement);
732
                }
752
                }
733
            } else {
734
                Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir);
735
            }
753
            }
736
        }
754
        }
737
        
755
        
 Lines 779-784    Link Here 
779
            File act = (File)it.next();
797
            File act = (File)it.next();
780
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act));
798
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act));
781
        }
799
        }
800
        
801
        if (loaders.length == 0) {
802
            loaders = new ClassLoader[] {Module.class.getClassLoader()};
803
        }
804
        
782
        try {
805
        try {
783
            classloader = new OneModuleClassLoader(classp, loaders);
806
            classloader = new OneModuleClassLoader(classp, loaders);
784
        } catch (IllegalArgumentException iae) {
807
        } catch (IllegalArgumentException iae) {
 Lines 788-793    Link Here 
788
            throw ioe;
811
            throw ioe;
789
        }
812
        }
790
    }
813
    }
814
    
815
    /** Scans content of a directory */
816
    private void scanFilesInADir (File patchdir, List classp) throws IOException {
817
        if (!patchdir.isDirectory()) {
818
            return;
819
        }
820
        File[] jars = patchdir.listFiles(Util.jarFilter());
821
        if (jars != null) {
822
            for (int j = 0; j < jars.length; j++) {
823
                ev.log(Events.PATCH, jars[j]);
824
                classp.add(new JarFile(jars[j]));
825
            }
826
        } else {
827
            Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir);
828
        }
829
    }
830
    
791
    /** Turn off the classloader and release all resources. */
831
    /** Turn off the classloader and release all resources. */
792
    void classLoaderDown() {
832
    void classLoaderDown() {
793
        if (isFixed()) return; // don't touch it
833
        if (isFixed()) return; // don't touch it
(-)nb_all/xtest/src/org/netbeans/xtest/ide/Main.java (+673 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.xtest.ide;
15
16
import java.util.*;
17
import java.awt.EventQueue;
18
import java.awt.Toolkit;
19
import java.awt.AWTEvent;
20
import java.awt.event.MouseEvent;
21
import java.awt.event.*;
22
import org.openide.*;
23
import org.openide.filesystems.*;
24
import org.openide.filesystems.FileSystem; // override java.io.FileSystem
25
import org.openide.loaders.*;
26
import org.openide.nodes.*;
27
import org.openide.execution.*;
28
import org.openide.util.*;
29
import org.openide.util.actions.*;
30
31
import org.netbeans.core.output.OutputSettings;
32
import org.netbeans.core.execution.TopSecurityManager;
33
34
// flag file stuff
35
import java.io.*;
36
37
// native kill stuff
38
import org.netbeans.xtest.util.JNIKill;
39
40
/**
41
 *
42
 * @author jchalupa
43
 */
44
public class Main extends Object {
45
    
46
    // terminate code :-)
47
    public static final int TERMINATE_CODE = 666;
48
    // terminate command :-)
49
    public static final String TERMINATE_NAME = "kill";
50
    
51
    private static ErrorManager errMan;
52
    
53
    // ide running flag file
54
    private static File ideRunning = null;
55
56
57
    
58
    // flag whether IDE was interrupted 
59
    private static boolean ideInterrupted = false;
60
    
61
    
62
    // finds terminate process action in the action array
63
    private static SystemAction findTerminateAction(SystemAction[] actions) {
64
        if (actions == null) {
65
            throw new IllegalArgumentException();
66
        }
67
        // I need to get the string from resource bundle
68
        // bundle = org.netbeans.core.execution.Bundle.properties
69
        // key = terminateProcess
70
        String terminateString = NbBundle.getMessage(org.netbeans.core.execution.ProcessNode.class,"terminateProcess");
71
        for (int i=0; i<actions.length; i++) {
72
            if (terminateString.equals(actions[i].getName())) {
73
                return actions[i];
74
            }
75
        }
76
        return null;
77
    }
78
    
79
    
80
81
    
82
    /* 
83
     * terminates processes shown in the Runtime/Processes node
84
     * return number of processes which the method was not able
85
     * to kill, -1 if any problem was encoutered
86
     */
87
    public static int terminateProcesses() {
88
        
89
        // number of processes which were not terminated
90
        int notTerminatedProcesses = 0;
91
        // number of processes which were terminated
92
        int terminatedProcesses = 0;
93
        
94
        
95
        // first - try to use ExecutionEngine ...
96
        org.netbeans.core.execution.ExecutionEngine engine = org.netbeans.core.execution.ExecutionEngine.getExecutionEngine();
97
        Collection tasks = engine.getRunningTasks();
98
        Object items[] = tasks.toArray();
99
        for (int i=0; i< items.length; i++) {
100
            if ( (items[i] != null) & (items[i] instanceof ExecutorTask) ) {
101
                ExecutorTask task = (ExecutorTask)items[i];
102
                // do not kill anything starting with org.netbeans.xtest.
103
                if (task.toString().indexOf("org.netbeans.xtest.") == -1) {
104
                    errMan.log(ErrorManager.USER,"Stopping task (via Execution Engine): "+task.toString());
105
                    task.stop();
106
                    int result = task.result();
107
                    errMan.log(ErrorManager.USER,"Task exited with result: "+result);
108
                    terminatedProcesses++;
109
                }
110
            }
111
        }    
112
        
113
        // second - use Runtime and Processes Nodes (to be sure) ...
114
        
115
        // get runtime node
116
        Places places = TopManager.getDefault().getPlaces();
117
        Node runtime = places.nodes().environment();
118
119
        // find Processes node
120
        // bundle = org.netbeans.core.execution.Bundle.properties
121
        // key = Processes
122
        //String processesString = "Processes";
123
        String processesString = NbBundle.getMessage(org.netbeans.core.execution.ProcessNode.class,"Processes");
124
        if (processesString == null) {
125
            processesString = "Processes";
126
        }
127
        Node processesNode = runtime.getChildren().findChild(processesString);
128
                
129
        // get all running processes
130
        Node[] runningProcesses = processesNode.getChildren().getNodes();
131
        
132
        if (runningProcesses != null) {
133
            for (int i=0; i<runningProcesses.length; i++) {                   
134
                // if process does not start with org.netbeans.xtest - these are
135
                // processes driving the tests, we should not kill them
136
                if (!runningProcesses[i].getName().startsWith("org.netbeans.xtest")) {
137
                    // get actions for the processes
138
                    SystemAction[] actions = runningProcesses[i].getActions();
139
                    if (actions != null) {
140
                        SystemAction terminate = findTerminateAction(actions);
141
                        if (terminate != null) {
142
                            ActionEvent av = new ActionEvent(runningProcesses[i],
143
                                    TERMINATE_CODE,TERMINATE_NAME);
144
                            errMan.log(ErrorManager.USER,"Stopping process: (via Execution View) "+runningProcesses[i].getName());
145
                            // is there any status returned from the method ?
146
                            terminate.actionPerformed(av);
147
                            terminatedProcesses++;
148
                        } else {
149
                            // cannot terminate this process - does not have
150
                            // terminate action (highly unlikely)
151
                            errMan.log(ErrorManager.USER,"Process "+runningProcesses[i].getName() + " has not terminate action. Can't terminate.");
152
                            notTerminatedProcesses++;
153
                        }
154
                    } else {
155
                        // process does not have any actions - cannot terminate
156
                        // again, this is highly unlikely
157
                        errMan.log(ErrorManager.USER,"Process "+runningProcesses[i].getName() + " has not any action. Can't terminate.");
158
                        notTerminatedProcesses++;
159
                    }
160
                } else {
161
                    // not killing my own processes
162
                    // they are not even counted
163
                }
164
            }
165
        }
166
        if (terminatedProcesses > 0) {
167
            // better sleep for a sec, so they can be really killed
168
            try {
169
                Thread.sleep(5000);
170
            } catch (InterruptedException ie) {
171
                // nothing
172
            }
173
        }
174
        return notTerminatedProcesses;
175
    }
176
        
177
    
178
    /** Installs XTestErrorManager to NetBeans 
179
     *
180
     */
181
    private static boolean installXTestErrorManager() {
182
        try {
183
            System.out.println("Installing XTestErrorManager");
184
            FileSystem systemFS = TopManager.getDefault().getRepository().findFileSystem("SystemFileSystem");
185
            DataFolder emFolder = DataFolder.findFolder(systemFS.getRoot().getFileObject("Services").getFileObject("Hidden"));
186
            InstanceDataObject xem = InstanceDataObject.create(emFolder,"xem","org.netbeans.xtest.ide.XTestErrorManager");
187
            // sleep for a sec, so ErrorManager gets installed
188
            Thread.sleep(1000);
189
            System.out.println("XTestErrorManager Installed");
190
            return true;
191
        } catch (NullPointerException npe) {
192
            // cannot install custom ErrorManager
193
            return false;
194
        } catch (IOException ioe) {
195
            return false;        
196
        } catch (InterruptedException ie) {
197
            return true;
198
        }
199
    }
200
    
201
    private static void prepareModuleLoaderClassPath() {
202
        String moduleLoaderName = System.getProperty("xtest.useclassloader");
203
        if (moduleLoaderName != null) {
204
            System.out.println("Using module "+moduleLoaderName+" classloader to load tests");
205
            String testbagClassPath = System.getProperty("tbag.classpath");
206
            if (testbagClassPath != null) {
207
                // set appropriate property
208
                String patchesProperty = "netbeans.patches."+moduleLoaderName;
209
                System.out.println("Setting system property "+patchesProperty+" to "+testbagClassPath);
210
                System.setProperty(patchesProperty, testbagClassPath);
211
            } else {
212
                System.out.println("TestBag classpath (tbag.classpath) property not defined - there is nothing to load");
213
            }
214
        }
215
    }
216
    
217
    
218
    /** Starts the IDE.
219
     * @param args the command line arguments
220
     */
221
    public static void main(String args[]) {
222
        // need to initialize org.openide.TopManager, not org.netbeans.core.Plain
223
          System.getProperties().put (
224
            "org.openide.TopManager", // NOI18N
225
            "org.netbeans.core.Main" // NOI18N
226
          );
227
        
228
        // create the IDE flag file
229
        String workdir = System.getProperty("xtest.workdir");
230
        if (workdir!=null) {
231
            // create flag file indicating running tests
232
            ideRunning = new File(workdir,"ide.flag");
233
            File idePID = new File(workdir,"ide.pid");
234
            PrintWriter writer = null;
235
             try {
236
                ideRunning.createNewFile();
237
                idePID.createNewFile();
238
                writer = new PrintWriter(new FileOutputStream(idePID));
239
                // get my pid
240
                JNIKill kill = new JNIKill();
241
                long myPID = kill.getMyPID();
242
                System.out.println("IDE is running under PID:"+myPID);
243
                writer.println(myPID);                
244
            } catch (IOException ioe) {
245
                System.out.println("cannot create flag file:"+ideRunning);
246
                ideRunning = null;
247
            } catch (Throwable e) {
248
                System.out.println("There was a problem: "+e);
249
            } finally {
250
                if (writer != null) {
251
                    writer.close();
252
                }
253
            }
254
        } else {
255
            System.out.println("cannot get xtest.workdir property - it has to be set to a valid working directory");
256
        }
257
        
258
        // prepare module's classpath
259
        prepareModuleLoaderClassPath();
260
        
261
        // do the expected stuff
262
        try {
263
           org.netbeans.core.Main.main(args);
264
        }
265
        catch (Exception e) {
266
           e.printStackTrace();
267
           exit();
268
        }
269
270
        // install XTest error manager (only if xtest.error.manager=true)
271
        // and openide version > 2
272
273
        // get openide version - if sys property is not found - assume it is version 0
274
        float openideVersion = 0;
275
        try {
276
            openideVersion = Float.parseFloat(System.getProperty("org.openide.specification.version","0"));
277
        } catch (NumberFormatException nfe) {
278
            // property is not found - go on with 0
279
        }
280
        
281
        if (System.getProperty("xtest.error.manager","false").equals("true")) {
282
            if (openideVersion > 2.0) {                
283
                boolean result = installXTestErrorManager();
284
                if (result==false) {
285
                    System.out.println("Cannot install XTestErrorManager");
286
                } else {
287
                    System.setProperty("xtest.error.manager","installed");
288
                }                
289
            } else {
290
                System.out.println("OpenIDE version must be over 2.0 to use XTestErrorManager");
291
                System.out.println("Current version is "+openideVersion);
292
            }
293
        }
294
    
295
296
        
297
298
        
299
        // get the static ErrorManager instance
300
        errMan = TopManager.getDefault().getErrorManager();
301
        
302
        // some threads may be still active, wait for the event queue to become quiet
303
        Thread initThread = new Thread(new Runnable() {
304
            public void run() {
305
                try {
306
                    new QueueEmpty().waitEventQueueEmpty(2000);
307
                }
308
                catch (Exception ex) {
309
                    TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex);
310
                }
311
            }
312
        });
313
        // start the init thread
314
        initThread.start();
315
        try {
316
            initThread.join(60000L);  // wait 1 minute at the most
317
        }
318
        catch (InterruptedException iex) {
319
            errMan.notify(ErrorManager.EXCEPTION, iex);
320
            
321
        }
322
        if (initThread.isAlive()) {
323
            // time-out expired, event queue still busy -> interrupt the init thread
324
            errMan.log(ErrorManager.USER, new Date().toString() + ": EventQueue still busy, starting anyway.");
325
            initThread.interrupt();
326
        }
327
        // ok. The IDE should be up and fully initialized
328
        // let's run the test now
329
        try {
330
            doTestPart();
331
        }
332
        catch (RuntimeException ex) {
333
            ex.printStackTrace();
334
        }
335
    }
336
    
337
    
338
    private static final String TEST_CLASS = "test.class";
339
    private static final String TEST_CLASSPATH = "test.classpath";
340
    private static final String TEST_ARGS = "test.arguments";
341
    private static final String TEST_EXECUTOR = "test.executor";
342
    private static final String TEST_EXIT = "test.exit";
343
    private static final String TEST_FINISHED = "test.finished";
344
    private static final String TEST_TIMEOUT = "test.timeout";
345
    private static final String TEST_REDIRECT = "test.output.redirect";
346
    private static final String TEST_REUSE_IDE = "test.reuse.ide";
347
    
348
    private static final long DEFAULT_TIMEOUT = 30;
349
    
350
    private static void doTestPart() {
351
        
352
        long testTimeout;
353
        
354
        // do nothing if no TEST_CLASS specified
355
        if (System.getProperty(TEST_CLASS) == null)
356
            return;                
357
        
358
        // Yarda Tulach's line - is this good for anything ?
359
        Object jarda = org.openide.filesystems.Repository.getDefault ();
360
        
361
        if (System.getProperty(TEST_REDIRECT) != null && System.getProperty(TEST_REDIRECT).equals("true")) {
362
            ((OutputSettings) Lookup.getDefault().lookup( OutputSettings.class )).setRedirection(true);
363
        }
364
        
365
        
366
        try {
367
            // default timeout is 30 minutes
368
            testTimeout = Long.parseLong(System.getProperty(TEST_TIMEOUT, "30"));
369
        }
370
        catch (NumberFormatException ex) {
371
            testTimeout = DEFAULT_TIMEOUT;
372
        }
373
        if (testTimeout <= 0) {
374
            testTimeout = DEFAULT_TIMEOUT;
375
        }
376
        // convert to milis
377
        testTimeout *= 60000L;
378
        
379
        StringTokenizer st = new StringTokenizer(System.getProperty(TEST_ARGS, ""));
380
        final String[] params = new String[st.countTokens()];
381
        int i = 0;
382
        while (st.hasMoreTokens()) {
383
            params[i++] = st.nextToken();
384
        }
385
        
386
        final long startTime = System.currentTimeMillis();
387
        final long testTime = testTimeout;
388
        Thread testThread = new Thread( new Runnable() {
389
            public void run() {
390
                try {
391
                    
392
                    // setup the repository
393
                    if (System.getProperty(TEST_CLASSPATH) != null && 
394
                        System.getProperty(TEST_REUSE_IDE, "false").equals("false")) {
395
                            mountFileSystems();
396
                    }
397
                     
398
                    setNodeProperties();
399
                    
400
                    ExecInfo ei = new org.openide.execution.ExecInfo(System.getProperty(TEST_CLASS), params);
401
                    Executor exec = (Executor)Class.forName(System.getProperty(TEST_EXECUTOR, "org.openide.execution.ThreadExecutor")).newInstance();
402
                    
403
                    if (exec != null) {
404
                        System.setProperty(TEST_FINISHED, "false");
405
                        ExecutorTask task = exec.execute(ei);
406
                        
407
                        while (System.getProperty(TEST_FINISHED).equals("false")) {
408
                          try {
409
                            Thread.sleep(2000);
410
                          }
411
                          catch (InterruptedException e) {
412
                            long currentTime = System.currentTimeMillis();
413
                            if (startTime + testTime + 10000 > currentTime) {
414
                                break;
415
                            } 
416
                            else {
417
                                errMan.log(ErrorManager.USER, new Date().toString() + ": False InterruptedException. Continuing running tests");
418
                            }
419
                          } 
420
                        }
421
                    }
422
                }
423
                catch (Exception ex) {
424
                    TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex);
425
                }
426
            }
427
        });
428
        
429
        errMan.log(ErrorManager.USER, new Date().toString() + ": just starting.");
430
        // start the test thread
431
        testThread.start();
432
        try {
433
            testThread.join(testTimeout);
434
        }
435
        catch (InterruptedException iex) {
436
            errMan.notify(ErrorManager.EXCEPTION, iex);
437
        }
438
        if (testThread.isAlive()) {
439
            // time-out expired, test not finished -> interrupt
440
            errMan.log(ErrorManager.USER, new Date().toString() + ": time-out expired - interrupting! ***");
441
            ideInterrupted = true;
442
            testThread.interrupt();
443
        }
444
        
445
        // we're leaving IDE 
446
        // delete the flag file (if ide was not interrupted)
447
        if (ideRunning!=null) {
448
            if (!ideInterrupted) {
449
                if (ideRunning.delete()==false) {
450
                    System.out.println("Cannot delete the flag file "+ideRunning);
451
                }
452
            }
453
        }
454
        
455
        // close IDE
456
        if (System.getProperty(TEST_EXIT, "false").equals("true")) {
457
            Thread exitThread = new Thread(new Runnable() {
458
                public void run() {
459
                    // terminate all running processes
460
                    try {
461
                        terminateProcesses();
462
                    } catch (Exception e) {
463
                        System.out.println("Exception when terminating processes started from IDE");
464
                        e.printStackTrace();
465
                    }
466
                    TopManager.getDefault().exit();
467
                }
468
            });
469
            // try to exit nicely first
470
            errMan.log(ErrorManager.USER, new Date().toString() + ": soft exit attempt.");
471
            exitThread.start();
472
            try {
473
                // wait 90 seconds for the IDE to exit
474
                exitThread.join(90000);
475
            }
476
            catch (InterruptedException iex) {
477
                errMan.notify(ErrorManager.EXCEPTION, iex);
478
            }
479
            if (exitThread.isAlive()) {
480
                // IDE refuses to shutdown, terminate unconditionally
481
                errMan.log(ErrorManager.USER, new Date().toString() + ": hard exit attempt!!!.");
482
                exitThread.interrupt();
483
                exit();
484
            }
485
        }
486
    }
487
    
488
    private static void exit() {
489
        try {
490
           Class param[] = new Class[1];
491
           param[0] = int.class;
492
           Class c = org.netbeans.core.execution.TopSecurityManager.class;
493
           java.lang.reflect.Method m = c.getMethod("exit",param);
494
           Integer intparam[] = {new Integer(1)};
495
           errMan.log(ErrorManager.USER, new Date().toString() + ": using TopSecurityManager.exit(1) to exit IDE.");
496
           // exit
497
           m.invoke(null,intparam);
498
        }
499
        catch (Exception e) {
500
           errMan.log(ErrorManager.USER, new Date().toString() + ": using System.exit(1) to exit IDE.");
501
           // exit
502
           System.exit(1);
503
        }
504
    }
505
    
506
    
507
    private static void mountFileSystems() {
508
        Repository repo = TopManager.getDefault().getRepository();
509
        
510
        // unmount the currently mounted filesystems
511
        // (could be more sofisticated some day)
512
        Enumeration all = repo.getFileSystems();
513
        while (all.hasMoreElements()) {
514
            FileSystem fs = (FileSystem)all.nextElement();
515
            // preserve the hidden and default filesystems
516
            if (!fs.isHidden() && !fs.isDefault())
517
                repo.removeFileSystem(fs);
518
        }        
519
        // mount new filesystems as specified in TEST_CLASSPATH
520
        StringTokenizer stok = new StringTokenizer(System.getProperty(TEST_CLASSPATH), System.getProperty("path.separator"));
521
        while (stok.hasMoreElements()) {
522
            String pathelem = stok.nextToken();
523
            try {
524
                if (pathelem.endsWith(".jar") || pathelem.endsWith(".zip")) {
525
                    JarFileSystem jfs = new JarFileSystem();
526
                    jfs.setJarFile(new java.io.File(pathelem));
527
                    repo.addFileSystem(jfs);
528
                }
529
                else {
530
                    LocalFileSystem lfs = new LocalFileSystem();
531
                    lfs.setRootDirectory(new java.io.File(pathelem));
532
                    repo.addFileSystem(lfs);
533
                }
534
            }
535
            catch (Exception ex) {
536
                TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex);
537
            }
538
        }
539
    }
540
    
541
    
542
    private static void setNodeProperties() {
543
        FileObject fo = TopManager.getDefault().getRepository().findResource(System.getProperty(TEST_CLASS) + ".java");
544
        if (fo != null) {
545
            try {
546
                DataObject obj = DataObject.find(fo);
547
                Node nod = obj.getNodeDelegate();
548
                Node.PropertySet[] psets = nod.getPropertySets();
549
                Node.Property[] props = null;
550
                
551
                // get the Execution property set
552
                for (int i = 0; i < psets.length; i++) {
553
                    if (psets[i].getName().equals("Execution")) {
554
                        props = psets[i].getProperties();
555
                        break;
556
                    }
557
                }
558
                // get the "params" property and try to set it
559
                if (props != null) {
560
                    for (int i = 0; i < props.length; i++) {
561
                        if (props[i].getName().equals("params")) {
562
                            if (System.getProperty(TEST_ARGS) != null) {
563
                                props[i].setValue(System.getProperty(TEST_ARGS));
564
                            }
565
                        }
566
                    }
567
                }
568
            }
569
            catch (java.lang.Exception ex) {
570
                // ok, not able to set the Arguments property
571
                // it's still worth trying to proceed with the test
572
                // the FileObject may just be read-only
573
            }
574
            
575
        }
576
        
577
    }
578
    
579
580
    private static class QueueEmpty implements java.awt.event.AWTEventListener {
581
        
582
        private long eventDelayTime = 100; // 100 millis
583
        private long lastEventTime;
584
        
585
        /** Creates a new QueueEmpty instance */
586
        public QueueEmpty() {
587
        }
588
        
589
        /** method called every time when AWT Event is dispatched
590
         * @param event event dispatched from AWT Event Queue
591
         */
592
        public void eventDispatched(java.awt.AWTEvent awtEvent) {
593
            lastEventTime = System.currentTimeMillis();
594
        }
595
        
596
        /** constructor with user defined value
597
         * @param eventdelaytime maximum delay between two events of one redraw action
598
         */
599
        public synchronized void waitEventQueueEmpty(long eventDelayTime) throws InterruptedException {
600
            this.eventDelayTime = eventDelayTime;
601
            waitEventQueueEmpty();
602
        }
603
        
604
        /** Waits until the AWTEventQueue is empty for a specified interval
605
         */
606
        public synchronized void waitEventQueueEmpty() throws InterruptedException {
607
            // store current time as the start time
608
            long startTime = System.currentTimeMillis();
609
            // register itself as an AWTEventListener
610
            Toolkit.getDefaultToolkit().addAWTEventListener(this,
611
            AWTEvent.ACTION_EVENT_MASK |
612
            AWTEvent.ADJUSTMENT_EVENT_MASK |
613
            AWTEvent.COMPONENT_EVENT_MASK |
614
            AWTEvent.CONTAINER_EVENT_MASK |
615
            AWTEvent.FOCUS_EVENT_MASK |
616
            AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK |
617
            AWTEvent.HIERARCHY_EVENT_MASK |
618
            AWTEvent.INPUT_METHOD_EVENT_MASK |
619
            AWTEvent.INVOCATION_EVENT_MASK |
620
            AWTEvent.ITEM_EVENT_MASK |
621
            AWTEvent.KEY_EVENT_MASK |
622
            AWTEvent.MOUSE_EVENT_MASK |
623
            AWTEvent.MOUSE_MOTION_EVENT_MASK |
624
            AWTEvent.PAINT_EVENT_MASK |
625
            AWTEvent.TEXT_EVENT_MASK |
626
            AWTEvent.WINDOW_EVENT_MASK);
627
            
628
            // set last event time to the current time
629
            lastEventTime=System.currentTimeMillis();
630
            // get the thread to be put asleep
631
            Thread t = Thread.currentThread();
632
            // get current AWT Event Queue
633
            EventQueue queue=Toolkit.getDefaultToolkit().getSystemEventQueue();
634
            
635
            try {
636
                
637
                // while AWT Event Queue is not empty and timedelay from last event is shorter then eventdelaytime
638
                
639
                //wait till the queue is empty
640
                while ( queue.peekEvent() != null ) Thread.currentThread().sleep(100);
641
                //test it - post my own task and wait for it
642
                synchronized(this){
643
                    Runnable r = new Runnable() {
644
                        public void run() {
645
                            synchronized(QueueEmpty.this){QueueEmpty.this.notifyAll();}
646
                        }
647
                    };
648
                    queue.invokeLater(r);
649
                    wait();
650
                }
651
                //now 2 sec continuously should be silence
652
                while (System.currentTimeMillis() - lastEventTime < eventDelayTime) {
653
                    //sleep for the rest of eventDelay time
654
                    t.sleep(eventDelayTime + lastEventTime - System.currentTimeMillis());
655
                }
656
657
                //if (queue.peekEvent()==null) System.out.println("The AWT event queue seems to be empty.");
658
                //else System.out.println("Ops, in the AWT event queue still seems to be some tasks!");
659
660
            }
661
            catch (InterruptedException ex) {
662
                throw ex;
663
            }
664
            finally {
665
                //removing from listeners
666
                Toolkit.getDefaultToolkit().removeAWTEventListener(this);
667
            }
668
        }
669
        
670
        
671
    }
672
}
673
(-)nb_all/xtest/src/org/netbeans/xtest/ide/XTestErrorManager.java (+164 lines)
Added Link Here 
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.xtest.ide;
15
16
import org.openide.ErrorManager;
17
import org.openide.ErrorManager.Annotation;
18
import org.openide.TopManager;
19
import org.netbeans.core.TopLogging;
20
import java.util.*;
21
import java.io.*;
22
import java.lang.ref.*;
23
24
/**
25
 *
26
 * @author  mb115822
27
 */
28
public class XTestErrorManager extends ErrorManager  {
29
    
30
31
    
32
    // here's XTest ErrorManager
33
    private static ErrorManager errorManager = null;
34
    
35
36
    // here are stored notifications
37
    private static StringBuffer errorLog = new StringBuffer();        
38
    
39
    // getter for notifications
40
    public static synchronized String getNotifications() {
41
        if (errorLog.length() > 0) {
42
            return errorLog.toString();
43
        } else {
44
            return null;
45
        }
46
    }
47
    
48
    // clear stuff for notifications
49
    public static synchronized void clearNotifications() {
50
        errorLog = new StringBuffer();
51
    }
52
    
53
54
    // get if there were any notifications and clear the status
55
    public static synchronized boolean anyNotifications() {
56
        if (getNotifications() == null) {
57
            return false;
58
        } else {
59
            clearNotifications();
60
            return true;
61
        }
62
    }
63
    
64
        
65
    
66
    /** Creates new NbExceptionManager. */
67
    public XTestErrorManager() {
68
        if (errorManager == null) {
69
            errorManager = this;
70
        }
71
    }
72
    
73
    
74
    
75
    public org.openide.ErrorManager getInstance(String name)  {
76
        return getInstance();
77
    }
78
    
79
    public static org.openide.ErrorManager getInstance() {
80
         if (errorManager == null) {
81
            errorManager = new XTestErrorManager();
82
        }
83
        return errorManager;
84
    }
85
    
86
    /** Adds these values. All the
87
     * previous annotations are kept and this new is added at
88
     * the top of the annotation stack (index 0 of the annotation
89
     * array).
90
     *
91
     * @param severity integer describing severity (one of const values
92
     *   from this class)
93
     * @param date date or null
94
     * @param message message to attach to the exception or null
95
     * @param localizedMessage localized message for the user or null
96
     * @param stackTrace exception representing the stack trace or null
97
     */
98
    public synchronized Throwable annotate(
99
    Throwable t,
100
    int severity, String message, String localizedMessage,
101
    Throwable stackTrace, java.util.Date date
102
    ) {
103
        return null;
104
    }
105
    
106
    
107
    /** Associates annotations with this thread.
108
     *
109
     * @param arr array of annotations (or null)
110
     */
111
    public synchronized Throwable attachAnnotations(Throwable t, Annotation[] arr) {      
112
        return null;
113
    }
114
    
115
    /** Notifies all the exceptions associated with
116
     * this thread.
117
     * @param clear should the current exception be cleared or not?
118
     */
119
    public synchronized void notify(int severity, Throwable t) {
120
        // synchronized to ensure that only one exception is
121
        // written to the thread
122
        
123
        
124
        if (severity > ErrorManager.USER ) {
125
            // let's print the stuff to theByteArray ....
126
            
127
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
128
            
129
            PrintWriter ps = new PrintWriter(bs);
130
            
131
            ps.println("*********** Exception occured ************"); // NOI18N
132
            
133
            // log into the byte array
134
            t.printStackTrace(ps);
135
            
136
            ps.flush();
137
            
138
            ps.close();
139
            
140
            // add the notification to the string buffer
141
            errorLog.append(bs.toString()+"\n");
142
        /*
143
        ErrorManager.getDefault().log(ErrorManager.ERROR,"#\n#\n############# XTestEM notification: "+t+"\n#\n#\n");
144
         */
145
        }
146
    }
147
    
148
    
149
    /** Finds annotations associated with given exception.
150
     * @param t the exception
151
     * @return array of annotations or null
152
     */
153
    public synchronized Annotation[] findAnnotations(Throwable t) {
154
        return null;
155
    }
156
    
157
    // log !!!
158
    public void log(int severity, String s) {
159
    }
160
       
161
    
162
    
163
    
164
}
(-)nbextra/xtest/build.xml (-2 / +2 lines)
 Lines 17-27    Link Here 
17
               debug="${build.compiler.debug}">
17
               debug="${build.compiler.debug}">
18
            <classpath>
18
            <classpath>
19
                <pathelement location="${nbroot}/xtest/lib/xtest.jar"/>
19
                <pathelement location="${nbroot}/xtest/lib/xtest.jar"/>
20
		<!--<pathelement location="${nbroot}/xtest/lib/xtest-ide.jar"/>-->
20
                <pathelement location="${nbroot}/xtest/lib/junit-ext.jar"/>
21
                <pathelement location="${nbroot}/xtest/lib/junit-ext.jar"/>
21
                <pathelement location="${nbroot}/openide/netbeans/lib/openide.jar"/>                
22
                <pathelement location="${nbroot}/openide/netbeans/lib/openide.jar"/>                
22
                <pathelement location="${binroot}/xtest/lib/junit.jar"/>
23
                <pathelement location="${binroot}/xtest/lib/junit.jar"/>
23
                <pathelement location="${binroot}/xtest/lib/xerces.jar"/>
24
                <pathelement location="${binroot}/xtest/lib/xml-apis.jar"/>
24
                <pathelement location="${binroot}/xtest/lib/xalan.jar"/>
25
            </classpath>
25
            </classpath>
26
        </javac>
26
        </javac>
27
    </target>
27
    </target>
(-).cvsignore (+1 lines)
Added Link Here 
1
*.class
(-).cvsignore (+1 lines)
Added Link Here 
1
*.class
(-)nbextra/xtest/src/org/netbeans/xtest/pe/junit/JUnitResultsReporter.java (-1 / +1 lines)
 Lines 19-25    Link Here 
19
19
20
package org.netbeans.xtest.pe.junit;
20
package org.netbeans.xtest.pe.junit;
21
21
22
import org.netbeans.xtest.XTestErrorManager;
22
import org.netbeans.xtest.ide.XTestErrorManager;
23
import org.netbeans.xtest.junit.*;
23
import org.netbeans.xtest.junit.*;
24
import org.netbeans.xtest.pe.xmlbeans.*;
24
import org.netbeans.xtest.pe.xmlbeans.*;
25
import org.netbeans.xtest.pe.*;
25
import org.netbeans.xtest.pe.*;
(-).cvsignore (+1 lines)
Added Link Here 
1
*.class

Return to bug 19443
By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo