This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 26126
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/ide.cfg (-1 / +2 lines)
Line 1 Link Here
1
-J-Xverify:none -J-Xms24m -J-Xmx96m -J-Dnetbeans.logger.console=true
1
-J-Xms24m -J-Xmx96m
2
-J-Dnetbeans.logger.console=true
(-)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 (+805 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
import java.util.HashMap;
18
19
/** Class that can enhance bytecode with information about alternative
20
 * superclass and access modifiers. It can also extract this information 
21
 * later when the class is about to be loaded into the VM.
22
 * <P>
23
 * The additional information is added to attributes of the classfile (global attributes 
24
 * and also member attributes) and as such the class remain compatible and 
25
 * understandable for any VM. But if loaded by classloader that before defining 
26
 * the class invokes:
27
 * <pre>
28
 *  byte[] arr = ...;
29
 *  arr = PatchByteCode.patch (arr); 
30
 * </pre>
31
 * The class is altered in its superclass and/or access modifiers.
32
 * <P>
33
 * The patching mechanism uses two attributes. ATTR_SUPERCLASS can be just 
34
 * in global attributes pool (and only once), is of length 2 and contains index
35
 * into constant pool that contains definition of a Class that should become 
36
 * the alternate superclass. Attribute ATTR_MEMBER can appear in global
37
 * attribute set and also in set of each member (field or method). It is of 
38
 * length 2 and contains alternate value for access flags of the class or of
39
 * the field.
40
 * <P>
41
 * For purposes for speed, each patched class file has to end with bytes "nb". 
42
 * This is achieved by finishing the patching process by adding third attribute
43
 * "org.netbeans.enhanced" with value "nb". As such the <code>PatchByteCode.patch</code>
44
 * can quickly check the byte array and process just those that need processing.
45
 *
46
 * @author  Jaroslav Tulach
47
 */
48
public final class PatchByteCode {
49
    private static final String ATTR_SUPERCLASS = "org.netbeans.superclass"; // NOI18N
50
    private static final byte[] BYTE_SUPERCLASS;
51
    static {
52
        try {
53
            BYTE_SUPERCLASS = ATTR_SUPERCLASS.getBytes("utf-8"); // NOI18N
54
        } catch (java.io.UnsupportedEncodingException ex) {
55
            throw new IllegalStateException (ex.getMessage());
56
        }
57
    }
58
    private static final String ATTR_MEMBER = "org.netbeans.member"; // NOI18N
59
    private static final byte[] BYTE_MEMBER;
60
    static {
61
        try {
62
            BYTE_MEMBER = ATTR_MEMBER.getBytes("utf-8"); // NOI18N
63
        } catch (java.io.UnsupportedEncodingException ex) {
64
            throw new IllegalStateException (ex.getMessage());
65
        }
66
    }
67
68
    private static final String ATTR_INIT = "<init>"; // NOI18N
69
    private static final byte[] BYTE_INIT;
70
    static {
71
        try {
72
            BYTE_INIT = ATTR_INIT.getBytes("utf-8"); // NOI18N
73
        } catch (java.io.UnsupportedEncodingException ex) {
74
            throw new IllegalStateException (ex.getMessage());
75
        }
76
    }
77
78
    private static final String ATTR_INIT_TYPE = "()V"; // NOI18N
79
    private static final byte[] BYTE_INIT_TYPE;
80
    static {
81
        try {
82
            BYTE_INIT_TYPE = ATTR_INIT_TYPE.getBytes("utf-8"); // NOI18N
83
        } catch (java.io.UnsupportedEncodingException ex) {
84
            throw new IllegalStateException (ex.getMessage());
85
        }
86
    }
87
    
88
    private byte[] arr;
89
    
90
    private int cpCount;
91
    private int cpEnd;
92
    private int atCount;
93
    private int atEnd;
94
    
95
    /** the index of a string that matches the searched attribute */
96
    private int superClassNameIndex;
97
    /** the possiton of found attribute */
98
    private int superClassNameAttr;
99
    /** the index of a string to patch members of a field */
100
    private int memberNameIndex = -1;
101
    /** position of attribute the change the access rights of the class */
102
    private int memberClassAttr = -1;
103
    /** index of <init> UTF8 in constant pool*/
104
    private int initIndex = -1;
105
    /** index of ()V UTF8 in constant pool */
106
    private int initIndexType = -1;
107
    /** index of CONSTANT_NameAndType index for <init> and ()V in pool */
108
    private int initNameTypeIndex = -1;
109
    /** position of the <init> method */
110
    private int initAttr = -1;
111
    
112
    /** map that maps names of fields to their position in constant pool (String, int[1]) */
113
    private HashMap nameIndexes;
114
    
115
    /** Creates a new instance of PatchByteCode 
116
     *
117
     * @param nameIndexes hashmap from (String -> int[1]) 
118
     */
119
    private PatchByteCode(byte[] arr, HashMap nameIndexes) {
120
        this.arr = arr;
121
        this.nameIndexes = nameIndexes;
122
        
123
        // scan twice because of back references
124
        scan ();
125
        scan ();
126
    }
127
    
128
129
    /** Generates patch attribute into the classfile to
130
     * allow method <code>patch</code> to modify the superclass of this 
131
     * class.
132
     *
133
     * @param arr the bytecode to change
134
     * @param superClass name of the new superclass like java/awt/Button
135
     * @return new version of the bytecode if changed, otherwise null to signal that
136
     * no change has been made
137
     */
138
    public static byte[] enhance (byte[] arr, String superClass) {
139
        return enhance (arr, superClass, null);
140
    }
141
    
142
    /** Generates patch attribute into the classfile to
143
     * allow method <code>patch</code> to modify the superclass of this 
144
     * class.
145
     *
146
     * @param arr the bytecode to change
147
     * @param superClass name of the new superclass like java/awt/Button
148
     * @param methods array of names of methods to make public
149
     * @return new version of the bytecode if changed, otherwise null to signal that
150
     * no change has been made
151
     */
152
    public static byte[] enhance (byte[] arr, String superClass, String[] methods) {
153
        if (isPatched (arr)) {
154
            // already patched
155
            return null;
156
        }
157
        
158
        HashMap m;
159
        if (methods != null) {
160
            m = new HashMap ();
161
            for (int i = 0; i < methods.length; i++) {
162
                m.put (methods[i], new int[1]);
163
            }
164
        } else {
165
            m = null;
166
        }
167
        
168
        
169
        PatchByteCode pc = new PatchByteCode (arr, m); 
170
        boolean patched = false;
171
        
172
        if (superClass != null) {
173
            int x = pc.addClass (superClass);
174
175
            byte[] sup = new byte[2];
176
            writeU2 (sup, 0, x);
177
            pc.addAttribute (ATTR_SUPERCLASS, sup);
178
            
179
            patched = true;
180
        }
181
        
182
        if (!pc.isPublic ()) {
183
            // will need patching
184
            pc.markPublic ();
185
            patched = true;
186
        }
187
        
188
        if (methods != null) {
189
            for (int i = 0; i < methods.length; i++) {
190
                patched |= pc.markMemberPublic (methods[i]);
191
            }
192
        }
193
        
194
        if (patched) {
195
            byte[] patch = { 
196
                'n', 'b' // identification at the end of class file
197
            };
198
199
            pc.addAttribute ("org.netbeans.enhanced", patch);
200
        } else {
201
            return null;
202
        }
203
        
204
        
205
        
206
        // otherwise do the patching
207
        return pc.getClassFile ();
208
    }
209
    
210
    /** Checks if the class has previously been enhanced by the 
211
     * change of superclass attribute and if so, changes the bytecode
212
     * to reflect the change.
213
     * 
214
     * @param arr the bytecode
215
     * @return the enhanced bytecode
216
     */
217
    public static byte[] patch (byte[] arr) {
218
        if (!isPatched (arr)) return arr;
219
220
        PatchByteCode pc = new PatchByteCode (arr, null);
221
        if (pc.superClassNameAttr > 0) {
222
            // let's patch
223
            int classindex = pc.readU2 (pc.superClassNameAttr + 6);
224
            
225
            writeU2 (pc.getClassFile(), pc.cpEnd + 4, classindex);
226
            
227
            if (pc.initAttr != -1) {
228
                // patch also CONSTANT_Methodref to superclass's <init>
229
                writeU2 (pc.getClassFile (), pc.initAttr + 1, classindex);
230
            }
231
        }
232
233
        if (pc.memberClassAttr > 0) {
234
            // change the access rights of the class itself
235
            if (pc.readU4 (pc.memberClassAttr + 2) != 2) {
236
                throw new IllegalArgumentException ("Size of a attribute " + ATTR_MEMBER + " should be 2"); // NOI18N
237
            }
238
239
            // alternate access rights
240
            int access = pc.readU2 (pc.memberClassAttr + 6);
241
            
242
            int now = pc.readU2 (pc.cpEnd);
243
            
244
            writeU2 (pc.getClassFile (), pc.cpEnd, access);
245
            
246
        }
247
248
        if (pc.memberNameIndex > 0) {
249
            // change access rights of fields
250
            pc.applyMemberAccessChanges ();
251
        }
252
        
253
        return pc.getClassFile ();
254
    }
255
    
256
    
257
    /** Check if the byte code is patched.
258
     * @param arr the bytecode
259
     * @return true if patched
260
     */
261
    private static boolean isPatched (byte[] arr) {
262
        if (arr == null || arr.length < 2) return false;
263
        
264
        int base = arr.length - 2;
265
        if (arr[base + 1] != 'b') return false;
266
        if (arr[base + 0] != 'n') return false;
267
        
268
        //
269
        // ok, looks like enhanced byte code
270
        //
271
        return true;
272
    }
273
    
274
    
275
    
276
    
277
    
278
    
279
    
280
    /** Gets the current byte array of the actual class file.
281
     * @return bytes of the class file
282
     */
283
    private byte[] getClassFile () {
284
        return arr;
285
    }
286
    
287
    /** Creates new contant pool entry representing given class.
288
     * @param c name of the class
289
     * @return index of the entry
290
     */
291
    private int addClass (String s) {
292
        int x = addConstant (s);
293
        
294
        byte[] t = { 7, 0, 0 };
295
        writeU2 (t, 1, x);
296
        
297
        return addPool (t);
298
    }
299
    
300
    /** Adds a new string constant to the constant pool.
301
     * @param s the string to add
302
     * @return index of the constant
303
     */
304
    private int addConstant (String s) {
305
        byte[] t;
306
        
307
        try {
308
            t = s.getBytes("utf-8"); // NOI18N
309
        } catch (java.io.UnsupportedEncodingException ex) {
310
            throw new IllegalStateException ("UTF-8 shall be always supported"); // NOI18N
311
        }
312
        
313
        byte[] add = new byte[t.length + 3];
314
        System.arraycopy (t, 0, add, 3, t.length);
315
        add[0] = 1; // UTF8 contant
316
        writeU2 (add, 1, t.length);
317
        
318
        return addPool (add);
319
    }
320
        
321
    /** Adds this array of bytes as another entry into the constant pool */
322
    private int addPool (byte[] add) {
323
        byte[] res = new byte[arr.length + add.length];
324
     
325
        System.arraycopy (arr, 0, res, 0, cpEnd);
326
        // increments number of objects in contant pool
327
        int index = readU2 (cpCount);
328
        writeU2 (res, cpCount, index + 1);
329
        
330
        // adds the content
331
        System.arraycopy (add, 0, res, cpEnd, add.length);
332
        
333
        // and now add the rest of the original array
334
        System.arraycopy (arr, cpEnd, res, cpEnd + add.length, arr.length - cpEnd);
335
        
336
        arr = res;
337
        
338
        cpEnd += add.length;
339
        atCount += add.length;
340
        atEnd += add.length;
341
        
342
        // the index
343
        return index;
344
    }
345
    
346
    /** Checks whether the code is public.
347
     */
348
    private boolean isPublic () {
349
        int x = readU2 (cpEnd);
350
        
351
        if ((x & 0x0001) != 0) {
352
            return true;
353
        } else {
354
            return false;
355
        }
356
    }
357
    
358
    /** Ensures that the class is public 
359
     * @return true if really patched, false if not
360
     */
361
    private boolean markPublic () {
362
        if (isPublic ()) {
363
            return false;
364
        }
365
        
366
        // make sure ATTR_MEMBER is in constant pool
367
        if (memberNameIndex == -1) {
368
            memberNameIndex = addConstant (ATTR_MEMBER);
369
        }
370
        
371
        int x = readU2 (cpEnd) | 0x0001; // make it public
372
        
373
        byte[] sup = new byte[2];
374
        writeU2 (sup, 0, x);
375
        addAttribute (ATTR_MEMBER, sup);
376
        
377
        return true;
378
    }
379
    
380
    /** Makes method of field public and non final.
381
     * @param name name of the method to make public
382
     * @return true if really changed, false if it already was public
383
     */
384
    private boolean markMemberPublic (String name) {
385
        int constantPoolIndex = ((int[])nameIndexes.get (name))[0];
386
        int patchCount = 0;
387
        boolean modified = false;
388
389
        // make sure ATTR_MEMBER is in constant pool
390
        if (memberNameIndex == -1) {
391
            memberNameIndex = addConstant (ATTR_MEMBER);
392
        }
393
        
394
        int pos = cpEnd;
395
        
396
        pos += 6;
397
        // now add interfaces
398
        pos += 2 * readU2 (pos);
399
        // to add also the integer with interfaces
400
        pos += 2;
401
        
402
        for (int fieldsAndMethods = 0; fieldsAndMethods < 2; fieldsAndMethods++) {
403
            // fields and then methods
404
            int fieldsOrMethods = readU2 (pos);
405
            pos += 2;
406
            
407
            while (fieldsOrMethods-- > 0) {
408
                // check the name
409
                int nameIndex = readU2 (pos + 2);
410
                if (nameIndex == constantPoolIndex) {
411
                    // let's patch
412
                    int access = readU2 (pos);
413
                    if ((access & 0x0001) == 0 || (access & 0x0010) != 0) {
414
                        // is not public or is final
415
                        access = (access | 0x0001) & ~(0x0010 | 0x0002 | 0x0004);
416
417
418
                        // increment the attributes count
419
                        int cnt = readU2 (pos + 6) + 1;
420
421
                        // 
422
                        byte[] res = new byte[arr.length + 2 + 6];
423
424
                        // copy the array before
425
                        System.arraycopy(arr, 0, res, 0, pos + 6);
426
                        // write the new count of attributes
427
                        writeU2 (res, pos + 6, cnt);
428
                        
429
                        // write the attribute itself
430
                        writeU2 (res, pos + 8, memberNameIndex); // name of attribute
431
                        writeU4 (res, pos + 10, 2); // length
432
                        writeU2 (res, pos + 14, access); // data - the "NetBeans" member modifier
433
434
                        // copy the rest
435
                        System.arraycopy(arr, pos + 8, res, pos + 8 + 6 + 2, arr.length - pos - 8);
436
437
                        atEnd += 2 + 6;
438
                        atCount += 2 + 6;
439
440
441
                        arr = res;
442
                        
443
                        modified = true;
444
                    }
445
                        
446
                    patchCount++;
447
                }
448
                
449
                pos += memberSize (pos, null);
450
            }
451
        }
452
        
453
        if (patchCount == 0) {
454
            throw new IllegalArgumentException ("Member " + name + " not found!");
455
        }
456
        
457
        return modified;
458
    }
459
    
460
    
461
    /** Checks all members of the class to find out whether they need patching
462
     * of access rights. If so, patches them.
463
     */
464
    private void applyMemberAccessChanges () {
465
        int[] result = new int[1];
466
        
467
        int pos = cpEnd;
468
        
469
        pos += 6;
470
        // now add interfaces
471
        pos += 2 * readU2 (pos);
472
        // to add also the integer with interfaces
473
        pos += 2;
474
        
475
        for (int fieldsAndMethods = 0; fieldsAndMethods < 2; fieldsAndMethods++) {
476
            // fields and then methods
477
            int fieldsOrMethods = readU2 (pos);
478
            pos += 2;
479
            
480
            while (fieldsOrMethods-- > 0) {
481
                result[0] = -1;
482
                int size = memberSize(pos, result);
483
                if (result[0] != -1) {
484
                    // we will do patching
485
                    
486
                    if (readU4 (result[0] + 2) != 2) {
487
                        throw new IllegalArgumentException ("Size of a attribute " + ATTR_MEMBER + " should be 2"); // NOI18N
488
                    }
489
                    
490
                    // alternate access rights
491
                    int access = readU2 (result[0] + 6);
492
                    writeU2 (arr, pos, access);
493
                }
494
                
495
                pos += size;
496
            }
497
        }
498
    }
499
    
500
    /** Adds an attribute to the class file.
501
     * @param name name of the attribute to add
502
     * @param b the bytes representing the attribute
503
     */
504
    private void addAttribute (String name, byte[] b) {
505
        int index = -1;
506
        if (ATTR_SUPERCLASS.equals (name) && superClassNameIndex > 0) {
507
            index = superClassNameIndex;
508
        } 
509
        
510
        if (ATTR_MEMBER.equals (name) && memberNameIndex > 0) {
511
            index = memberNameIndex;
512
        }
513
        
514
        if (index == -1) {
515
            // register new attribute
516
            index = addConstant (name);
517
        }
518
        
519
        byte[] res = new byte[arr.length + b.length + 6];
520
        
521
        System.arraycopy(arr, 0, res, 0, arr.length);
522
        
523
        writeU2 (res, arr.length, index);
524
        writeU4 (res, arr.length + 2, b.length);
525
        
526
        int begin = arr.length + 6;
527
        System.arraycopy(b, 0, res, begin, b.length);
528
        
529
        atEnd += b.length + 6;
530
        
531
        writeU2 (res, atCount, readU2 (atCount) + 1);
532
        
533
        arr = res;
534
    }
535
    
536
    
537
    /** Gets i-th element from the array.
538
     */
539
    private int get (int pos) {
540
        if (pos >= arr.length) {
541
            throw new ArrayIndexOutOfBoundsException ("Size: " + arr.length + " index: " + pos);
542
        }
543
        
544
        int x = arr[pos];
545
        return x >= 0 ? x : 256 + x;
546
    }
547
548
    /** Scans the file to find out important possitions
549
     * @return size of the bytecode
550
     */
551
    private void scan () {
552
        if (get (0) != 0xCA && get (1) != 0xFE && get (2) != 0xBA && get (3) != 0xBE) {
553
            throw new IllegalStateException ("Not a class file!"); // NOI18N
554
        }
555
        
556
        int pos = 10;
557
        // count of items in CP is here
558
        cpCount = 8;
559
        
560
        int cp = readU2 (8);
561
        for (int[] i = { 1 }; i[0] < cp; i[0]++) {
562
            // i[0] can be incremented in constantPoolSize
563
            int len = constantPoolSize (pos, i);
564
            pos += len;
565
        }
566
        
567
        // list item in constant pool
568
        cpEnd = pos;
569
        
570
        pos += 6;
571
        // now add interfaces
572
        pos += 2 * readU2 (pos);
573
        // to add also the integer with interfaces
574
        pos += 2;
575
        
576
        // fields
577
        int fields = readU2 (pos);
578
        pos += 2;
579
        while (fields-- > 0) {
580
            pos += memberSize (pos, null);
581
        }
582
        
583
        int methods = readU2 (pos);
584
        pos += 2;
585
        while (methods-- > 0) {
586
            pos += memberSize (pos, null);
587
        }
588
589
        // count of items in Attributes is here
590
        
591
        int[] memberAccess = { -1 };
592
        
593
        atCount = pos;
594
        int attrs = readU2 (pos);
595
        pos += 2;
596
        while (attrs-- > 0) {
597
            pos += attributeSize (pos, memberAccess);
598
        }
599
        
600
        if (memberAccess[0] != -1) {
601
            // we need to update the name of class
602
            memberClassAttr = memberAccess[0];
603
        }
604
605
        // end of attributes
606
        atEnd = pos;
607
    }
608
    
609
    private int readU2 (int pos) {
610
        int b1 = get (pos);
611
        int b2 = get (pos + 1);
612
        
613
        return b1 * 256 + b2;
614
    }
615
    
616
    private int readU4 (int pos) {
617
        return readU2 (pos) * 256 * 256 + readU2 (pos + 2);
618
    }
619
620
    private static void writeU2 (byte[] arr, int pos, int value) {
621
        int v1 = (value & 0xff00) >> 8;
622
        int v2 = value & 0xff;
623
        
624
        if (v1 < 0) v1 += 256;
625
        if (v2 < 0) v2 += 256;
626
        
627
        arr[pos] = (byte)v1;
628
        arr[pos + 1] = (byte)v2;
629
    }
630
    
631
    private static void writeU4 (byte[] arr, int pos, int value) {
632
        writeU2 (arr, pos, (value & 0xff00) >> 16);
633
        writeU2 (arr, pos + 2, value & 0x00ff);
634
    }
635
    
636
    /** @param pos position to read from
637
     * @param cnt[0] index in the pool that we are now reading
638
     */
639
    private int constantPoolSize (int pos, int[] cnt) {
640
        switch (get (pos)) {
641
            case 7: // CONSTANT_Class 
642
            case 8: // CONSTANT_String 
643
                return 3;
644
                
645
            case 12: // CONSTANT_NameAndType
646
                // check for <init> and ()V invocation
647
                int nameIndex = readU2 (pos + 1);
648
                if (nameIndex == initIndex) {
649
                    int descriptorIndex = readU2 (pos + 3);
650
                    if (descriptorIndex == initIndexType) {
651
                        if (initNameTypeIndex > 0 && initNameTypeIndex != cnt[0]) {
652
                            throw new IllegalArgumentException ("Second initialization of name type index"); // NOI18N
653
                        }
654
                        initNameTypeIndex = cnt[0];
655
                    }
656
                }
657
                return 5;
658
                
659
            case 10: // CONSTANT_Methodref 
660
                // special check for <init> invocation
661
                int classname = readU2 (pos + 1);
662
                int nameAndType = readU2 (pos + 3);
663
                if (nameAndType == initNameTypeIndex) {
664
                    // found call to <init>
665
                    int superclass = readU2 (cpEnd + 4);
666
                    
667
                    if (superclass == classname) {
668
                        // it is call to our superclass
669
                        if (initAttr > 0 && initAttr != pos) {
670
                            throw new IllegalStateException ("Second initialization of position of <init> invocation"); // NOI18N
671
                        }
672
                        initAttr = pos;
673
                    }
674
                }
675
                return 5;
676
                
677
            case 9: // CONSTANT_Fieldref 
678
            case 11: // CONSTANT_InterfaceMethodref 
679
            case 3: // CONSTANT_Integer
680
            case 4: // CONSTANT_Float
681
                return 5;
682
                
683
            case 5: // CONSTANT_Long
684
            case 6: // CONSTANT_Double
685
                // after long and double the next entry in CP is unusable
686
                cnt[0]++;
687
                return 9;
688
            case 1: // CONSTANT_Utf8
689
                int len = readU2 (pos + 1);
690
691
                if (compareUtfEntry (BYTE_INIT, pos)) {
692
                    if (initIndex > 0 && initIndex != cnt[0]) {
693
                        throw new IllegalArgumentException ("Second initialization of " + ATTR_INIT); // NOI18N
694
                    }
695
                    initIndex = cnt[0];
696
                }
697
698
                if (compareUtfEntry (BYTE_INIT_TYPE, pos)) {
699
                    if (initIndexType > 0 && initIndexType != cnt[0]) {
700
                        throw new IllegalArgumentException ("Second initialization of " + ATTR_INIT_TYPE); // NOI18N
701
                    }
702
                    initIndexType = cnt[0];
703
                }
704
                
705
                if (compareUtfEntry (BYTE_SUPERCLASS, pos)) {
706
                    // we have found the attribute
707
                    if (superClassNameIndex > 0 && superClassNameIndex != cnt[0]) {
708
                        throw new IllegalStateException (ATTR_SUPERCLASS + " registered for the second time!"); // NOI18N
709
                    }
710
711
                    superClassNameIndex = cnt[0];
712
                }
713
714
                if (compareUtfEntry (BYTE_MEMBER, pos)) {
715
                    // we have found the attribute
716
                    if (memberNameIndex > 0 && memberNameIndex != cnt[0]) {
717
                        throw new IllegalStateException (ATTR_MEMBER + " registered for the second time!"); // NOI18N
718
                    }
719
720
                    memberNameIndex = cnt[0];
721
                }
722
                    
723
                if (nameIndexes != null) {
724
                    // check the name in the table
725
                    String s;
726
                    try {
727
                        s = new String (arr, pos + 3, len, "utf-8"); // NOI18N
728
                    } catch (UnsupportedEncodingException ex) {
729
                        throw new IllegalStateException ("utf-8 is always supported"); // NOI18N
730
                    }
731
                    
732
                    int[] index = (int[])nameIndexes.get (s);
733
                    if (index != null) {
734
                        index[0] = cnt[0];
735
                    }
736
                }
737
738
                // ok, exit
739
                return len + 3;
740
            default:
741
                throw new IllegalStateException ("Unknown pool type: " + get (pos)); // NOI18N
742
        }
743
    }
744
    
745
    private int memberSize (int pos, int[] containsPatchAttribute) {
746
        int s = 8;
747
        int name = readU2 (pos + 2);
748
        
749
        int cnt = readU2 (pos + 6);
750
        
751
        while (cnt-- > 0) {
752
            s += attributeSize (pos + s, containsPatchAttribute);
753
        }
754
        return s;
755
    }
756
    
757
    /** Into the containsPatchAttribute (if not null) it adds the
758
     * index of structure of attribute ATTR_MEMBER.
759
     */
760
    private int attributeSize (int pos, int[] containsPatchAttribute) {
761
        // index to the name attr
762
        int name = readU2 (pos);
763
        
764
        if (name == superClassNameIndex) {
765
            if (superClassNameAttr > 0 && superClassNameAttr != pos) {
766
                throw new IllegalStateException ("Two attributes with name " + ATTR_SUPERCLASS); // NOI18N
767
            }
768
769
            // we found the attribute
770
            superClassNameAttr = pos;
771
        }
772
            
773
        if (name == memberNameIndex && containsPatchAttribute != null) {
774
            if (containsPatchAttribute[0] != -1) {
775
                throw new IllegalStateException ("Second attribute " + ATTR_MEMBER); // NOI18N
776
            }
777
            containsPatchAttribute[0] = pos;
778
        }
779
        
780
        int len = readU4 (pos + 2);
781
        return len + 6;
782
    }
783
    
784
    
785
    /** Compares arrays.
786
     */
787
    private boolean compareUtfEntry (byte[] pattern, int pos) {
788
        int len = readU2 (pos + 1);
789
        
790
        if (pattern.length != len) {
791
            return false;
792
        }
793
        
794
        int base = pos + 3;
795
        // we are searching for an attribute with given name
796
        for (int i = 0; i < len; i++) {
797
            if (pattern[i] != arr[base + i]) {
798
                // regular exit
799
                return false;
800
            }
801
        }
802
        
803
        return true;
804
    }        
805
}
(-)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 / +3 lines)
Lines 121-128 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
    StartLog.logStart ("Forwarding to topThreadGroup"); // NOI18N
126
    tg.start ();
127
    tg.start ();
127
  }
128
  }
128
129
Lines 356-362 Link Here
356
  /**
357
  /**
357
  * @exception SecurityException if it is called multiple times
358
  * @exception SecurityException if it is called multiple times
358
  */
359
  */
359
  public static void main(String[] args) throws SecurityException {
360
  static void start (String[] args) throws SecurityException {
360
    long time = System.currentTimeMillis();
361
    long time = System.currentTimeMillis();
361
    
362
    
362
    StartLog.logEnd ("Forwarding to topThreadGroup"); // NOI18N
363
    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], Collections.EMPTY_SET);
60
    private SystemClassLoader classLoader = new SystemClassLoader(new ClassLoader[] {ModuleManager.class.getClassLoader()}, Collections.EMPTY_SET);
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, modules);
243
            nue = new SystemClassLoader(parentCLs, modules);
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], Collections.EMPTY_SET);
246
            nue = new SystemClassLoader(new ClassLoader[] {ModuleManager.class.getClassLoader()}, Collections.EMPTY_SET);
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/cfg-unit.xml (+1 lines)
Lines 57-62 Link Here
57
                <include name="org/netbeans/core/lookup/*Test.class"/>
57
                <include name="org/netbeans/core/lookup/*Test.class"/>
58
                <include name="org/netbeans/core/lookup/*Test?.class"/>
58
                <include name="org/netbeans/core/lookup/*Test?.class"/>
59
                <exclude name="org/netbeans/core/lookup/InstanceDataObjectModuleTest4.class"/>
59
                <exclude name="org/netbeans/core/lookup/InstanceDataObjectModuleTest4.class"/>
60
                <include name="org/netbeans/PatchByteCodeTest.class"/>
60
            </patternset>
61
            </patternset>
61
        </testset>
62
        </testset>
62
    </testbag>
63
    </testbag>
(-)nb_all/core/test/unit/src/org/netbeans/PatchByteCodeTest.java (+194 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 junit.framework.AssertionFailedError;
17
import junit.textui.TestRunner;
18
import org.netbeans.junit.*;
19
import java.io.InputStream;
20
import java.lang.reflect.*;
21
22
/** Test patching of openide.jar byte code for compatibility.
23
 * @author Jaroslav Tulach
24
 */
25
public class PatchByteCodeTest extends NbTestCase {
26
    
27
    public PatchByteCodeTest(String name) {
28
        super(name);
29
    }
30
    
31
    public static void main(String[] args) {
32
        TestRunner.run(new NbTestSuite(PatchByteCodeTest.class));
33
    }
34
    
35
    protected void setUp() throws Exception {
36
        super.setUp();
37
    }
38
39
    public void testBeanTreeViewLoad () throws Exception {
40
        checkPatching (
41
            "org.openide.explorer.view.BeanTreeView", 
42
            "data/BeanTreeView.clazz",
43
            null
44
        );
45
    }
46
47
    public void testCompilerGroupLoad () throws Exception {
48
        checkPatching (
49
            "org.openide.compiler.CompilerGroup", 
50
            "data/CompilerGroup.clazz",
51
            null
52
        );
53
        
54
        InputStream is = getClass ().getResourceAsStream ("data/CompilerGroup.clazz");
55
        assertNotNull ("Class has not been found", is);
56
        
57
        byte[] arr = new byte[is.available ()];
58
        int l = is.read (arr);
59
        assertEquals ("Read exactly as much as expected", l, arr.length);
60
        
61
        
62
        byte[] res = PatchByteCode.enhance(arr, null, new String[] { "addCompilerListener", "removeCompilerListener" } );
63
        PatchClassLoader loader = new PatchClassLoader ("org.openide.compiler.CompilerGroup", res, ClassLoader.getSystemClassLoader());
64
        
65
        Class c = loader.loadClass ("org.openide.compiler.CompilerGroup");
66
        
67
        Method m = c.getDeclaredMethod("addCompilerListener", new Class[] { org.openide.compiler.CompilerListener.class });
68
        assertTrue ("Is not final", !Modifier.isFinal (m.getModifiers ()));
69
        
70
        m = c.getDeclaredMethod("removeCompilerListener", new Class[] { org.openide.compiler.CompilerListener.class });
71
        assertTrue ("Is not final", !Modifier.isFinal (m.getModifiers ()));
72
    }
73
    
74
    public void testClassCanBeAlsoInstantiated () throws Exception {
75
        Class c = checkPatching (
76
            Sample.class.getName (),
77
            "Sample.class",
78
            "java.lang.Throwable"
79
        );
80
        
81
        c.newInstance ();
82
    }
83
    
84
    public void testPatchingOfFieldsAndMethodsToPublicAndNonFinal () throws Exception {
85
        InputStream is = getClass ().getResourceAsStream ("Sample.class");
86
        assertNotNull ("Class has not been found", is);
87
        
88
        byte[] arr = new byte[is.available ()];
89
        int l = is.read (arr);
90
        assertEquals ("Read exactly as much as expected", l, arr.length);
91
92
        
93
        
94
        byte[] res = PatchByteCode.enhance(arr, null, new String[] { "member", "field", "method", "staticmethod" } );
95
        PatchClassLoader loader = new PatchClassLoader (Sample.class.getName (), res, ClassLoader.getSystemClassLoader());
96
        
97
        Class c = loader.loadClass (Sample.class.getName ());
98
99
        assertTrue ("Class should be public", Modifier.isPublic (c.getModifiers()));
100
101
        Method m = c.getDeclaredMethod("method", new Class[0]);
102
        assertNotNull ("Mehtod method is there", m);
103
        assertTrue ("And is public", Modifier.isPublic (m.getModifiers()));
104
        assertTrue ("And is not final", !Modifier.isFinal(m.getModifiers ()));
105
        assertTrue ("And is not static", !Modifier.isStatic(m.getModifiers()));
106
        assertTrue ("And is not synchronzied", !Modifier.isSynchronized(m.getModifiers()));
107
        
108
        m = c.getDeclaredMethod("member", new Class[] { Object.class });
109
        assertNotNull ("Member method is there", m);
110
        assertTrue ("And is public", Modifier.isPublic (m.getModifiers()));        
111
        assertTrue ("And is not final", !Modifier.isFinal(m.getModifiers ()));
112
        assertTrue ("And is not static", !Modifier.isStatic(m.getModifiers()));
113
        assertTrue ("And is synchronzied", Modifier.isSynchronized(m.getModifiers()));
114
        
115
        m = c.getDeclaredMethod("staticmethod", new Class[] { });
116
        assertNotNull ("Member method is there", m);
117
        assertTrue ("And is public", Modifier.isPublic (m.getModifiers()));        
118
        assertTrue ("And is not final", !Modifier.isFinal(m.getModifiers ()));
119
        assertTrue ("And is not static", Modifier.isStatic(m.getModifiers()));
120
        assertTrue ("And is not synchronzied", !Modifier.isSynchronized(m.getModifiers()));
121
        
122
        java.lang.reflect.Field f;
123
        
124
        f = c.getDeclaredField("member");
125
        assertNotNull ("Really exists", f);
126
        assertTrue ("Is public", Modifier.isPublic (f.getModifiers ()));
127
        assertTrue ("Is not final", !Modifier.isFinal (f.getModifiers ()));
128
        assertTrue ("Is static", Modifier.isStatic (f.getModifiers ()));
129
        
130
        f = c.getDeclaredField("field");
131
        assertNotNull ("Really exists", f);
132
        assertTrue ("Is public", Modifier.isPublic (f.getModifiers ()));
133
        assertTrue ("Is not final", !Modifier.isFinal (f.getModifiers ()));
134
        assertTrue ("Is static", !Modifier.isStatic (f.getModifiers ()));
135
        
136
    }
137
    
138
        
139
    private Class checkPatching (
140
        String className, String resource, String superclass
141
    ) throws Exception {
142
        if (superclass == null) {
143
            superclass = PatchByteCodeTest.class.getName ();
144
        }
145
        
146
        InputStream is = getClass ().getResourceAsStream (resource);
147
        assertNotNull ("Resource has been found " + resource, is);
148
        
149
        byte[] arr = new byte[is.available ()];
150
        int l = is.read (arr);
151
        assertEquals ("Read exactly as much as expected", l, arr.length);
152
        
153
        byte[] res = PatchByteCode.enhance(arr, superclass.replace ('.', '/'));
154
        PatchClassLoader loader = new PatchClassLoader (className, res);
155
156
        Class c = loader.loadClass (className);
157
        
158
        assertEquals (
159
            "Superclass changed appropriately", 
160
            superclass,
161
            c.getSuperclass().getName ()
162
        );
163
        
164
        return c;
165
    }        
166
    
167
    
168
    private static final class PatchClassLoader extends ClassLoader {
169
        private String res;
170
        private byte[] arr;
171
        
172
        public PatchClassLoader (String res, byte[] arr) {
173
            this (res, arr, PatchClassLoader.class.getClassLoader ());
174
        }
175
        
176
        public PatchClassLoader (String res, byte[] arr, ClassLoader c) {
177
            super (c);
178
            
179
            this.res = res;
180
            this.arr = arr;
181
        }
182
        
183
        protected synchronized Class loadClass(String name, boolean resolve) 
184
        throws ClassNotFoundException {
185
            if (res.equals (name)) {
186
                byte[] patch = PatchByteCode.patch(arr);
187
                
188
                return defineClass (name, patch, 0, patch.length);
189
            } else {
190
                return super.loadClass (name, resolve);
191
            }
192
        }
193
    }
194
}
(-)nb_all/core/test/unit/src/org/netbeans/Sample.java (+40 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
import java.lang.reflect.*;
21
22
/** Sample class to pass to PatchByteCodeTest to see what changes can be done.
23
 */
24
class Sample extends Object {
25
    private static Object member;
26
    private final Object field = null;
27
    
28
    public Sample () {
29
    }
30
31
    protected synchronized void member (Object x) {
32
    }
33
34
    private final Object method () {
35
        return null;
36
    }
37
38
    protected static void staticmethod () {
39
    }
40
}
(-)nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbEnhanceClass.java (+217 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.nbbuild;
15
16
import java.io.File;
17
import java.io.FileInputStream;
18
import java.io.FileOutputStream;
19
import java.io.IOException;
20
import java.net.URL;
21
import java.net.URLClassLoader;
22
import java.util.ArrayList;
23
import java.util.Iterator;
24
// IMPORTANT! You may need to mount ant.jar before this class will
25
// compile. So mount the JAR modules/ext/ant-1.4.1.jar (NOT modules/ant.jar)
26
// from your IDE installation directory in your Filesystems before
27
// continuing to ensure that it is in your classpath.
28
29
import org.apache.tools.ant.*;
30
import org.apache.tools.ant.types.*;
31
32
/**
33
 * @author Jaroslav Tulach
34
 */
35
public class NbEnhanceClass extends Task {
36
    /* Path to library containing the patch method */
37
    private File patchLibrary;
38
    public void setLibrary (File f) {
39
        patchLibrary = f;
40
    }
41
    
42
    /* Name of class with patch method */
43
    private String patchClass = "org.netbeans.PatchByteCode";
44
    public void setPatchClass (String f) {
45
        patchClass = f;
46
    }
47
    
48
    /** Name of the method to call. Must have byte[] array argument and return the same
49
     */
50
    private String enhanceMethod = "enhance";
51
    public void setEnhanceMethod (String f) {
52
        enhanceMethod = f;
53
    }
54
    
55
    /* Base dir to find classes relative to */
56
    private File basedir;
57
    public void setBasedir (File f) {
58
        basedir = f;
59
    }
60
    
61
    /* The class to change its super class and the value of the super class.
62
     */
63
    public static class Patch {
64
        String clazz;
65
        String nbSuperClass;
66
        ArrayList members;
67
        
68
        
69
        /** Class in form of java/lang/Object */
70
        public void setClass (String s) {
71
            clazz = s;
72
        }
73
        /** Class in form of java/lang/Object */
74
        public void setSuper (String s) {
75
            nbSuperClass = s;
76
        }
77
        
78
        public Object createMember () {
79
            Member m = new Member();
80
            if (members == null) {
81
                members = new ArrayList ();
82
            }
83
            members.add (m);
84
            return m;
85
        }
86
        
87
        public static final class Member extends Object {
88
            String name;
89
            
90
            public void setName (String s) {
91
                name = s;
92
            }
93
        }
94
    }
95
    private ArrayList patches = new ArrayList (); // List<Nestme>
96
    public Patch createPatch () {
97
        Patch n = new Patch ();
98
        patches.add(n);
99
        return n;
100
    }
101
    
102
    
103
    public void execute() throws BuildException {
104
        if (basedir == null) {
105
            throw new BuildException ("Attribute basedir must be specified");
106
        }
107
        
108
        if (patches.isEmpty()) {
109
            // no work
110
            return;
111
        }
112
        
113
        //
114
        // Initialize the method
115
        //
116
        
117
        ClassLoader cl;
118
        if (patchLibrary == null) {
119
            log ("Loading patch class from task loader");
120
            cl = getClass ().getClassLoader();
121
        } else {
122
            try {
123
                cl = new URLClassLoader (new URL[] { patchLibrary.toURL() });
124
            } catch (java.net.MalformedURLException ex) {
125
                throw new BuildException (ex);
126
            }
127
        }
128
        
129
        java.lang.reflect.Method m;
130
        try {
131
            Class c = cl.loadClass (patchClass);
132
            m = c.getMethod(enhanceMethod, new Class[] { byte[].class, String.class, String[].class });
133
            if (m.getReturnType() != byte[].class) {
134
                throw new BuildException ("Method does not return byte[]: " + m);
135
            }
136
        } catch (Exception ex) {
137
            throw new BuildException ("Cannot initialize class " + patchClass + " and method " + enhanceMethod, ex);
138
        }
139
            
140
        /*
141
        try {
142
            log ("Testing method " + m);
143
            byte[] res = (byte[])m.invoke (null, new Object[] { new byte[0], "someString" });
144
        } catch (Exception ex) {
145
            throw new BuildException ("Exception during test invocation of the method", ex);
146
        }
147
         */
148
            
149
        //
150
        // Ok we have the method and we can do the patching
151
        //
152
        
153
        Iterator it = patches.iterator();
154
        while (it.hasNext()) {
155
            Patch p = (Patch)it.next ();
156
            
157
            if (p.clazz == null) {
158
                throw new BuildException ("Attribute class must be specified");
159
            }
160
            
161
            File f = new File (basedir, p.clazz + ".class");
162
            if (!f.exists ()) {
163
                throw new BuildException ("File " + f + " for class " + p.clazz + " does not exists");
164
            }
165
            
166
            byte[] arr = new byte[(int)f.length()];
167
            try {
168
                FileInputStream is = new FileInputStream (f);
169
                if (arr.length != is.read (arr)) {
170
                    throw new BuildException ("Not all bytes read");
171
                }
172
                is.close ();
173
            } catch (IOException ex) {
174
                throw new BuildException ("Cannot read file " + f, ex);
175
            }
176
            
177
            String[] members;
178
            if (p.members != null) {
179
                members = new String[p.members.size ()];
180
                Iterator myIt = p.members.iterator();
181
                int i = 0;
182
                while (myIt.hasNext ()) {
183
                    members[i++] = ((Patch.Member)myIt.next ()).name;
184
                }
185
            } else {
186
                members = null;
187
            }
188
                
189
             
190
            byte[] out;
191
            try {
192
                out = (byte[])m.invoke (null, new Object[] { arr, p.nbSuperClass, members });
193
                if (out == null) {
194
                    // no patching needed
195
                    continue;
196
                }
197
            } catch (Exception ex) {
198
                throw new BuildException (ex);
199
            }
200
201
            if (p.nbSuperClass != null) {
202
                log ("Enhanced " + f + " to have alternate superclass " + p.nbSuperClass + " and be public");
203
            } else {
204
                log ("Enhanced " + f + " to be public");
205
            }
206
            
207
            try {
208
                FileOutputStream os = new FileOutputStream (f);
209
                os.write (out);
210
                os.close ();
211
            } catch (IOException ex) {
212
                throw new BuildException ("Cannot overwrite file " + f, ex);
213
            }
214
        }
215
    }
216
    
217
}
(-)nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchClass.java (+191 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.nbbuild;
15
16
import java.io.File;
17
import java.io.FileInputStream;
18
import java.io.FileOutputStream;
19
import java.io.IOException;
20
import java.net.URL;
21
import java.net.URLClassLoader;
22
import java.util.ArrayList;
23
import java.util.Iterator;
24
import java.util.jar.JarFile;
25
// IMPORTANT! You may need to mount ant.jar before this class will
26
// compile. So mount the JAR modules/ext/ant-1.4.1.jar (NOT modules/ant.jar)
27
// from your IDE installation directory in your Filesystems before
28
// continuing to ensure that it is in your classpath.
29
30
import org.apache.tools.ant.*;
31
import org.apache.tools.ant.types.*;
32
33
/**
34
 * @author Jaroslav Tulach
35
 */
36
public class NbPatchClass extends Task {
37
    /* Path to library containing the patch method */
38
    private File patchLibrary;
39
    public void setLibrary (File f) {
40
        patchLibrary = f;
41
    }
42
    
43
    /* Name of class with patch method */
44
    private String patchClass = "org.netbeans.PatchByteCode";
45
    public void setPatchClass (String f) {
46
        patchClass = f;
47
    }
48
    
49
    /** Name of the method to call. Must have byte[] array argument and return the same
50
     */
51
    private String patchMethod = "patch";
52
    public void setPatchMethod (String f) {
53
        patchMethod = f;
54
    }
55
    
56
    /** Source JAR to extract.
57
     */
58
    private File sourceJar;
59
    public void setSource (File f) {
60
        sourceJar = f;
61
    }
62
    
63
    /* Base dir to find classes relative to */
64
    private File targetdir;
65
    public void setTargetdir (File f) {
66
        targetdir = f;
67
    }
68
    
69
    public void execute() throws BuildException {
70
        if (targetdir == null) {
71
            throw new BuildException ("Attribute targetdir must be specified");
72
        }
73
74
        if (sourceJar == null) {
75
            throw new BuildException ("Attribute source must be specified");
76
        }
77
        
78
        
79
        JarFile jar;
80
        
81
        try {
82
            jar = new JarFile (sourceJar);
83
        } catch (IOException ex) {
84
            throw new BuildException ("Problem initializing file " + sourceJar, ex);
85
        }
86
        
87
        //
88
        // Initialize the method
89
        //
90
        
91
        log ("Initilalizing patching " + patchClass + '.' + patchMethod);
92
        
93
        ClassLoader cl;
94
        if (patchLibrary == null) {
95
            log ("Loading patch class from task loader");
96
            cl = getClass ().getClassLoader();
97
        } else {
98
            try {
99
                cl = new URLClassLoader (new URL[] { patchLibrary.toURL() });
100
            } catch (java.net.MalformedURLException ex) {
101
                throw new BuildException (ex);
102
            }
103
        }
104
        
105
        java.lang.reflect.Method m;
106
        try {
107
            Class c = cl.loadClass (patchClass);
108
            m = c.getMethod(patchMethod, new Class[] { byte[].class });
109
            if (m.getReturnType() != byte[].class) {
110
                throw new BuildException ("Method does not return byte[]: " + m);
111
            }
112
        } catch (Exception ex) {
113
            throw new BuildException ("Cannot initialize class " + patchClass + " and method " + patchMethod, ex);
114
        }
115
            
116
        /*
117
        try {
118
            log ("Testing method " + m);
119
            byte[] res = (byte[])m.invoke (null, new Object[] { new byte[0], "someString" });
120
        } catch (Exception ex) {
121
            throw new BuildException ("Exception during test invocation of the method", ex);
122
        }
123
         */
124
            
125
        //
126
        // Ok we have the method and we can do the patching
127
        //
128
        
129
        java.util.Enumeration it = jar.entries();
130
        while (it.hasMoreElements()) {
131
            java.util.jar.JarEntry e = (java.util.jar.JarEntry)it.nextElement ();
132
133
            int size = (int)e.getSize();
134
            if (size <= 4) {
135
                // not interesting entry
136
                continue;
137
            }
138
            
139
            byte[] arr = new byte[size];
140
            
141
            try {
142
                java.io.InputStream is = jar.getInputStream(e);
143
                
144
                int indx = 0;
145
                while (indx < arr.length) {
146
                    int read = is.read (arr, indx, arr.length - indx);
147
                    if (read == -1) {
148
                        throw new BuildException("Entry: " + e.getName () + " size should be: " + size + " but was read just: " + indx);
149
                    }
150
                    indx += read;
151
                }
152
            } catch (IOException ex) {
153
                throw new BuildException (ex);
154
            }
155
            
156
            byte[] original = (byte[])arr.clone ();
157
            byte[] out;
158
            try {
159
                out = (byte[])m.invoke (null, new Object[] { arr });
160
            } catch (java.lang.reflect.InvocationTargetException ex) {
161
                throw new BuildException (ex.getTargetException());
162
            } catch (Exception ex) {
163
                throw new BuildException (ex);
164
            }
165
            
166
            if (java.util.Arrays.equals (original, out)) {
167
                // no patching, go on
168
                continue;
169
            }
170
171
            File f = new File (targetdir, e.getName ().replace ('/', File.separatorChar));
172
            if (f.exists () && f.lastModified() > sourceJar.lastModified ()) {
173
                // if the file is newer
174
                continue;
175
            }
176
            
177
            f.getParentFile().mkdirs();
178
            
179
            log ("Writing patched file " + f);
180
            
181
            try {
182
                FileOutputStream os = new FileOutputStream (f);
183
                os.write (out);
184
                os.close ();
185
            } catch (IOException ex) {
186
                throw new BuildException ("Cannot write file " + f, ex);
187
            }
188
        }
189
    }
190
    
191
}
(-)nb_all/nbbuild/antsrc/org/netbeans/nbbuild/NbPatchSuperClass.java (-186 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.nbbuild;
15
16
import java.io.File;
17
import java.io.FileInputStream;
18
import java.io.FileOutputStream;
19
import java.io.IOException;
20
import java.net.URL;
21
import java.net.URLClassLoader;
22
import java.util.ArrayList;
23
import java.util.Iterator;
24
// IMPORTANT! You may need to mount ant.jar before this class will
25
// compile. So mount the JAR modules/ext/ant-1.4.1.jar (NOT modules/ant.jar)
26
// from your IDE installation directory in your Filesystems before
27
// continuing to ensure that it is in your classpath.
28
29
import org.apache.tools.ant.*;
30
import org.apache.tools.ant.types.*;
31
32
/**
33
 * @author Jaroslav Tulach
34
 */
35
public class NbPatchSuperClass extends Task {
36
    /* Path to library containing the patch method */
37
    private File patchLibrary;
38
    public void setPatchLibrary (File f) {
39
        patchLibrary = f;
40
    }
41
    
42
    /* Name of class with patch method */
43
    private String patchClass = "org.netbeans.PatchByteCode";
44
    public void setPatchClass (String f) {
45
        patchClass = f;
46
    }
47
    
48
    /** Name of the method to call. Must have byte[] array argument and return the same
49
     */
50
    private String patchMethod = "enhance";
51
    public void setPatchMethod (String f) {
52
        patchMethod = f;
53
    }
54
    
55
    /* Base dir to find classes relative to */
56
    private File basedir;
57
    public void setBasedir (File f) {
58
        basedir = f;
59
    }
60
    
61
    /* The class to change its super class and the value of the super class.
62
     */
63
    public static class Patch {
64
        String clazz;
65
        String nbSuperClass;
66
        /** Class in form of java/lang/Object */
67
        public void setClass (String s) {
68
            clazz = s;
69
        }
70
        /** Class in form of java/lang/Object */
71
        public void setSuper (String s) {
72
            nbSuperClass = s;
73
        }
74
    }
75
    private ArrayList patches = new ArrayList (); // List<Nestme>
76
    public Patch createPatch () {
77
        Patch n = new Patch ();
78
        patches.add(n);
79
        return n;
80
    }
81
    
82
    
83
    public void execute() throws BuildException {
84
        if (basedir == null) {
85
            throw new BuildException ("Attribute basedir must be specified");
86
        }
87
        
88
        if (patches.isEmpty()) {
89
            // no work
90
            return;
91
        }
92
        
93
        //
94
        // Initialize the method
95
        //
96
        
97
        log ("Initilalizing patching " + patchClass + '.' + patchMethod);
98
        
99
        ClassLoader cl;
100
        if (patchLibrary == null) {
101
            log ("Loading patch class from task loader");
102
            cl = getClass ().getClassLoader();
103
        } else {
104
            try {
105
                cl = new URLClassLoader (new URL[] { patchLibrary.toURL() });
106
            } catch (java.net.MalformedURLException ex) {
107
                throw new BuildException (ex);
108
            }
109
        }
110
        
111
        java.lang.reflect.Method m;
112
        try {
113
            Class c = cl.loadClass (patchClass);
114
            m = c.getMethod(patchMethod, new Class[] { byte[].class, String.class });
115
            if (m.getReturnType() != byte[].class) {
116
                throw new BuildException ("Method does not return byte[]: " + m);
117
            }
118
        } catch (Exception ex) {
119
            throw new BuildException ("Cannot initialize class " + patchClass + " and method " + patchMethod, ex);
120
        }
121
            
122
        /*
123
        try {
124
            log ("Testing method " + m);
125
            byte[] res = (byte[])m.invoke (null, new Object[] { new byte[0], "someString" });
126
        } catch (Exception ex) {
127
            throw new BuildException ("Exception during test invocation of the method", ex);
128
        }
129
         */
130
            
131
        //
132
        // Ok we have the method and we can do the patching
133
        //
134
        
135
        Iterator it = patches.iterator();
136
        while (it.hasNext()) {
137
            Patch p = (Patch)it.next ();
138
            
139
            if (p.clazz == null) {
140
                throw new BuildException ("Attribute class must be specified");
141
            }
142
            
143
            File f = new File (basedir, p.clazz + ".class");
144
            if (!f.exists ()) {
145
                throw new BuildException ("File " + f + " for class " + p.clazz + " does not exists");
146
            }
147
            
148
            byte[] arr = new byte[(int)f.length()];
149
            try {
150
                FileInputStream is = new FileInputStream (f);
151
                if (arr.length != is.read (arr)) {
152
                    throw new BuildException ("Not all bytes read");
153
                }
154
                is.close ();
155
            } catch (IOException ex) {
156
                throw new BuildException ("Cannot read file " + f, ex);
157
            }
158
             
159
            byte[] out;
160
            try {
161
                out = (byte[])m.invoke (null, new Object[] { arr, p.nbSuperClass });
162
                if (out == null) {
163
                    // no patching needed
164
                    continue;
165
                }
166
            } catch (Exception ex) {
167
                throw new BuildException (ex);
168
            }
169
170
            if (p.nbSuperClass != null) {
171
                log ("Patch applied to " + f + " to have alternate superclass " + p.nbSuperClass + " and be public");
172
            } else {
173
                log ("Patch applied to " + f + " to be public");
174
            }
175
            
176
            try {
177
                FileOutputStream os = new FileOutputStream (f);
178
                os.write (out);
179
                os.close ();
180
            } catch (IOException ex) {
181
                throw new BuildException ("Cannot overwrite file " + f, ex);
182
            }
183
        }
184
    }
185
    
186
}
(-)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 (-64 / +117 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="enhanceclass" classname="org.netbeans.nbbuild.NbEnhanceClass" 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
    <enhanceclass basedir="src" library="../core/netbeans/lib/ext/boot.jar" >
115
      <switch name="compat" on="true"/>
110
            <!-- changes the superclass because there is a clash in return types of two methods -->
116
      <!-- For efficiency and clarity and safety, we explicitly -->
111
	    <patch class="org/openide/util/actions/SystemAction" super="org/openide/util/actions/$$SystemAction$$Patch$$" /> 
117
      <!-- list all files known to need preprocessing. -->
112
            <!-- changes superclass to one that implements Node.Cookie -->
118
      <include name="org/openide/loaders/DataLoaderPool.java"/>
113
	    <patch class="org/openide/filesystems/Repository" super="org/openide/filesystems/$$Repository$$Patch$$" /> 
119
      <include name="org/openide/loaders/MultiDataObject.java"/>
114
            
120
      <include name="org/openide/nodes/AbstractNode.java"/>
115
            <!-- just make some class members public -->
121
      <include name="org/openide/compiler/CompilerGroup.java"/>
116
	    <patch class="org/openide/nodes/AbstractNode" > 
122
      <include name="org/openide/compiler/ExternalCompiler.java"/>
117
                <!-- make following member public -->
123
      <include name="org/openide/util/actions/SystemAction.java"/>
118
                <member name="getCookieSet" />
124
      <include name="org/openide/filesystems/LocalFileSystem.java"/>
119
            </patch>
125
      <include name="org/openide/filesystems/JarFileSystem.java"/>
120
	    <patch class="org/openide/loaders/MultiDataObject" > 
126
      <include name="org/openide/filesystems/AbstractFileSystem.java"/>
121
                <!-- make following members public -->
127
      <include name="org/openide/filesystems/Repository.java"/>
122
                <member name="getCookieSet" />
128
      <include name="org/openide/explorer/propertysheet/PropertyDialogManager.java"/>
123
                <member name="setCookieSet" />
129
      <include name="org/openide/explorer/propertysheet/SetDefaultValueAction.java"/>
124
            </patch>
130
      <include name="org/openide/awt/Toolbar.java"/>
125
	    <patch class="org/openide/explorer/view/BeanTreeView" > 
131
      <include name="org/openide/explorer/view/BeanTreeView.java"/>
126
                <member name="selectionChanged" />
132
    </preprocess>
127
            </patch>
128
	    <patch class="org/openide/compiler/ExternalCompiler" > 
129
                <member name="isUpToDate" />
130
            </patch>
131
            <!-- making the members non-final -->
132
	    <patch class="org/openide/compiler/CompilerGroup" > 
133
                <member name="addCompilerListener" />
134
                <member name="removeCompilerListener" />
135
            </patch>
136
137
            <!-- superclass changed in order to implement MouseInputListener -->
138
            <patch class="org/openide/awt/Toolbar" super="org/openide/awt/$$Toolbar$$Patch$$">
139
                <member name="BASIC_HEIGHT" /> <!-- made non-final -->
140
            </patch>
141
            <patch class="org/openide/awt/Toolbar$$DnDEvent" >
142
                <!-- make fields public -->
143
                <member name="name" />
144
                <member name="dx" />
145
                <member name="dy" />
146
                <member name="type" />
147
            </patch>
148
149
            <!-- superclass needs to provide refershRoot method with different signature than the one in AbstractFileSystem -->                        
150
	    <patch class="org/openide/filesystems/AbstractFileSystem" super="org/openide/filesystems/$$AbstractFileSystem$$Patch$$" /> 
151
            
152
            <!-- superclass implements intefaces AbstractFileSystem.Info, List, Change -->
153
	    <patch class="org/openide/filesystems/LocalFileSystem" super="org/openide/filesystems/$$LocalFileSystem$$Patch$$"> 
154
                <!-- methods are made public instead of proteted -->
155
                <member name="children" />
156
                <member name="createData" />
157
                <member name="createFolder" />
158
                <member name="delete" />
159
                <member name="folder" />
160
                <member name="inputStream" />
161
                <member name="lastModified" />
162
                <member name="lock" />
163
                <member name="markUnimportant" />
164
                <member name="mimeType" />
165
                <member name="outputStream" />
166
                <member name="readOnly" />
167
                <member name="rename" />
168
                <member name="size" />
169
                <member name="unlock" />
170
            </patch>
171
            <!-- the same case as LocalFileSystem -->
172
	    <patch class="org/openide/filesystems/JarFileSystem" super="org/openide/filesystems/$$JarFileSystem$$Patch$$"> 
173
                <member name="attributes" />
174
                <member name="deleteAttributes" />
175
                <member name="readAttribute" />
176
                <member name="renameAttributes" />
177
                <member name="writeAttribute" />
178
                
179
                <member name="children" />
180
                <member name="createData" />
181
                <member name="createFolder" />
182
                <member name="delete" />
183
                <member name="folder" />
184
                <member name="inputStream" />
185
                <member name="lastModified" />
186
                <member name="lock" />
187
                <member name="markUnimportant" />
188
                <member name="mimeType" />
189
                <member name="outputStream" />
190
                <member name="readOnly" />
191
                <member name="rename" />
192
                <member name="size" />
193
                <member name="unlock" />
194
            </patch>
195
            
196
            <!-- no super change, just be public -->
197
	    <patch class="org/openide/explorer/propertysheet/SetDefaultValueAction"  /> 
198
	    <patch class="org/openide/loaders/DataLoaderPool$$FolderLoader"  /> 
199
	    <patch class="org/openide/loaders/DataLoaderPool$$InstanceLoader"  /> 
200
	    <patch class="org/openide/loaders/DataLoaderPool$$DefaultLoader"  /> 
201
	    <patch class="org/openide/loaders/DataLoaderPool$$ShadowLoader"  /> 
202
203
    </enhanceclass>
133
  </target>
204
  </target>
134
205
135
  <target name="13javac-workaround">
206
  <target name="13javac-workaround">
Lines 188-194 Link Here
188
    <filter token="BUILD_NUMBER_SUBST" value="${buildnumber}"/>
259
    <filter token="BUILD_NUMBER_SUBST" value="${buildnumber}"/>
189
  </target>
260
  </target>
190
  
261
  
191
  <target name="jars" depends="compile,13javac-workaround,vers-prep" description="Create JAR files.">
262
  <target name="jars" depends="compile,13javac-workaround,vers-prep,patchsuper" description="Create JAR files.">
192
    <mkdir dir="netbeans/lib"/>
263
    <mkdir dir="netbeans/lib"/>
193
    <filter token="Class-Path" value="Class-Path"/>
264
    <filter token="Class-Path" value="Class-Path"/>
194
    <filter token="OpenIDE-Module" value="OpenIDE-Module"/>
265
    <filter token="OpenIDE-Module" value="OpenIDE-Module"/>
Lines 213-233 Link Here
213
           <exclude name="org/openide/explorer/propertysheet/editors/Enhanced*.class"/>
284
           <exclude name="org/openide/explorer/propertysheet/editors/Enhanced*.class"/>
214
285
215
      </fileset>
286
      </fileset>
287
      
288
      <!-- include also patches -->
289
      <fileset dir="compat/src">
290
           <!-- But include patch files -->
291
           <include name="**/$$*$$Patch$$.class" />
292
      </fileset>
293
      
216
    </locjar>
294
    </locjar>
217
    
218
    
219
    <!-- Create binary compatibility kit. NOBODY should compile against it unless they -->
220
    <!-- are trying to make their code obsolete! -->
221
    <mkdir dir="netbeans/lib/patches"/>
222
    <!-- Use the same manifest to ensure that packages are defined correctly. -->
223
    <filter token="Class-Path" value="X-Commented-Out-Class-Path"/>
224
    <filter token="OpenIDE-Module" value="X-Commented-Out-OpenIDE-Module"/>
225
    <copy file="manifest.mf" tofile="manifest-compat-subst.mf" filtering="on"/>
226
    <jar jarfile="netbeans/lib/patches/openide-compat.jar"
227
         basedir="compatkit-work"
228
         manifest="manifest-compat-subst.mf"
229
	 excludesfile="../nbbuild/standard-jar-excludes.txt"
230
	 compress="false"/>
231
  </target>
295
  </target>
232
296
233
  <target name="jars-with-lib" depends="libs,compile,13javac-workaround,vers-prep" description="Create JAR files.">
297
  <target name="jars-with-lib" depends="libs,compile,13javac-workaround,vers-prep" description="Create JAR files.">
Lines 301-316 Link Here
301
    <!-- It also needs regexp.jar: -->
365
    <!-- It also needs regexp.jar: -->
302
    <copy file="${binroot}/core/release/lib/ext/regexp.jar" tofile="standalone/regexp.jar"/>
366
    <copy file="${binroot}/core/release/lib/ext/regexp.jar" tofile="standalone/regexp.jar"/>
303
    
367
    
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>
368
  </target>
315
369
316
  <target name="netbeans" depends="jars" description="Build everything needed for inclusion in the IDE.">
370
  <target name="netbeans" depends="jars" description="Build everything needed for inclusion in the IDE.">
Lines 882-888 Link Here
882
    <delete file="OpenAPIs.tar.bz2"/>
936
    <delete file="OpenAPIs.tar.bz2"/>
883
    <delete file="nb-api-tutorial.zip"/>
937
    <delete file="nb-api-tutorial.zip"/>
884
    <delete dir="examplemodules"/>
938
    <delete dir="examplemodules"/>
885
    <delete dir="compatkit-work"/>
886
    <delete dir="standalone"/>
939
    <delete dir="standalone"/>
887
    <delete dir="Info"/>
940
    <delete dir="Info"/>
888
    <delete file="openide.nbm"/>
941
    <delete file="openide.nbm"/>
(-)nb_all/openide/api/doc/changes/apichanges.xml (+14 lines)
Lines 106-111 Link Here
106
  </apidefs>
106
  </apidefs>
107
107
108
<!-- ACTUAL CHANGES BEGIN HERE: -->
108
<!-- ACTUAL CHANGES BEGIN HERE: -->
109
  <changes>
109
    <change>
110
    <change>
110
        <api name="util"/>
111
        <api name="util"/>
111
        <summary>Deprecation of parts of MouseUtils.PopupMenuAdapter</summary>
112
        <summary>Deprecation of parts of MouseUtils.PopupMenuAdapter</summary>
Lines 3940-3945 Link Here
3940
3941
3941
<hr/><h1><a name="compatkit">Binary Compatibility Kit</a></h1>
3942
<hr/><h1><a name="compatkit">Binary Compatibility Kit</a></h1>
3942
3943
3944
      <h2>Binary Compatibility up to NetBeans 3.4</h2>
3945
3943
<p>In most cases, when it is desirable from an architectural standpoint
3946
<p>In most cases, when it is desirable from an architectural standpoint
3944
to change an API in an incompatible way, the standard Java mechanism
3947
to change an API in an incompatible way, the standard Java mechanism
3945
of <code>@deprecated</code> tags in Javadoc suffices as a compromise:
3948
of <code>@deprecated</code> tags in Javadoc suffices as a compromise:
Lines 4002-4007 Link Here
4002
into an IDE installation that has had its
4005
into an IDE installation that has had its
4003
<samp>lib/patches/openide-compat.jar</samp> removed, to ensure that
4006
<samp>lib/patches/openide-compat.jar</samp> removed, to ensure that
4004
they are not depending on the deprecated APIs.</p>
4007
they are not depending on the deprecated APIs.</p>
4008
4009
      <h2>Binary Compatibility after NetBeans 3.4</h2>
4010
4011
      <p>
4012
        In releases after 3.4 (expected 4.0), the system used is slightly
4013
        different, though the effect is similar.
4014
        <samp>lib/openide-compat.jar</samp> is now the compatibility JAR
4015
        location. It contains fake superclasses for some classes; the fake
4016
        superclasses will be inserted into the inheritance tree at runtime and
4017
        include methods and interfaces which are not available in source code.
4018
      </p>
4005
4019
4006
    </body>
4020
    </body>
4007
  </htmlcontents>
4021
  </htmlcontents>
(-)nb_all/openide/compat/.cvsignore (+1 lines)
Added Link Here
1
patched
(-)nb_all/openide/compat/src/org/openide/awt/$Toolbar$Patch$.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 $Toolbar$Patch$ extends JToolBar 
26
implements MouseInputListener {
27
    /** Constructor that delegates.
28
     */
29
    public $Toolbar$Patch$ () {
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/filesystems/$AbstractFileSystem$Patch$.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 $AbstractFileSystem$Patch$ 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/$JarFileSystem$Patch$.java (+27 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 that implements interfaces
21
 * that used to be implemented by LocalFS and JarFS
22
 *
23
 * @author Jaroslav Tulach
24
 */
25
abstract class $JarFileSystem$Patch$ extends AbstractFileSystem 
26
implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change, AbstractFileSystem.Attr {
27
}
(-)nb_all/openide/compat/src/org/openide/filesystems/$LocalFileSystem$Patch$.java (+27 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 that implements interfaces
21
 * that used to be implemented by LocalFS and JarFS
22
 *
23
 * @author Jaroslav Tulach
24
 */
25
abstract class $LocalFileSystem$Patch$ extends AbstractFileSystem 
26
implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change {
27
}
(-)nb_all/openide/compat/src/org/openide/filesystems/$Repository$Patch$.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
abstract class $Repository$Patch$ extends Object 
25
implements org.openide.nodes.Node.Cookie {
26
}
(-)nb_all/openide/compat/src/org/openide/util/actions/$SystemAction$Patch$.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 $SystemAction$Patch$ extends org.openide.util.SharedClassObject {
26
    /** Constructor that delegates.
27
     */
28
    public $SystemAction$Patch$ () {
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/compat/test/.cvsignore (+4 lines)
Added Link Here
1
gensrc
2
lib
3
results
4
work
(-)nb_all/openide/compat/test/build-unit.xml (+206 lines)
Added Link Here
1
<?xml version="1.0"?>
2
<!--
3
                Sun Public License Notice
4
5
The contents of this file are subject to the Sun Public License
6
Version 1.0 (the "License"). You may not use this file except in
7
compliance with the License. A copy of the License is available at
8
http://www.sun.com/
9
10
The Original Code is NetBeans. The Initial Developer of the Original
11
Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
12
Microsystems, Inc. All Rights Reserved.
13
-->
14
15
<project name="Openide compatibility tests" basedir="." default="all">
16
17
<!-- =================== -->
18
    <!-- Setting classpathes -->
19
    <!-- =================== -->
20
    
21
    <target name="set_classpath" depends="prepare-compile-classpath,prepare-codetest-classpath">
22
    
23
        <!-- During filling classpathes remember that only <module>/test 
24
             is checked out during automated test execution so <module>/src 
25
             or <module>/netbeans isn't available. If you need to add something 
26
	     from <module>/src or <module>/netbeans to classpath, 
27
	     look below to "setting advanced claspathes" part of this target.
28
          -->
29
    
30
        <!-- List of directories where jars will be searched. -->
31
        <property name="xtest.extra.jars.path" location=""/>
32
    
33
        <!-- This jars is used for compilation, execution codetests and also for
34
             execution ide tests (it means this classpath will be mounted in repository).
35
             You can also write only name of jar or zip file, not in which directory it is and 
36
             this file will be searched in directories specified by property xtest.extra.jars.path 
37
                 example: <property name="xtest.extra.jars" value="jemmy.jar;jelly.jar"/>
38
          -->
39
        <property name="xtest.extra.jars"     value=""/>
40
   
41
        <!-- These jars will be copied to directory ${netebans.home}/lib/ext.
42
	     Again you can write only name of jar or zip file, not in which directory it is and 
43
             this file will be searched in directories specified by property xtest.extra.jars.path 
44
                 example: <property name="xtest.extra.jars.ide" value="jdbc_driver1.zip;jdbcd_river2.jar"/>
45
          -->
46
        <property name="xtest.extra.jars.ide" value=""/>
47
48
49
        <!-- Arguments which will be added into commandline of starting IDE. 
50
                 example: <property name="xtest.ide.commandline.suffix" value="-J-Dxtest.useclassloader=org.openidex.util"/>
51
          -->
52
        <property name="xtest.ide.commandline.suffix" value=""/>
53
  	
54
        <!-- =========================== -->
55
        <!-- Setting avanced classpathes -->
56
        <!-- =========================== -->
57
    
58
        <!-- If you need to add something from <module>/src or <module>/netbeans
59
             to classpath use target prepare-compile-classpath or prepare-codetest-classpath
60
             which fills path according to property xtest.source.location. This property
61
             can have values "src" (compilation and execution against sources), "jar" (compil.
62
             and execut. against jars) or "ide" (compil. and execut. against installed IDE).
63
             "ide" mode is used during automated test execution so it has to be always supported. 
64
          -->
65
    
66
	<!-- This classpath is beside jars in xtest.extra.jars also used for compilation, 
67
	     but it depends on property xtest.source.location which classpath will be used.
68
	     Fill apropriate classpathes in targets "${xtest.source.location}compile-classath". -->
69
	<property name="compiletest.classpath" refid="compiletest.classpath"/>
70
            
71
	<!-- This classpath is beside jars in xtest.extra.jars also used for execution codetests,
72
	     but it depends on property xtest.source.location which classpath will be used.
73
	     Fill apropriate classpathes in targets "${xtest.source.location}test-classath". -->
74
	<property name="codetest.classpath" refid="codetest.classpath"/>
75
        
76
    </target>
77
    
78
    <!-- ========= -->
79
    <!-- Compilers -->
80
    <!-- ========= -->
81
    
82
    <target name="unit-compiler" depends="set_classpath">
83
       <ant dir="." antfile="${xtest.module_harness.antfile}"
84
             target="buildtests">
85
           <!-- This property contains directories to compile.
86
    	        These directories will be compiled separately. 
87
                   example: <property name="compile.srcdir" value="unit/src1;unit/src2"/>
88
             -->
89
           <property name="compile.srcdir" value="unit/src"/>
90
	   <property name="compile.excludes" value="**/data/**"/>
91
       </ant>
92
    </target>
93
94
    <!-- ========= -->
95
    <!-- Executors -->
96
    <!-- ========= -->
97
    
98
    <!-- This target is executed from test-executor in newly created Project -->
99
    <!-- Name of this task is defined in cfg-xxx.xml -->
100
    <!-- This target executes tests inside IDE -->
101
    <target name="runidetest" depends="set_classpath">
102
        <ant dir="." antfile="${xtest.module_harness.antfile}"
103
             target="test">
104
           <property name="xtest.exectype" value="ide"/>
105
        </ant>
106
    </target>
107
    
108
    <!-- This target is executed from test-executor in newly created Project -->
109
    <!-- Name of this task is defined in cfg-xxx.xml -->
110
    <!-- This target executes standalone tests -->
111
    <target name="runcodetest" depends="set_classpath">
112
        <ant dir="." antfile="${xtest.module_harness.antfile}"
113
             target="test">
114
           <property name="xtest.exectype" value="code"/>
115
        </ant>
116
    </target>
117
118
119
    <!-- =============================================================
120
        Following targets are for "advanced" users who needs more 
121
        compilacated classpathes, which depends on way of execution.
122
        ============================================================= -->
123
124
    <!-- this "switch" will decide how to create classpath -->
125
    <target name="which-classpath">
126
        <condition property="jarcode.classpath">
127
            <equals arg1="${xtest.source.location}" arg2="jar"/>
128
        </condition>
129
        <condition property="srccode.classpath">
130
            <equals arg1="${xtest.source.location}" arg2="src"/>
131
        </condition>
132
        <condition property="idecode.classpath">
133
            <equals arg1="${xtest.source.location}" arg2="ide"/>
134
        </condition>
135
    </target>
136
137
    <!-- ========================= -->
138
    <!-- Classpath for compilation -->
139
    <!-- ========================= -->
140
    
141
    <target name="prepare-compile-classpath"
142
         depends="jarcompile-classpath,srccompile-classpath,idecompile-classpath"/>
143
    
144
    <target name="jarcompile-classpath" depends="which-classpath" if="jarcode.classpath">
145
        <echo message="Using jars classpath for compilation."/>
146
    	<!-- this classpath will be used for compiling tests against jars -->
147
	<path id="compiletest.classpath">        
148
	    <!-- If you need e.g. openide.jar, write this:
149
	           <pathelement location="../netbeans/lib/openide.jar"/>
150
 	      -->
151
	    <pathelement location="../mymodule.jar"/>
152
	</path>
153
    </target>
154
        
155
    <target name="srccompile-classpath" depends="which-classpath" if="srccode.classpath">
156
        <echo message="Using srcs classpath for compilation."/>
157
    	<!-- this classpath will be used for compiling tests against sources -->
158
    	<path id="compiletest.classpath">        
159
    	    <!-- If you need e.g. openide.jar, write this:
160
	           <pathelement location="../netbeans/lib/openide.jar"/>
161
	         If you need e.g. sources of your tested module, write this:
162
	           <pathelement location="../src"/>
163
 	      -->
164
	     <pathelement location="gensrc"/>
165
	     <pathelement location="../../src"/>
166
	     <pathelement location="../src"/>
167
	</path>
168
    </target>
169
    
170
    <!-- we're not using this, because mymodule is not a part of IDE :-) -->    
171
    <target name="idecompile-classpath" depends="which-classpath" if="idecode.classpath">
172
        <echo message="Using IDE classpath for compilation."/>
173
    	<!-- this classpath will be used for compiling tests against installed IDE -->
174
    	<path id="compiletest.classpath">   
175
    	    <!-- If you need e.g. openide.jar, write this:
176
	           <pathelement location="${netbeans.home}/lib/openide.jar"/>
177
	         If you need e.g. your tested module, write this:
178
	           <pathelement location="${netbeans.home}/modules/somemodule.jar"/>
179
 	      -->
180
	    <pathelement location="../mymodule.jar"/>     
181
   	</path>
182
    </target>
183
    
184
    <!-- ================================== -->
185
    <!-- Classpath for execution code tests -->
186
    <!-- ================================== -->
187
    
188
    <target name="prepare-codetest-classpath" 
189
            depends="idetest-classpath"/>
190
    
191
192
    <target name="idetest-classpath" >
193
        <echo message="Using IDE classpath."/>
194
        <!-- this classpath will be used for executing tests against installed IDE -->
195
    	<path id="codetest.classpath">
196
	    <!-- If you need e.g. openide.jar, write this:
197
	           <pathelement location="${netbeans.home}/lib/openide.jar"/>
198
	         If you need e.g. your tested module, write this:
199
	           <pathelement location="${netbeans.home}/modules/somemodule.jar"/>
200
 	      --> 
201
	     <pathelement location="../mymodule.jar"/>
202
    	</path>
203
    </target>
204
    
205
206
</project>
(-)nb_all/openide/compat/test/build.xml (+103 lines)
Added Link Here
1
<?xml version="1.0"?>
2
<!--
3
                Sun Public License Notice
4
5
The contents of this file are subject to the Sun Public License
6
Version 1.0 (the "License"). You may not use this file except in
7
compliance with the License. A copy of the License is available at
8
http://www.sun.com/
9
10
The Original Code is NetBeans. The Initial Developer of the Original
11
Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
12
Microsystems, Inc. All Rights Reserved.
13
-->
14
15
<project name="Openide compatibility tests" basedir="." default="all">
16
    <taskdef name="patchclass" classname="org.netbeans.nbbuild.NbPatchClass" classpath="../../../nbbuild/nbantext.jar"/>
17
18
    <!-- Ant property. Value 'ignore' means that system classpath is ignored
19
         and only classpath specified in build file is used. -->
20
    <property name="build.sysclasspath" value="ignore"/>
21
22
    <!-- Points to directory with IDE to test-->
23
    <property name="netbeans.home" location="../../../nbbuild/netbeans"/>
24
    
25
    <!-- Name of tested module -->
26
    <property name="xtest.module" value="Openide compatibility"/>
27
    
28
    <!-- Home of XTest -->
29
    <property name="xtest.home" location="../../../xtest"/>
30
   
31
    <!-- default testtypes, attributes used when no value is supplied from command line -->
32
    <property name="xtest.testtype" value="unit"/>
33
    <property name="xtest.attribs" value="ide"/>
34
    
35
    <!-- Points to antfile with module's harness. 
36
         Targets from that antfile is called from this build.xml -->
37
    <property name="xtest.module_harness.antfile" location="${xtest.home}/lib/module_harness.xml"/>
38
39
    <!-- Says how to create classpath for compilation and for execution code tests by default.
40
         Can have values src, jar, ide -->
41
    <property name="xtest.source.location" value="src"/>
42
43
    
44
 
45
    <!-- ============ -->
46
    <!-- Main targets -->
47
    <!-- ============ -->
48
    
49
    <target name="all" depends="runtests"/>
50
    
51
    <!-- This calls target which will call compilers according to cfg file.
52
         You should not change this target unless you realy know what you are doing -->
53
    <target name="buildtests" depends="generate" >
54
       <ant dir="." antfile="${xtest.module_harness.antfile}"
55
             target="compiler-launcher"/>
56
    </target>
57
    
58
    <!-- generates classes as they appear to virtual machine during runtime 
59
    of the ide, so we can compile against them -->
60
    <target name="generate" >
61
        <patchclass library="${netbeans.home}/lib/ext/boot.jar" source="${netbeans.home}/lib/openide.jar" targetdir="gensrc" />
62
    </target>
63
    
64
    <!-- This calls common clean process. -->
65
    <!-- You can write your own if you need something special -->
66
    <target name="cleantests">
67
       <ant dir="." antfile="${xtest.module_harness.antfile}"
68
             target="cleantests"/>
69
       <delete dir="gensrc" />
70
    </target> 
71
72
    <!-- This target runs tests. You should not change this --> 
73
    <!-- target unless you realy know what you are doing -->
74
    <target name="runtests" depends="buildtests">
75
        <echo message="Module: Running tests for ${xtest.module}, testtype ${xtest.testtype}, attribs=${xtest.attribs}"/>
76
        <ant dir="." antfile="${xtest.module_harness.antfile}"
77
             target="runtests"/>
78
    </target>
79
   
80
    <!-- This target is executed from test-executor in newly created Project -->
81
    <!-- Name of this task is defined in cfg-xxx.xml -->
82
    <target name="test_report">
83
        <ant dir="." antfile="${xtest.module_harness.antfile}"
84
             target="test_report"/>
85
    </target>
86
    
87
    <target name="cleanresults">
88
        <ant dir="." antfile="${xtest.module_harness.antfile}"
89
             target="cleanresults"/>
90
    </target>
91
    
92
    <target name="realclean" depends="cleantests,cleanresults">
93
        <ant dir="." antfile="${xtest.module_harness.antfile}"
94
             target="realclean"/>
95
    </target>
96
    
97
    <target name="printconfig">
98
        <echo message="Default config is testtype: ${xtest.testtype}, attributes: ${xtest.attribs}."/>
99
    </target>
100
    
101
   
102
</project>
103
(-)nb_all/openide/compat/test/cfg-unit.xml (+49 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE mconfig PUBLIC "-//NetBeans//DTD XTest cfg 1.0//EN" "http://www.netbeans.org/dtds/xtest-cfg-1_0.dtd">
3
<!--
4
                Sun Public License Notice
5
6
The contents of this file are subject to the Sun Public License
7
Version 1.0 (the "License"). You may not use this file except in
8
compliance with the License. A copy of the License is available at
9
http://www.sun.com/
10
11
The Original Code is NetBeans. The Initial Developer of the Original
12
Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
13
Microsystems, Inc. All Rights Reserved.
14
-->
15
16
<!-- 
17
  These classes are excluded by default (defined in build.xml):
18
    "**/*Suite.class"
19
    "**/*$$*.class"
20
    "**/data/**"
21
    "**/hidden/**"
22
    "**/*Hidden.*"
23
    "**/*Hid.*"
24
-->
25
26
<mconfig name="Openide Compatibility Configuration">
27
    <!-- testbag with all MyModule tests running in ide mode (i.e. inside NetBeans IDE)
28
         use ant runtests -Dxtest.attribs=stable,ide to run this testbag  -->
29
    <testbag testattribs="stable" executor="ide" name="all tests (in ide)" resultsprocessor="unit">
30
        <testset dir="unit/src">
31
            <patternset>
32
		<include name="org/openide/*Test.class"/>
33
            </patternset>
34
        </testset>
35
    </testbag>
36
37
    <!-- ide executor - use this one if you plan to run your tests inside IDE (internally).
38
                        Similarly as with code executor, you can create your own to 
39
                        prepare some necessary stuff before running tests. -->
40
    <executor name="ide" antfile="build-unit.xml" target="runidetest"/>
41
    
42
43
    <compiler name="unit-compiler" antfile="build-unit.xml" target="unit-compiler" default="true"/>
44
45
    <!-- standard results processor - currently there is only one results processor
46
                                      in XTest -->    
47
    <resultsprocessor name="unit" antfile="build.xml" target="test_report" default="true"/>
48
    
49
</mconfig>
(-)nb_all/openide/compat/test/unit/src/org/openide/CompatibilityTest.java (+264 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.openide;
15
16
import java.io.IOException;
17
import java.util.*;
18
19
20
import org.netbeans.junit.NbTestCase;
21
import org.netbeans.junit.NbTestSuite;
22
import org.openide.compiler.ExternalCompiler;
23
import org.openide.filesystems.AbstractFileSystem;
24
import org.openide.filesystems.JarFileSystem;
25
import org.openide.filesystems.LocalFileSystem;
26
import org.openide.loaders.DataFolder;
27
28
/** Tests compatibility of the openide. Compiles against classes as they 
29
* are seen in runtime, but executed is just in regular IDE.
30
*/
31
public class CompatibilityTest extends NbTestCase {
32
    public CompatibilityTest (String name) {
33
        super (name);
34
    }
35
    
36
    public static void main(java.lang.String[] args) {
37
        junit.textui.TestRunner.run(suite());
38
    }
39
    
40
    public static junit.framework.Test suite() {
41
        junit.framework.TestSuite suite = new NbTestSuite(CompatibilityTest.class);
42
        return suite;
43
    }
44
    
45
    protected void setUp () {
46
    }
47
48
    public void testDataLoaderPoolShadowLoaderIsPublic () {
49
        new org.openide.loaders.DataLoaderPool$ShadowLoader ();
50
    }
51
    
52
    public void testDataLoaderPoolDefaultLoaderIsPublic () {
53
        new org.openide.loaders.DataLoaderPool$DefaultLoader ();
54
    }
55
    
56
    public void testDataLoaderPoolInstanceLoaderIsPublic () {
57
        new org.openide.loaders.DataLoaderPool$InstanceLoader ();
58
    }
59
    
60
    public void testDataLoaderPoolFolderLoaderIsPublic () {
61
        new org.openide.loaders.DataLoaderPool$FolderLoader ();
62
    }
63
    
64
    public void testSetDefaultValueActionIsPublic () {
65
        new org.openide.explorer.propertysheet.SetDefaultValueAction ();
66
    }
67
    
68
    public void testJarFileSystemImplementsAFSInterfaces () {
69
        JarFileSystem fs = new JarFileSystem ();
70
        callAFSInfo (fs);
71
        callAFSChange (fs);
72
        callAFSList (fs);
73
        callAFSAttr (fs);
74
    }
75
    
76
    public void testLocalFileSystemImplementsAFSIntefaces () {
77
        LocalFileSystem fs = new LocalFileSystem ();
78
        callAFSInfo (fs);
79
        callAFSChange (fs);
80
        callAFSList (fs);
81
    }
82
    
83
    public void testAbstractFileSystemHasTwoRefreshRootMethods () {
84
        int cnt = 0;
85
        
86
        Class c = AbstractFileSystem.class;
87
        
88
        while (c != null) {
89
            java.lang.reflect.Method[] arr = c.getDeclaredMethods();
90
91
            for (int i = 0; i < arr.length; i++) {
92
                if (arr[i].getName ().equals ("refreshRoot")) {
93
                    cnt++;
94
                }
95
            }
96
            
97
            c = c.getSuperclass();
98
        }
99
        
100
        assertEquals ("There are two refreshRoot methods defined", 2, cnt);
101
        
102
    }
103
    
104
    public void testToolbarBASIC_HEIGHTisnotfinal () {
105
        int prev = org.openide.awt.Toolbar.BASIC_HEIGHT;
106
        org.openide.awt.Toolbar.BASIC_HEIGHT = 22;
107
        org.openide.awt.Toolbar.BASIC_HEIGHT = prev;
108
    }
109
    
110
    public void testToolbarDnDFieldsArePublic () {
111
        org.openide.awt.Toolbar t = new org.openide.awt.Toolbar ();
112
        org.openide.awt.Toolbar.DnDEvent ev = new org.openide.awt.Toolbar.DnDEvent (
113
            t, "Str", 1, 2, 3
114
        );
115
        
116
        assertEquals ("Str", ev.name);
117
        assertEquals (1, ev.dx);
118
        assertEquals (2, ev.dy);
119
        assertEquals (3, ev.type);
120
    }
121
    
122
    
123
    public void testPossibleToOverrideListenerMethodsInCompilerGroup () {
124
        class C extends org.openide.compiler.CompilerGroup {
125
            boolean add;
126
            boolean remove;
127
            
128
            public boolean start () {
129
                return true;
130
            }
131
            
132
            public void add (org.openide.compiler.Compiler c) {
133
            }
134
            
135
            public void addCompilerListener (org.openide.compiler.CompilerListener l) {
136
                add = true;
137
            }
138
            public void removeCompilerListener (org.openide.compiler.CompilerListener l) {
139
                remove = true;
140
            }
141
        }
142
        
143
        C c = new C ();
144
        c.addCompilerListener (null);
145
        c.removeCompilerListener (null);
146
        
147
        assertTrue (c.add);
148
        assertTrue (c.remove);
149
        
150
    }
151
152
    public void testExternalCompilerIsUpToDataIsPublic () {
153
        new ExternalCompiler (
154
            new java.io.File ("ahoj"),
155
            ExternalCompiler.COMPILE,
156
            new org.openide.execution.NbProcessDescriptor ("x", "y"),
157
            ExternalCompiler.JAVAC
158
        ).isUpToDate ();
159
    }
160
    
161
    public void testBeanTreeViewSelectionChangedIsPublic () {
162
        try {
163
            new org.openide.explorer.view.BeanTreeView ().selectionChanged(
164
                new org.openide.nodes.Node[0], new org.openide.explorer.ExplorerManager ()
165
            );
166
        } catch (java.beans.PropertyVetoException ex) {
167
            // ok
168
        }
169
    }
170
    
171
    public void testAbstractNodeGetCookieSetIsPublic () {
172
        new org.openide.nodes.AbstractNode (
173
            org.openide.nodes.Children.LEAF
174
        ).getCookieSet();
175
    }
176
     
177
    public void testMultiDataObjectGetCookieSetIsPublic () {
178
        JarFileSystem fs = new JarFileSystem ();
179
        DataFolder f = DataFolder.findFolder(fs.getRoot ());
180
        f.getCookieSet ();
181
    }
182
    
183
    public void testRepositoryImplementsCookie () {
184
        assertTrue (
185
            new org.openide.filesystems.Repository (new JarFileSystem ())
186
            instanceof org.openide.nodes.Node.Cookie
187
        );
188
    }
189
    
190
    public void testSystemActionGetSetIcon () {
191
        boolean[] res = new boolean[4];
192
        
193
        java.lang.reflect.Method[] arr = org.openide.util.actions.SystemAction.class.getMethods();
194
195
        for (int i = 0; i < arr.length; i++) {
196
            int indx = -1;
197
            if (arr[i].getName ().equals ("getIcon") && arr[i].getParameterTypes().length == 0) {
198
                if (arr[i].getReturnType() == javax.swing.Icon.class) {
199
                    indx = 0;
200
                }
201
                if (arr[i].getReturnType() == javax.swing.ImageIcon.class) {
202
                    indx = 1;
203
                }
204
            }
205
            if (arr[i].getName ().equals ("setIcon") && arr[i].getParameterTypes().length == 1) {
206
                if (arr[i].getParameterTypes()[0] == javax.swing.Icon.class) {
207
                    indx = 2;
208
                }
209
                if (arr[i].getParameterTypes()[0] == javax.swing.ImageIcon.class) {
210
                    indx = 3;
211
                }
212
            }
213
            
214
            if (indx >= 0) {
215
                assertTrue ("Not yet set", !res[indx]);
216
                res[indx] = true;
217
            }
218
                
219
        }
220
    
221
        assertTrue ("Icon getIcon () exists", res[0]);
222
        assertTrue ("ImageIcon getIcon () exists", res[1]);
223
        assertTrue ("setIcon (Icon) exists", res[2]);
224
        assertTrue ("setIcon (ImageIcon) exists", res[3]);
225
    }
226
    
227
    //
228
    // Methods to do calls on filesystems
229
    //
230
    
231
    private static void callAFSInfo (AbstractFileSystem.Info info) {
232
        info.folder("");
233
        info.lastModified("");
234
        info.mimeType("");
235
        info.markUnimportant("");
236
        info.readOnly("");
237
        info.size ("");
238
        
239
        // getting IOException is good response...
240
        try { info.inputStream(""); } catch (IOException ex) {}
241
        try { info.outputStream(""); } catch (IOException ex) {}
242
        try { info.lock(""); } catch (IOException ex) {}
243
        
244
    }
245
    
246
    private static void callAFSChange (AbstractFileSystem.Change change) {
247
        // getting IOException is good response...
248
        try { change.createData(""); } catch (IOException ex) {}
249
        try { change.createFolder (""); } catch (IOException ex) {}
250
        try { change.delete(""); } catch (IOException ex) {}
251
        try { change.rename("", ""); } catch (IOException ex) {}
252
    }
253
    
254
    private static void callAFSList (AbstractFileSystem.List change) {
255
        change.children("");
256
    }
257
    
258
    private static void callAFSAttr (AbstractFileSystem.Attr attr) {
259
        attr.attributes("");
260
        attr.deleteAttributes("");
261
        attr.readAttribute("", "");
262
        attr.renameAttributes("", "");
263
    }
264
}
(-)nb_all/openide/src/org/openide/awt/Toolbar.java (-66 / +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 /*implemented by patchsuperclass MouseInputListener*/ {
43
/*nbif compat
44
implements MouseInputListener
45
/*nbend*/
46
{
47
    /** Basic toolbar height. */
43
    /** Basic toolbar height. */
48
    public static
44
    public static final int BASIC_HEIGHT = 34;
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 235-240 Link Here
235
            listener.dropToolbar (new DnDEvent (this, getName(), dx, dy, type));
226
            listener.dropToolbar (new DnDEvent (this, getName(), dx, dy, type));
236
    }
227
    }
237
228
229
    synchronized final MouseInputListener mouseDelegate () {
230
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
231
        return mouseListener;
232
    }
238
233
239
    /** Toolbar mouse listener. */
234
    /** Toolbar mouse listener. */
240
    class ToolbarMouseListener extends MouseInputAdapter {
235
    class ToolbarMouseListener extends MouseInputAdapter {
Lines 297-333 Link Here
297
292
298
    } // end of inner class ToolbarMouseListener
293
    } // end of inner class ToolbarMouseListener
299
294
300
    /*nbif compat
301
    public void mouseClicked (MouseEvent e) {
302
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
303
        mouseListener.mouseClicked (e);
304
    }
305
    public void mouseEntered (MouseEvent e) {
306
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
307
        mouseListener.mouseEntered (e);
308
    }
309
    public void mouseExited (MouseEvent e) {
310
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
311
        mouseListener.mouseExited (e);
312
    }
313
    public void mousePressed (MouseEvent e) {
314
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
315
        mouseListener.mousePressed (e);
316
    }
317
    public void mouseReleased (MouseEvent e) {
318
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
319
        mouseListener.mouseReleased (e);
320
    }
321
    public void mouseDragged (MouseEvent e) {
322
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
323
        mouseListener.mouseDragged (e);
324
    }
325
    public void mouseMoved (MouseEvent e) {
326
        if (mouseListener == null) mouseListener = new ToolbarMouseListener ();
327
        mouseListener.mouseMoved (e);
328
    }
329
    /*nbend*/
330
331
    /**
295
    /**
332
     * This class can be used to produce a <code>Toolbar</code> instance from
296
     * This class can be used to produce a <code>Toolbar</code> instance from
333
     * the given <code>DataFolder</code>.
297
     * the given <code>DataFolder</code>.
Lines 620-652 Link Here
620
        public static final int DND_LINE = 3;
584
        public static final int DND_LINE = 3;
621
585
622
        /** Name of toolbar where event occured. */
586
        /** Name of toolbar where event occured. */
623
        /*nbif compat
587
        private String name;
624
        public
625
        nbelse*/
626
        private
627
        /*nbend*/
628
        String name;
629
        /** distance of horizontal dragging */
588
        /** distance of horizontal dragging */
630
        /*nbif compat
589
        private int dx;
631
        public
632
        nbelse*/
633
        private
634
        /*nbend*/
635
        int dx;
636
        /** distance of vertical dragging */
590
        /** distance of vertical dragging */
637
        /*nbif compat
591
        private int dy;
638
        public
639
        nbelse*/
640
        private
641
        /*nbend*/
642
        int dy;
643
        /** Type of event. */
592
        /** Type of event. */
644
        /*nbif compat
593
        private int type;
645
        public
646
        nbelse*/
647
        private
648
        /*nbend*/
649
        int type;
650
594
651
        static final long serialVersionUID =4389530973297716699L;
595
        static final long serialVersionUID =4389530973297716699L;
652
        public DnDEvent (Toolbar toolbar, String name, int dx, int dy, int type) {
596
        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 final 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 final 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 / +3 lines)
Lines 21-32 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;
27
    
28
    public SetDefaultValueAction () {
29
    }
30
30
31
    public String getName () {
31
    public String getName () {
32
        return getString ("SetDefaultValue");
32
        return getString ("SetDefaultValue");
(-)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/DataFolder.java (-1 / +1 lines)
Lines 686-692 Link Here
686
                countDown--;
686
                countDown--;
687
                try {
687
                try {
688
                    // resolve temporary object for moving into
688
                    // resolve temporary object for moving into
689
                    DataLoaderPool.FolderLoader folderLoader = (DataLoaderPool.FolderLoader) getMultiFileLoader ();
689
                    DataLoaderPool$FolderLoader folderLoader = (DataLoaderPool$FolderLoader) getMultiFileLoader ();
690
                    newFolder = (DataFolder) folderLoader.createMultiObject (newFile, this);
690
                    newFolder = (DataFolder) folderLoader.createMultiObject (newFile, this);
691
                    dispose = false;
691
                    dispose = false;
692
                    break;
692
                    break;
(-)nb_all/openide/src/org/openide/loaders/DataLoaderPool.java (-370 / +360 lines)
Lines 472-478 Link Here
472
    private static MultiFileLoader[] getSystemLoaders () {
472
    private static MultiFileLoader[] getSystemLoaders () {
473
        if (systemLoaders == null) {
473
        if (systemLoaders == null) {
474
            systemLoaders = new MultiFileLoader [] {
474
            systemLoaders = new MultiFileLoader [] {
475
                new ShadowLoader (),
475
                new DataLoaderPool$ShadowLoader (),
476
                (MultiFileLoader) DataLoader.getLoader(InstanceLoaderSystem.class)
476
                (MultiFileLoader) DataLoader.getLoader(InstanceLoaderSystem.class)
477
            };
477
            };
478
        }
478
        }
Lines 484-493 Link Here
484
    private static MultiFileLoader[] getDefaultLoaders () {
484
    private static MultiFileLoader[] getDefaultLoaders () {
485
        if (defaultLoaders == null) {
485
        if (defaultLoaders == null) {
486
            defaultLoaders = new MultiFileLoader [] {
486
            defaultLoaders = new MultiFileLoader [] {
487
                (MultiFileLoader) DataLoader.getLoader(FolderLoader.class),
487
                (MultiFileLoader) DataLoader.getLoader(DataLoaderPool$FolderLoader.class),
488
                (MultiFileLoader) DataLoader.getLoader(XMLDataObject.Loader.class),
488
                (MultiFileLoader) DataLoader.getLoader(XMLDataObject.Loader.class),
489
                (MultiFileLoader) DataLoader.getLoader(InstanceLoader.class),
489
                (MultiFileLoader) DataLoader.getLoader(DataLoaderPool$InstanceLoader.class),
490
                (MultiFileLoader) DataLoader.getLoader(DefaultLoader.class)
490
                (MultiFileLoader) DataLoader.getLoader(DataLoaderPool$DefaultLoader.class)
491
            };
491
            };
492
        }
492
        }
493
        return defaultLoaders;
493
        return defaultLoaders;
Lines 516-625 Link Here
516
    //
516
    //
517
    // Default loaders
517
    // Default loaders
518
    //
518
    //
519
    
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 {
526
        static final long serialVersionUID =-8325525104047820255L;
527
        
528
        /* Representation class is DataFolder */
529
        public FolderLoader () {
530
            super ("org.openide.loaders.DataFolder"); // NOI18N
531
            // super (DataFolder.class);
532
        }
533
        
534
        /** Get default actions.
535
        * @return array of default system actions or <CODE>null</CODE> if this loader does not have any
536
        *   actions
537
        */
538
        protected SystemAction[] defaultActions () {
539
            return new SystemAction[] {
540
                    SystemAction.get (org.openide.actions.OpenLocalExplorerAction.class),
541
                    SystemAction.get (org.openide.actions.FindAction.class),
542
                    SystemAction.get (org.openide.actions.FileSystemAction.class),
543
                    null,
544
                    SystemAction.get (org.openide.actions.CompileAction.class),
545
                    SystemAction.get (org.openide.actions.CompileAllAction.class),
546
                    null,
547
                    SystemAction.get (org.openide.actions.BuildAction.class),
548
                    SystemAction.get (org.openide.actions.BuildAllAction.class),
549
                    null,
550
                    SystemAction.get (org.openide.actions.CutAction.class),
551
                    SystemAction.get (org.openide.actions.CopyAction.class),
552
                    SystemAction.get (org.openide.actions.PasteAction.class),
553
                    null,
554
                    SystemAction.get (org.openide.actions.DeleteAction.class),
555
                    SystemAction.get (org.openide.actions.RenameAction.class),
556
                    null,
557
                    SystemAction.get (org.openide.actions.NewTemplateAction.class),
558
                    null,
559
                    SystemAction.get (org.openide.actions.ToolsAction.class),
560
                    SystemAction.get (org.openide.actions.PropertiesAction.class)
561
                };
562
        }
563
        
564
        /** Get the default display name of this loader.
565
        * @return default display name
566
        */
567
        protected String defaultDisplayName () {
568
            return NbBundle.getMessage (DataLoaderPool.class, "LBL_folder_loader_display_name");
569
        }
570
571
        protected FileObject findPrimaryFile(FileObject fo) {
572
            if (fo.isFolder()) {
573
                return fo;
574
            }
575
            return null;
576
        }
577
        
578
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
579
            return new FileEntry.Folder(obj, primaryFile);
580
        }
581
        
582
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
583
            return new DataFolder (primaryFile);
584
        }
585
        
586
        /** This method is used only in DataFolder.handleMove method.
587
         * For more comments see {@link org.openide.loaders.DataFolder#handleMove}.
588
         *
589
         * @param primaryFile the primary file of the datafolder to be created
590
         * @param original The original DataFolder. The returned MultiDataObject 
591
         *      delegates createNodeDelegate and getClonedNodeDelegate methods calls
592
         *      to the original DataFolder.
593
         * @return The DataFolder that shares the nodes with the original DataFolder.
594
         */
595
        MultiDataObject createMultiObject(FileObject primaryFile, final DataFolder original) throws DataObjectExistsException, IOException {
596
            class NodeSharingDataFolder extends DataFolder {
597
                public NodeSharingDataFolder(FileObject fo) throws DataObjectExistsException, IllegalArgumentException {
598
                    super(fo);
599
                }
600
                protected Node createNodeDelegate() {
601
                    return new FilterNode(original.getNodeDelegate());
602
                }
603
                Node getClonedNodeDelegate (DataFilter filter) {
604
                    return new FilterNode(original.getClonedNodeDelegate(filter));
605
                }
606
            }
607
            return new NodeSharingDataFolder(primaryFile);
608
        }
609
        
610
        public void writeExternal(ObjectOutput oo) throws IOException {
611
        }
612
        public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException {
613
        }
614
615
    }
616
519
617
    /* Instance loader recognizing .settings files. It's placed at the beginning
520
    /* Instance loader recognizing .settings files. It's placed at the beginning
618
     * of loader pool, .settings files must alwaus be recognized by this loader
521
     * of loader pool, .settings files must alwaus be recognized by this loader
619
     * otherwise IDE settings will not work at all. No module is permitted to use
522
     * otherwise IDE settings will not work at all. No module is permitted to use
620
     * .settings files.
523
     * .settings files.
621
     */
524
     */
622
    private static class InstanceLoaderSystem extends InstanceLoader {
525
    private static class InstanceLoaderSystem extends DataLoaderPool$InstanceLoader {
623
        private static final long serialVersionUID = -935749906623354837L;
526
        private static final long serialVersionUID = -935749906623354837L;
624
        
527
        
625
        /* Creates new InstanceLoader */
528
        /* Creates new InstanceLoader */
Lines 648-940 Link Here
648
            };
551
            };
649
        }
552
        }
650
    }
553
    }
554
} // end of DataLoaderPool
651
555
652
    /* Instance loader recognizing .ser and .instance files. It's placed at
556
653
     * the end of loader pool among default loaders.
557
/* Instance loader recognizing .ser and .instance files. It's placed at
558
 * the end of loader pool among default loaders.
559
 */
560
class DataLoaderPool$InstanceLoader extends UniFileLoader {
561
    static final long serialVersionUID =-3462727693843631328L;
562
563
564
    /* Creates new InstanceLoader */
565
    public DataLoaderPool$InstanceLoader () {
566
        super ("org.openide.loaders.InstanceDataObject"); // NOI18N
567
    }
568
569
    protected void initialize () {
570
        super.initialize();
571
        setExtensions(null);
572
    }
573
574
    /** Get default actions.
575
    * @return array of default system actions or <CODE>null</CODE> if this loader does not have any
576
    *   actions
577
    */
578
    protected SystemAction[] defaultActions () {
579
        return new SystemAction[] {
580
            SystemAction.get (org.openide.actions.CustomizeBeanAction.class),
581
            SystemAction.get (org.openide.actions.FileSystemAction.class),
582
            null,
583
            SystemAction.get(org.openide.actions.CutAction.class),
584
            SystemAction.get(org.openide.actions.CopyAction.class),
585
            SystemAction.get(org.openide.actions.PasteAction.class),
586
            null,
587
            SystemAction.get(org.openide.actions.DeleteAction.class),
588
            // #16278: Rename should be there. (It may or may not be enabled...)
589
            SystemAction.get(org.openide.actions.RenameAction.class),
590
            null,
591
            SystemAction.get (org.openide.actions.ToolsAction.class),
592
            SystemAction.get(org.openide.actions.PropertiesAction.class)
593
        };
594
    }
595
596
    /** Get the default display name of this loader.
597
    * @return default display name
598
    */
599
    protected String defaultDisplayName () {
600
        return NbBundle.getMessage (DataLoaderPool.class, "LBL_instance_loader_display_name");
601
    }
602
603
    /* Creates the right data object for given primary file.
604
     * It is guaranteed that the provided file is realy primary file
605
     * returned from the method findPrimaryFile.
606
     *
607
     * @param primaryFile the primary file
608
     * @return the data object for this file
609
     * @exception DataObjectExistsException if the primary file already has data object
654
     */
610
     */
655
    /*nbif compat
611
    protected MultiDataObject createMultiObject (FileObject primaryFile)
656
    public
612
    throws DataObjectExistsException, java.io.IOException {
657
    nbelse*/
613
        InstanceDataObject obj = new InstanceDataObject(primaryFile, this);
658
    private
614
        return obj;
659
    /*nbend*/
615
    }
660
    static class InstanceLoader extends UniFileLoader {
616
661
        static final long serialVersionUID =-3462727693843631328L;
617
    public void writeExternal (ObjectOutput oo) throws IOException {
662
        
618
        // does not use super serialization of extensions
663
        
619
        oo.writeObject (this);
664
        /* Creates new InstanceLoader */
620
665
        public InstanceLoader() {
621
        super.writeExternal (oo);
666
            super ("org.openide.loaders.InstanceDataObject"); // NOI18N
622
    }
667
        }
623
668
        
624
    public void readExternal (ObjectInput oi) throws IOException, ClassNotFoundException {
669
        protected void initialize () {
625
        // the result of following code is either ExtensionList (original version)
670
            super.initialize();
626
        // or this (current version).
671
            setExtensions(null);
627
        Object o = oi.readObject ();
628
        if (o instanceof SystemAction[]) {
629
            //added for compatibility with FFJ2.0
630
            setActions ((SystemAction[]) o);            
631
            setExtensions(getExtensions());
632
        } else if (o instanceof ExtensionList) {
633
            // old serialization, add new extension
634
            ExtensionList list = (ExtensionList)o;
635
            setExtensions(list);
636
        } else {
637
            // newer serialization, everything should be ok, just read
638
            // the original value
639
            super.readExternal (oi);
640
            setExtensions(getExtensions());
672
        }
641
        }
673
        
642
    }
674
        /** Get default actions.
643
675
        * @return array of default system actions or <CODE>null</CODE> if this loader does not have any
644
    /** Set the extension list for this data loader.
676
        *   actions
645
    * Checks if all required extensions are in new list of extensions.
677
        */
646
    * @param ext new list of extensions
678
        protected SystemAction[] defaultActions () {
647
    */
679
            return new SystemAction[] {
648
    public void setExtensions(ExtensionList ext) {
680
                SystemAction.get (org.openide.actions.CustomizeBeanAction.class),
649
        super.setExtensions(initExtensions(ext));
650
    }
651
652
    /** fill in instance file's extension list; if ext == null new list is created */
653
    private ExtensionList initExtensions(ExtensionList ext) {
654
        String rqext [] = getRequiredExt ();
655
        if (ext == null) ext = new ExtensionList();
656
        for (int i = 0; i < rqext.length; i++)
657
            ext.addExtension(rqext[i]);
658
        return ext;
659
    }
660
661
    /** @return list of all required extensions for this loader */
662
    protected String [] getRequiredExt () {
663
        return new String[] {
664
            InstanceDataObject.INSTANCE,
665
            InstanceDataObject.SER_EXT,
666
            InstanceDataObject.XML_EXT
667
        };
668
    }
669
} // end of DataLoaderPool$InstanceLoader
670
671
672
673
    
674
675
/** Loader for file objects not recognized by any other loader */
676
class DataLoaderPool$DefaultLoader extends MultiFileLoader {
677
    static final long serialVersionUID =-6761887227412396555L;
678
679
    /* Representation class is DefaultDataObject */
680
    public DataLoaderPool$DefaultLoader () {
681
        super ("org.openide.loaders.DefaultDataObject"); // NOI18N
682
        //super (DefaultDataObject.class);
683
    }
684
685
    /** Get default actions.
686
    * @return array of default system actions or <CODE>null</CODE> if this loader does not have any
687
    *   actions
688
    */
689
    protected SystemAction[] defaultActions () {
690
        return new SystemAction[] {
681
                SystemAction.get (org.openide.actions.FileSystemAction.class),
691
                SystemAction.get (org.openide.actions.FileSystemAction.class),
682
                null,
692
                null,
683
                SystemAction.get(org.openide.actions.CutAction.class),
693
                SystemAction.get (org.openide.actions.CutAction.class),
684
                SystemAction.get(org.openide.actions.CopyAction.class),
694
                SystemAction.get (org.openide.actions.CopyAction.class),
685
                SystemAction.get(org.openide.actions.PasteAction.class),
695
                SystemAction.get (org.openide.actions.PasteAction.class),
686
                null,
696
                null,
687
                SystemAction.get(org.openide.actions.DeleteAction.class),
697
                SystemAction.get (org.openide.actions.DeleteAction.class),
688
                // #16278: Rename should be there. (It may or may not be enabled...)
698
                SystemAction.get (org.openide.actions.RenameAction.class),
689
                SystemAction.get(org.openide.actions.RenameAction.class),
690
                null,
699
                null,
691
                SystemAction.get (org.openide.actions.ToolsAction.class),
700
                SystemAction.get (org.openide.actions.ToolsAction.class),
692
                SystemAction.get(org.openide.actions.PropertiesAction.class)
701
                SystemAction.get (org.openide.actions.PropertiesAction.class)
693
            };
702
            };
694
        }
703
    }
695
        
696
        /** Get the default display name of this loader.
697
        * @return default display name
698
        */
699
        protected String defaultDisplayName () {
700
            return NbBundle.getMessage (DataLoaderPool.class, "LBL_instance_loader_display_name");
701
        }
702
704
703
        /* Creates the right data object for given primary file.
705
    /** Get the default display name of this loader.
704
         * It is guaranteed that the provided file is realy primary file
706
    * @return default display name
705
         * returned from the method findPrimaryFile.
707
    */
706
         *
708
    protected String defaultDisplayName () {
707
         * @param primaryFile the primary file
709
        return NbBundle.getMessage (DataLoaderPool.class, "LBL_default_loader_display_name");
708
         * @return the data object for this file
710
    }
709
         * @exception DataObjectExistsException if the primary file already has data object
711
710
         */
712
    /** Get the primary file.
711
        protected MultiDataObject createMultiObject (FileObject primaryFile)
713
     * @param fo the file to find the primary file for
712
        throws DataObjectExistsException, java.io.IOException {
714
     *
713
            InstanceDataObject obj = new InstanceDataObject(primaryFile, this);
715
     * @return the primary file
714
            return obj;
716
     */
715
        }
717
    protected FileObject findPrimaryFile (FileObject fo) {
716
        
718
        // never recognize folders
717
        public void writeExternal (ObjectOutput oo) throws IOException {
719
        if (fo.isFolder()) return null;
718
            // does not use super serialization of extensions
720
        return fo;
719
            oo.writeObject (this);
721
    }
720
            
722
721
            super.writeExternal (oo);
723
    /* Creates the right data object for given primary file.
722
        }
724
     * It is guaranteed that the provided file is realy primary file
723
        
725
     * returned from the method findPrimaryFile.
724
        public void readExternal (ObjectInput oi) throws IOException, ClassNotFoundException {
726
     *
725
            // the result of following code is either ExtensionList (original version)
727
     * @param primaryFile the primary file
726
            // or this (current version).
728
     * @return the data object for this file
727
            Object o = oi.readObject ();
729
     * @exception DataObjectExistsException if the primary file already has data object
728
            if (o instanceof SystemAction[]) {
730
     */
729
                //added for compatibility with FFJ2.0
731
    protected MultiDataObject createMultiObject (FileObject primaryFile)
730
                setActions ((SystemAction[]) o);            
732
    throws DataObjectExistsException, java.io.IOException {
731
                setExtensions(getExtensions());
733
        return new DefaultDataObject(primaryFile, this);
732
            } else if (o instanceof ExtensionList) {
734
    }
733
                // old serialization, add new extension
735
734
                ExtensionList list = (ExtensionList)o;
736
    /* Creates the right primary entry for given primary file.
735
                setExtensions(list);
737
     *
736
            } else {
738
     * @param obj requesting object
737
                // newer serialization, everything should be ok, just read
739
     * @param primaryFile primary file recognized by this loader
738
                // the original value
740
     * @return primary entry for that file
739
                super.readExternal (oi);
741
     */
740
                setExtensions(getExtensions());
742
    protected MultiDataObject.Entry createPrimaryEntry (MultiDataObject obj, FileObject primaryFile) {
741
            }
743
        return new FileEntry (obj, primaryFile);
742
        }
744
    }
743
        
745
744
        /** Set the extension list for this data loader.
746
    /** Do not create a seconday entry.
745
        * Checks if all required extensions are in new list of extensions.
747
     *
746
        * @param ext new list of extensions
748
     * @param obj ignored
747
        */
749
     * @param secondaryFile ignored
748
        public void setExtensions(ExtensionList ext) {
750
     * @return never returns
749
            super.setExtensions(initExtensions(ext));
751
     * @exception UnsupportedOperationException because this loader supports only a primary file object
752
     */
753
    protected MultiDataObject.Entry createSecondaryEntry (MultiDataObject obj, FileObject secondaryFile) {
754
        throw new UnsupportedOperationException ();
755
    }
756
757
    /** Does nothing because this loader works only with objects
758
     * with one file => primary file so it is not necessary to search
759
     * for anything else.
760
     *
761
     * @param obj the object to test
762
     */
763
    void checkFiles (MultiDataObject obj) {
764
    }
765
} // end of DataLoaderPool$DefaultLoader
766
767
768
769
770
771
/** Loader for shadows, since 1.13 changed to UniFileLoader. */
772
class DataLoaderPool$ShadowLoader extends UniFileLoader {
773
    static final long serialVersionUID =-11013405787959120L;
774
775
    /* Adapter for listening on filesystems changes */
776
    private static ShadowChangeAdapter changeAdapter = new ShadowChangeAdapter();
777
778
    /* Representation class is DataShadow */
779
    public DataLoaderPool$ShadowLoader () {
780
        super ("org.openide.loaders.DataShadow"); // NOI18N
781
        //super (DataShadow.class);
782
    }
783
784
    /** Get the default display name of this loader.
785
    * @return default display name
786
    */
787
    protected String defaultDisplayName () {
788
        return NbBundle.getMessage (DataLoaderPool.class, "LBL_shadow_loader_display_name");
789
    }
790
791
    /** For a given file finds the primary file.
792
     * @param fo the (secondary) file
793
     *
794
     * @return the primary file for the file or <code>null</code> if the file is not
795
     *  recognized by this loader
796
     */
797
    protected FileObject findPrimaryFile(FileObject fo) {
798
        if (fo.hasExt (DataShadow.SHADOW_EXTENSION)) {
799
            return fo;
750
        }
800
        }
801
        return null;
802
    }
803
804
    /** Creates the right primary entry for a given primary file.
805
     *
806
     * @param obj requesting object
807
     * @param primaryFile primary file recognized by this loader
808
     * @return primary entry for that file
809
     */
810
    protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
811
        return new FileEntry(obj, primaryFile);
812
    }
751
813
752
        /** fill in instance file's extension list; if ext == null new list is created */
814
    /** Creates the right data object for a given primary file.
753
        private ExtensionList initExtensions(ExtensionList ext) {
815
     * It is guaranteed that the provided file will actually be the primary file
754
            String rqext [] = getRequiredExt ();
816
     * returned by {@link #findPrimaryFile}.
755
            if (ext == null) ext = new ExtensionList();
817
     *
756
            for (int i = 0; i < rqext.length; i++)
818
     * @param primaryFile the primary file
757
                ext.addExtension(rqext[i]);
819
     * @return the data object for this file
758
            return ext;
820
     * @exception DataObjectExistsException if the primary file already has a data object
821
     */
822
    protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
823
        try {
824
            DataObject d = DataShadow.deserialize (primaryFile);
825
            if (d != null) return new DataShadow (primaryFile, d, this);
826
        } catch (IOException ex) {
827
            // broken link or damaged shadow file
759
        }
828
        }
760
        
829
        /* Link is broken, create BrokenDataShadow */
761
        /** @return list of all required extensions for this loader */
830
        return new BrokenDataShadow (primaryFile, this);
762
        protected String [] getRequiredExt () {
831
    }
763
            return new String[] {
832
    public void writeExternal(ObjectOutput oo) throws IOException {
764
                InstanceDataObject.INSTANCE,
833
    }
765
                InstanceDataObject.SER_EXT,
834
    public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException {
766
                InstanceDataObject.XML_EXT
835
    }
836
} // end of DataLoaderPool$ShadowLoader
837
838
/** Loader for folders, since 1.13 changed to UniFileLoader. Will be made public by patching
839
 */
840
class DataLoaderPool$FolderLoader extends UniFileLoader {
841
    static final long serialVersionUID =-8325525104047820255L;
842
843
    /* Representation class is DataFolder */
844
    public DataLoaderPool$FolderLoader () {
845
        super ("org.openide.loaders.DataFolder"); // NOI18N
846
        // super (DataFolder.class);
847
    }
848
849
    /** Get default actions.
850
    * @return array of default system actions or <CODE>null</CODE> if this loader does not have any
851
    *   actions
852
    */
853
    protected SystemAction[] defaultActions () {
854
        return new SystemAction[] {
855
                SystemAction.get (org.openide.actions.OpenLocalExplorerAction.class),
856
                SystemAction.get (org.openide.actions.FindAction.class),
857
                SystemAction.get (org.openide.actions.FileSystemAction.class),
858
                null,
859
                SystemAction.get (org.openide.actions.CompileAction.class),
860
                SystemAction.get (org.openide.actions.CompileAllAction.class),
861
                null,
862
                SystemAction.get (org.openide.actions.BuildAction.class),
863
                SystemAction.get (org.openide.actions.BuildAllAction.class),
864
                null,
865
                SystemAction.get (org.openide.actions.CutAction.class),
866
                SystemAction.get (org.openide.actions.CopyAction.class),
867
                SystemAction.get (org.openide.actions.PasteAction.class),
868
                null,
869
                SystemAction.get (org.openide.actions.DeleteAction.class),
870
                SystemAction.get (org.openide.actions.RenameAction.class),
871
                null,
872
                SystemAction.get (org.openide.actions.NewTemplateAction.class),
873
                null,
874
                SystemAction.get (org.openide.actions.ToolsAction.class),
875
                SystemAction.get (org.openide.actions.PropertiesAction.class)
767
            };
876
            };
768
        }
769
    }
877
    }
770
    
878
771
    
879
    /** Get the default display name of this loader.
772
    /** Loader for file objects not recognized by any other loader */
880
    * @return default display name
773
    /*nbif compat
881
    */
774
    public
882
    protected String defaultDisplayName () {
775
    nbelse*/
883
        return NbBundle.getMessage (DataLoaderPool.class, "LBL_folder_loader_display_name");
776
    private
884
    }
777
    /*nbend*/
885
778
    static class DefaultLoader extends MultiFileLoader {
886
    protected FileObject findPrimaryFile(FileObject fo) {
779
        static final long serialVersionUID =-6761887227412396555L;
887
        if (fo.isFolder()) {
780
        
781
        /* Representation class is DataFolder */
782
        public DefaultLoader () {
783
            super ("org.openide.loaders.DefaultDataObject"); // NOI18N
784
            //super (DefaultDataObject.class);
785
        }
786
        
787
        /** Get default actions.
788
        * @return array of default system actions or <CODE>null</CODE> if this loader does not have any
789
        *   actions
790
        */
791
        protected SystemAction[] defaultActions () {
792
            return new SystemAction[] {
793
                    SystemAction.get (org.openide.actions.FileSystemAction.class),
794
                    null,
795
                    SystemAction.get (org.openide.actions.CutAction.class),
796
                    SystemAction.get (org.openide.actions.CopyAction.class),
797
                    SystemAction.get (org.openide.actions.PasteAction.class),
798
                    null,
799
                    SystemAction.get (org.openide.actions.DeleteAction.class),
800
                    SystemAction.get (org.openide.actions.RenameAction.class),
801
                    null,
802
                    SystemAction.get (org.openide.actions.ToolsAction.class),
803
                    SystemAction.get (org.openide.actions.PropertiesAction.class)
804
                };
805
        }
806
        
807
        /** Get the default display name of this loader.
808
        * @return default display name
809
        */
810
        protected String defaultDisplayName () {
811
            return NbBundle.getMessage (DataLoaderPool.class, "LBL_default_loader_display_name");
812
        }
813
        
814
        /** Get the primary file.
815
         * @param fo the file to find the primary file for
816
         *
817
         * @return the primary file
818
         */
819
        protected FileObject findPrimaryFile (FileObject fo) {
820
            // never recognize folders
821
            if (fo.isFolder()) return null;
822
            return fo;
888
            return fo;
823
        }
889
        }
824
        
890
        return null;
825
        /* Creates the right data object for given primary file.
826
         * It is guaranteed that the provided file is realy primary file
827
         * returned from the method findPrimaryFile.
828
         *
829
         * @param primaryFile the primary file
830
         * @return the data object for this file
831
         * @exception DataObjectExistsException if the primary file already has data object
832
         */
833
        protected MultiDataObject createMultiObject (FileObject primaryFile)
834
        throws DataObjectExistsException, java.io.IOException {
835
            return new DefaultDataObject(primaryFile, this);
836
        }
837
        
838
        /* Creates the right primary entry for given primary file.
839
         *
840
         * @param obj requesting object
841
         * @param primaryFile primary file recognized by this loader
842
         * @return primary entry for that file
843
         */
844
        protected MultiDataObject.Entry createPrimaryEntry (MultiDataObject obj, FileObject primaryFile) {
845
            return new FileEntry (obj, primaryFile);
846
        }
847
        
848
        /** Do not create a seconday entry.
849
         *
850
         * @param obj ignored
851
         * @param secondaryFile ignored
852
         * @return never returns
853
         * @exception UnsupportedOperationException because this loader supports only a primary file object
854
         */
855
        protected MultiDataObject.Entry createSecondaryEntry (MultiDataObject obj, FileObject secondaryFile) {
856
            throw new UnsupportedOperationException ();
857
        }
858
        
859
        /** Does nothing because this loader works only with objects
860
         * with one file => primary file so it is not necessary to search
861
         * for anything else.
862
         *
863
         * @param obj the object to test
864
         */
865
        void checkFiles (MultiDataObject obj) {
866
        }
867
    }
891
    }
868
    
892
869
    /** Loader for shadows, since 1.13 changed to UniFileLoader. */
893
    protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
870
    /*nbif compat
894
        return new FileEntry.Folder(obj, primaryFile);
871
    public
895
    }
872
    nbelse*/
896
873
    private
897
    protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
874
    /*nbend*/
898
        return new DataFolder (primaryFile);
875
    static class ShadowLoader extends UniFileLoader {
899
    }
876
        static final long serialVersionUID =-11013405787959120L;
900
877
        
901
    /** This method is used only in DataFolder.handleMove method.
878
        /* Adapter for listening on filesystems changes */
902
     * For more comments see {@link org.openide.loaders.DataFolder#handleMove}.
879
        private static ShadowChangeAdapter changeAdapter = new ShadowChangeAdapter();
903
     *
880
        
904
     * @param primaryFile the primary file of the datafolder to be created
881
        /* Representation class is DataShadow */
905
     * @param original The original DataFolder. The returned MultiDataObject 
882
        public ShadowLoader () {
906
     *      delegates createNodeDelegate and getClonedNodeDelegate methods calls
883
            super ("org.openide.loaders.DataShadow"); // NOI18N
907
     *      to the original DataFolder.
884
            //super (DataShadow.class);
908
     * @return The DataFolder that shares the nodes with the original DataFolder.
885
        }
909
     */
886
        
910
    MultiDataObject createMultiObject(FileObject primaryFile, final DataFolder original) throws DataObjectExistsException, IOException {
887
        /** Get the default display name of this loader.
911
        class NodeSharingDataFolder extends DataFolder {
888
        * @return default display name
912
            public NodeSharingDataFolder(FileObject fo) throws DataObjectExistsException, IllegalArgumentException {
889
        */
913
                super(fo);
890
        protected String defaultDisplayName () {
891
            return NbBundle.getMessage (DataLoaderPool.class, "LBL_shadow_loader_display_name");
892
        }
893
        
894
        /** For a given file finds the primary file.
895
         * @param fo the (secondary) file
896
         *
897
         * @return the primary file for the file or <code>null</code> if the file is not
898
         *  recognized by this loader
899
         */
900
        protected FileObject findPrimaryFile(FileObject fo) {
901
            if (fo.hasExt (DataShadow.SHADOW_EXTENSION)) {
902
                return fo;
903
            }
914
            }
904
            return null;
915
            protected Node createNodeDelegate() {
905
        }
916
                return new FilterNode(original.getNodeDelegate());
906
        
917
            }
907
        /** Creates the right primary entry for a given primary file.
918
            Node getClonedNodeDelegate (DataFilter filter) {
908
         *
919
                return new FilterNode(original.getClonedNodeDelegate(filter));
909
         * @param obj requesting object
910
         * @param primaryFile primary file recognized by this loader
911
         * @return primary entry for that file
912
         */
913
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
914
            return new FileEntry(obj, primaryFile);
915
        }
916
        
917
        /** Creates the right data object for a given primary file.
918
         * It is guaranteed that the provided file will actually be the primary file
919
         * returned by {@link #findPrimaryFile}.
920
         *
921
         * @param primaryFile the primary file
922
         * @return the data object for this file
923
         * @exception DataObjectExistsException if the primary file already has a data object
924
         */
925
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
926
            try {
927
                DataObject d = DataShadow.deserialize (primaryFile);
928
                if (d != null) return new DataShadow (primaryFile, d, this);
929
            } catch (IOException ex) {
930
                // broken link or damaged shadow file
931
            }
920
            }
932
            /* Link is broken, create BrokenDataShadow */
933
            return new BrokenDataShadow (primaryFile, this);
934
        }
935
        public void writeExternal(ObjectOutput oo) throws IOException {
936
        }
937
        public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException {
938
        }
921
        }
922
        return new NodeSharingDataFolder(primaryFile);
923
    }
924
925
    public void writeExternal(ObjectOutput oo) throws IOException {
939
    }
926
    }
940
}
927
    public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException {
928
    }
929
930
} // end of DataLoaderPool$FolderLoader
(-)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 (-2 / +12 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"/>
Lines 68-82 Link Here
68
            basedir="src"
69
            basedir="src"
69
            excludesfile="../nbbuild/standard-jar-excludes.txt"
70
            excludesfile="../nbbuild/standard-jar-excludes.txt"
70
            compress="false"
71
            compress="false"
71
            includes="org/netbeans/xtest/**" excludes="org/netbeans/xtest/pe/server*/**" />
72
            includes="org/netbeans/xtest/**" excludes="org/netbeans/xtest/pe/server*/**,org/netbeans/xtest/ide/**" />
72
73
74
            <!--
73
    <jar jarfile="lib/patches/testmain.jar"
75
    <jar jarfile="lib/patches/testmain.jar"
74
            manifest="manifest-subst.mf"
76
            manifest="manifest-subst.mf"
75
            basedir="src"
77
            basedir="src"
76
            compress="false">
78
            compress="false">
77
        <include name="org/netbeans/Main*.class"/>
79
        <include name="org/netbeans/Main*.class"/>
78
        <include name="org/netbeans/core/modules/"/>
80
        <include name="org/netbeans/core/modules/"/>
79
    </jar>        
81
    </jar>      
82
    -->  
83
    <jar jarfile="lib/xtest-ide.jar"
84
            manifest="manifest-subst.mf"
85
            basedir="src"
86
            compress="false">
87
        <include name="org/netbeans/xtest/ide/*.class"/>        
88
    </jar>      
80
    <copy file="${xtest.extra.home}/lib/junit.jar" todir="lib"/>
89
    <copy file="${xtest.extra.home}/lib/junit.jar" todir="lib"/>
81
    <copy file="${xtest.extra.home}/lib/xml-apis.jar" todir="lib"/>
90
    <copy file="${xtest.extra.home}/lib/xml-apis.jar" todir="lib"/>
82
    <copy file="${xtest.extra.home}/lib/xerces.jar" todir="lib"/>
91
    <copy file="${xtest.extra.home}/lib/xerces.jar" todir="lib"/>
Lines 108-113 Link Here
108
    </delete>
117
    </delete>
109
    <delete file="manifest-subst.mf"/>
118
    <delete file="manifest-subst.mf"/>
110
    <delete dir="lib/patches"/>
119
    <delete dir="lib/patches"/>
120
    <delete file="lib/xtest-ide.jar"/>
111
    <delete file="lib/xtest.jar"/>
121
    <delete file="lib/xtest.jar"/>
112
    <delete file="lib/junit-ext.jar"/>
122
    <delete file="lib/junit-ext.jar"/>
113
    <delete file="lib/junit.jar"/>
123
    <delete file="lib/junit.jar"/>
(-)nb_all/xtest/bin/xtest-pes.sh (-177 / +228 lines)
Lines 1-177 Link Here
1
#!/bin/sh
1
#!/bin/sh
2
#
2
#
3
#                 Sun Public License Notice
3
#                 Sun Public License Notice
4
# 
4
# 
5
# The contents of this file are subject to the Sun Public License
5
# The contents of this file are subject to the Sun Public License
6
# Version 1.0 (the "License"). You may not use this file except in
6
# Version 1.0 (the "License"). You may not use this file except in
7
# compliance with the License. A copy of the License is available at
7
# compliance with the License. A copy of the License is available at
8
# http://www.sun.com/
8
# http://www.sun.com/
9
# 
9
# 
10
# The Original Code is NetBeans. The Initial Developer of the Original
10
# The Original Code is NetBeans. The Initial Developer of the Original
11
# Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
11
# Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
12
# Microsystems, Inc. All Rights Reserved.
12
# Microsystems, Inc. All Rights Reserved.
13
13
14
#
14
#
15
# this script is a simple executor for Publishing Engine Server
15
# this script is a simple executor for Publishing Engine Server
16
#    - it handles running the code in an endless loop
16
#    - it handles running the code in an endless loop
17
#    - its basic behaviour is similar to other services
17
#    - its basic behaviour is similar to other services
18
#          available on Unix systems
18
#          available on Unix systems
19
#    - you can use:
19
#    - you can use:
20
#          'xtest-pes.sh run' to tun the server
20
#          'xtest-pes.sh run' to tun the server
21
#          'xtest-pes.sh stop' to stop the server
21
#          'xtest-pes.sh stop' to stop the server
22
#          'xtest-pes.sh kill' to kill the server
22
#          'xtest-pes.sh kill' to kill the server
23
#   
23
#   
24
24
25
25
26
# These variables needs to be updated to correspond your values
26
# These variables needs to be updated to correspond your values
27
27
28
# where is Publishing Engine Server installed
28
# where is Publishing Engine Server installed
29
#PES_HOME=/space/xtest-pes
29
# PES_HOME=/your/pes/home
30
30
31
# where is Ant
31
32
#ANT_HOME=/space/xtest-pes/jakarta-ant-1.4.1
32
# where is PES' config stored
33
33
#PES_CONFIG=/your/pes/config
34
# set all the Java stuff
34
35
#JAVA_HOME=/usr/j2sdk1_3_1_02
35
36
#JDK_HOME=$JAVA_HOME
36
# set all the Java stuff
37
#JAVA_PATH=$JAVA_HOME
37
#JAVA_HOME=/your/java/home
38
38
39
# add tit to path and export it
39
# sleep interval
40
#PATH=$ANT_HOME/bin:$JDK_HOME/bin:$PATH
40
SLEEP_INTERVAL=300
41
#export ANT_HOME JAVA_HOME JAVA_PATH JDK_HOME PATH
41
42
42
# logging level for pes, should be set to WARNING
43
#
43
PES_LOGGING_LEVEL=WARNING
44
# internal script stuff - you should not touch anything after this line
44
45
#
45
46
pes_status_file=xtest-pes.run
46
#
47
pes_stop_file=xtest-pes.stop
47
# internal script stuff - you should not touch anything after this line
48
SLEEP_INTERVAL=300
48
#
49
49
pes_status_file=xtest-pes.run
50
pes_server_run() {
50
pes_stop_file=xtest-pes.stop
51
51
52
    if [ -r "$PES_HOME/$pes_status_file" ]; then
52
53
	echo Another instance of XTest PES already running
53
pes_server_run() {
54
	return
54
55
    fi
55
    if [ -r "$PES_HOME/$pes_status_file" ]; then
56
56
	echo Another instance of XTest PES already running
57
    # create the flag file with PID in PES home
57
	return
58
    echo $$ >  $PES_HOME/$pes_status_file
58
    fi
59
59
60
    timer=0
60
    # create the flag file with PID in PES home
61
    check_interval=5
61
    echo $$ >  $PES_HOME/$pes_status_file
62
62
63
    while true
63
    timer=0
64
	do
64
    check_interval=5
65
65
66
	if [ "$timer" -eq 0 ]; then
66
    while true
67
	    echo Running ANT part of PES
67
	do
68
	    ant -f pes.xml 
68
69
	    echo ANT part finished
69
	if [ "$timer" -eq 0 ]; then
70
	fi
70
		pes_server_cmd 'run'
71
71
	fi
72
	timer=`expr $timer + $check_interval`
72
73
73
	timer=`expr $timer + $check_interval`
74
	# check if PES should be stopped
74
75
	if [ -r "$PES_HOME/$pes_stop_file" ]; then
75
	# check if PES should be stopped
76
	    echo Stopping XTest PES
76
	if [ -r "$PES_HOME/$pes_stop_file" ]; then
77
	    rm -f "$PES_HOME/$pes_stop_file"
77
	    echo `date`: Stopping XTest PES
78
	    rm -f "$PES_HOME/$pes_status_file"
78
	    rm -f "$PES_HOME/$pes_stop_file"
79
	    return
79
	    rm -f "$PES_HOME/$pes_status_file"
80
	fi
80
	    return
81
81
	fi
82
 	if [ "$timer" -ge "$SLEEP_INTERVAL" ]; then
82
83
	    timer=0
83
 	if [ "$timer" -ge "$SLEEP_INTERVAL" ]; then
84
	fi
84
	    timer=0
85
85
	fi
86
	#echo Sleeping for $SLEEP_INTERVAL seconds
86
87
	sleep $check_interval
87
	#echo Sleeping for $SLEEP_INTERVAL seconds
88
    done
88
	sleep $check_interval
89
89
    done
90
}
90
91
91
}
92
92
93
pes_server_stop() {
93
pes_server_reconfigure() {
94
    if [ ! -r "$PES_HOME/$pes_status_file" ]; then
94
95
	echo "XTest PES does not seem to run. Cannot stop"
95
    if [ -r "$PES_HOME/$pes_status_file" ]; then
96
	echo "You can try to $0 kill to kill the server"
96
	echo Another instance of XTest PES already running
97
	return
97
	return
98
    fi
98
    fi
99
    echo stopping xtest PES
99
100
    if [ -r "$PES_HOME/$pes_stop_file" ]; then
100
    # create the flag file with PID in PES home
101
	echo "Command $0 stop is already running"
101
    echo $$ >  $PES_HOME/$pes_status_file
102
	echo "If not, you can try to $0 kill to kill server"
102
	
103
	return
103
	# run pes
104
    fi
104
	pes_server_cmd 'reconfigure'
105
    
105
	
106
    # create the stop file and wait until run file is deleted
106
	# delete the status file	
107
    touch "$PES_HOME/$pes_stop_file"
107
	if [ -r "$PES_HOME/$pes_stop_file" ]; then
108
    echo "Waiting until XTest PES finished it's work"
108
	    rm -f "$PES_HOME/$pes_stop_file"
109
    while true; do
109
	fi	
110
	if [ ! -r "$PES_HOME/$pes_status_file" ]; then
110
}
111
	    echo "XTest PES stopped"
111
112
	    return
112
# runs pes command
113
	fi
113
pes_server_cmd() {
114
	# sleep for a second
114
	pes_cmd=${1:-run}	
115
	sleep 1
115
	# create PES' classpath
116
    done
116
   	pes_classpath=""
117
117
   	for i in ${PES_HOME}/lib/*.jar ; do
118
}
118
   		pes_classpath=${pes_classpath}:$i
119
119
   	done
120
120
   	cmd="$JAVA_HOME/bin/java -cp $pes_classpath -Dpes.logging.level=$PES_LOGGING_LEVEL -Dxtest.home=$PES_HOME -Dpes.config=$PES_CONFIG -Dpes.command=$pes_cmd org.netbeans.xtest.pe.server.PEServer"
121
pes_server_kill() {
121
#	echo running : $cmd
122
    if [ -r "$PES_HOME/$pes_status_file" ]; then
122
#	echo `date`: Running PES
123
	pid_to_kill=` cat $PES_HOME/$pes_status_file`
123
	eval $cmd
124
	echo "Killing xtest-pes with PID $pid_to_kill"
124
#	echo `date`: PES Done
125
	kill -9 $pid_to_kill
125
}
126
	rm -f "$PES_HOME/$pes_status_file" 
126
127
	if [ -r "$PES_HOME/$pes_stop_file" ]; then
127
128
	    rm -f "$PES_HOME/$pes_stop_file"
128
pes_server_stop() {
129
	fi
129
    if [ ! -r "$PES_HOME/$pes_status_file" ]; then
130
	return
130
	echo "XTest PES does not seem to run. Cannot stop"
131
    fi
131
	echo "You can try to $0 kill to kill the server"
132
132
	return
133
    if [ ! -r "$PES_HOME/$pes_status_file" ]; then
133
    fi
134
	echo "XTest PES does not seem to run."
134
    echo stopping xtest PES
135
	echo "You have to kill xtest-pes manually"
135
    if [ -r "$PES_HOME/$pes_stop_file" ]; then
136
    fi
136
	echo "Command $0 stop is already running"
137
}
137
	echo "If not, you can try to $0 kill to kill server"
138
138
	return
139
139
    fi
140
140
    
141
if [ -z "$PES_HOME" ]; then
141
    # create the stop file and wait until run file is deleted
142
    echo PES_HOME needs to be set to XTest PES home
142
    touch "$PES_HOME/$pes_stop_file"
143
    exit 1
143
    echo "Waiting until XTest PES finished it's work"
144
fi
144
    while true; do
145
145
	if [ ! -r "$PES_HOME/$pes_status_file" ]; then
146
cd $PES_HOME
146
	    echo "XTest PES stopped"
147
147
	    return
148
148
	fi
149
if [ -z "$ANT_HOME" ]; then
149
	# sleep for a second
150
    echo ANT_HOME needs to be set to ANT home directory
150
	sleep 1
151
fi
151
    done
152
152
153
case "$1" in
153
}
154
'run')
154
155
	echo 'Running XTest Publishing Server (PES)'
155
156
	pes_server_run
156
pes_server_kill() {
157
	;;
157
    if [ -r "$PES_HOME/$pes_status_file" ]; then
158
158
	pid_to_kill=` cat $PES_HOME/$pes_status_file`
159
'stop')
159
	echo "Killing xtest-pes with PID $pid_to_kill"
160
	echo 'Stopping XTest Publishing Server'
160
	kill -9 $pid_to_kill
161
	pes_server_stop
161
	rm -f "$PES_HOME/$pes_status_file" 
162
	;;
162
	if [ -r "$PES_HOME/$pes_stop_file" ]; then
163
163
	    rm -f "$PES_HOME/$pes_stop_file"
164
164
	fi
165
'kill') 
165
	return
166
	echo 'Killing XTest Publishing Server'
166
    fi
167
	pes_server_kill
167
168
	;;
168
    if [ ! -r "$PES_HOME/$pes_status_file" ]; then
169
169
	echo "XTest PES does not seem to run."
170
*)
170
	echo "You have to kill xtest-pes manually"
171
	echo "Usage: $0 { run | stop | kill}"
171
    fi
172
	exit 1
172
}
173
	;;
173
174
174
175
175
176
esac
176
if [ -z "$PES_HOME" ]; then
177
exit 0
177
    echo PES_HOME needs to be set to XTest PES home
178
    exit 1
179
fi
180
181
if [ -z "$PES_CONFIG" ]; then
182
    echo PES_CONFIG needs to be set to PES configuration file
183
    exit 1
184
fi
185
186
if [ -z "$JAVA_HOME" ]; then
187
    echo JAVA_HOME needs to be set to JDK 1.4 home
188
    exit 1
189
fi
190
191
cd $PES_HOME
192
193
194
case "$1" in
195
'run')
196
	echo `date`: Running XTest Publishing Engine Server
197
	pes_server_run
198
	;;
199
200
'start')
201
	echo `date`: Starting XTest Publishing Engine Server
202
	pes_server_run &
203
	;;
204
205
'stop')
206
	echo `date`: Stopping XTest Publishing Engine Server
207
	pes_server_stop
208
	;;
209
210
211
'kill') 
212
	echo `date`: Killing XTest Publishing Engine Server
213
	pes_server_kill
214
	;;
215
	
216
'reconfigure')
217
	echo `date`: Reconfiguring XTest Publishing Engine Server
218
	pes_server_reconfigure
219
	;;
220
221
*)
222
	echo "Usage: $0 { run | stop | kill | reconfigue}"
223
	exit 1
224
	;;
225
226
227
esac
228
exit 0
(-)nb_all/xtest/examples/MyModule/test/build-unit.xml (-1 / +1 lines)
Lines 36-42 Link Here
36
             this file will be searched in directories specified by property xtest.extra.jars.path 
36
             this file will be searched in directories specified by property xtest.extra.jars.path 
37
                 example: <property name="xtest.extra.jars" value="jemmy.jar;jelly.jar"/>
37
                 example: <property name="xtest.extra.jars" value="jemmy.jar;jelly.jar"/>
38
          -->
38
          -->
39
        <property name="xtest.extra.jars"     value="../mymodule.jar"/>
39
        <property name="xtest.extra.jars"     value="../mymodule.jar;${netbeans.home}/lib/openide.jar"/>
40
   
40
   
41
        <!-- These jars will be copied to directory ${netebans.home}/lib/ext.
41
        <!-- These jars will be copied to directory ${netebans.home}/lib/ext.
42
	     Again you can write only name of jar or zip file, not in which directory it is and 
42
	     Again you can write only name of jar or zip file, not in which directory it is and 
(-)nb_all/xtest/examples/MyModule/test/cfg-unit.xml (+9 lines)
Lines 62-67 Link Here
62
    <testbag testattribs="all and ide" executor="ide" name="all tests (in ide)" resultsprocessor="unit">
62
    <testbag testattribs="all and ide" executor="ide" name="all tests (in ide)" resultsprocessor="unit">
63
        <testset dir="unit/src">
63
        <testset dir="unit/src">
64
            <patternset>
64
            <patternset>
65
		<include name="**.class"/>
66
		
67
            </patternset>
68
        </testset>
69
    </testbag>
70
    
71
    <testbag testattribs="all and ide" executor="ide" name="all tests (in ide) 2" resultsprocessor="unit">
72
        <testset dir="unit/src">
73
            <patternset>
65
		<include name="HelloWorldTest.class"/>
74
		<include name="HelloWorldTest.class"/>
66
		<include name="myorg/*.class"/>
75
		<include name="myorg/*.class"/>
67
            </patternset>
76
            </patternset>
(-)nb_all/xtest/examples/MyModule/test/unit/src/HelloWorldTest.java (+15 lines)
Lines 41-46 Link Here
41
        greeting = testObject.greeting();
41
        greeting = testObject.greeting();
42
        assert(null != greeting);
42
        assert(null != greeting);
43
    }
43
    }
44
    
45
    public void testKill() {
46
        
47
        System.out.println("testKill");
48
        /*
49
        try {
50
        	Thread.sleep(100000);
51
        } catch (InterruptedException ie) {
52
        	System.out.println("InterruptedException: "+ie);
53
        }
54
        */
55
        
56
    }
57
    
58
    
44
    public void testGreeting2() throws IOException {
59
    public void testGreeting2() throws IOException {
45
        File test;
60
        File test;
46
        File pass;
61
        File pass;
(-)nb_all/xtest/instance/master-config.xml (+1 lines)
Lines 22-27 Link Here
22
      <module name="core" testtypes="unit" attributes="stable"/>
22
      <module name="core" testtypes="unit" attributes="stable"/>
23
      <module name="java" testtypes="unit" attributes="stable"/>
23
      <module name="java" testtypes="unit" attributes="stable"/>
24
      <module name="openide" testtypes="unit" attributes="stable"/>
24
      <module name="openide" testtypes="unit" attributes="stable"/>
25
      <module name="openide/compat" testtypes="unit" attributes="stable"/>
25
      <module name="openidex" testtypes="unit" attributes="stable"/>
26
      <module name="openidex" testtypes="unit" attributes="stable"/>
26
  </config>
27
  </config>
27
  
28
  
(-)nb_all/xtest/lib/module_harness.xml (-1 / +18 lines)
Lines 283-297 Link Here
283
283
284
        <ide-jvmargs jvmargs="${xtest.jvmargs}" property="xtest.ide.commandline.jvmargs"/>
284
        <ide-jvmargs jvmargs="${xtest.jvmargs}" property="xtest.ide.commandline.jvmargs"/>
285
            
285
            
286
        <!--
286
        <property name="args" value="-jdkhome ${jdkhome} -userdir &quot;${xtest.userdir}&quot; -nosplash -cp:p &quot;${xtest.ide.path}&quot; -J-Dtest.class=${test.class} -J-Dtest.classpath=&quot;${test.classpath}&quot; -J-Dtest.basedir=&quot;${basedir}&quot; -J-Dtest.ant.file=&quot;${ant.file}&quot; -J-Dtest.target=${test.target} -J-Dtest.reuse.ide=${xtest.reuse.ide} -J-Dxtest.home=&quot;${xtest.home}&quot; -J-Dxtest.includes=&quot;${xtest.includes}&quot; -J-Dxtest.excludes=&quot;${xtest.excludes}&quot; -J-Dtbag.classpath=&quot;${tbag.classpath}&quot; -J-Dtbag.patternset.include=${tbag.patternset.include} -J-Dtbag.patternset.exclude=${tbag.patternset.exclude} -J-Dtbag.testtype=${tbag.testtype} -J-Dtbag.formater=${tbag.formater} -J-Dtbag.name=&quot;${tbag.name}&quot; -J-Dtbag.executor=${tbag.executor} -J-Dxtest.module=&quot;${xtest.module}&quot; -J-Dxtest.attribs=&quot;${xtest.attribs}&quot; -J-Dxtest.distexec=true -J-Dtest.exit=${xtest.ide.exit} -J-Dtest.propertyfile=&quot;${test.propertyfile}&quot; -J-Dxtest.workdir=&quot;${xtest.workdir}&quot; -J-Dxtest.results=&quot;${xtest.results}&quot; -J-Dxtest.results.testrun.dir=&quot;${xtest.results.testrun.dir}&quot; -J-Dtest.output.redirect=true -J-Dnetbeans.full.hack=true -J-Djunit.properties.file=${junit.properties.file} -J-Dnetbeans.windows=${xtest.ide.winsys} -J-Dxtest.error.manager=${xtest.error.manager} ${xtest.ide.commandline.jvmargs} ${xtest.ide.commandline.suffix}"/>
287
        <property name="args" value="-jdkhome ${jdkhome} -userdir &quot;${xtest.userdir}&quot; -nosplash -cp:p &quot;${xtest.ide.path}&quot; -J-Dtest.class=${test.class} -J-Dtest.classpath=&quot;${test.classpath}&quot; -J-Dtest.basedir=&quot;${basedir}&quot; -J-Dtest.ant.file=&quot;${ant.file}&quot; -J-Dtest.target=${test.target} -J-Dtest.reuse.ide=${xtest.reuse.ide} -J-Dxtest.home=&quot;${xtest.home}&quot; -J-Dxtest.includes=&quot;${xtest.includes}&quot; -J-Dxtest.excludes=&quot;${xtest.excludes}&quot; -J-Dtbag.classpath=&quot;${tbag.classpath}&quot; -J-Dtbag.patternset.include=${tbag.patternset.include} -J-Dtbag.patternset.exclude=${tbag.patternset.exclude} -J-Dtbag.testtype=${tbag.testtype} -J-Dtbag.formater=${tbag.formater} -J-Dtbag.name=&quot;${tbag.name}&quot; -J-Dtbag.executor=${tbag.executor} -J-Dxtest.module=&quot;${xtest.module}&quot; -J-Dxtest.attribs=&quot;${xtest.attribs}&quot; -J-Dxtest.distexec=true -J-Dtest.exit=${xtest.ide.exit} -J-Dtest.propertyfile=&quot;${test.propertyfile}&quot; -J-Dxtest.workdir=&quot;${xtest.workdir}&quot; -J-Dxtest.results=&quot;${xtest.results}&quot; -J-Dxtest.results.testrun.dir=&quot;${xtest.results.testrun.dir}&quot; -J-Dtest.output.redirect=true -J-Dnetbeans.full.hack=true -J-Djunit.properties.file=${junit.properties.file} -J-Dnetbeans.windows=${xtest.ide.winsys} -J-Dxtest.error.manager=${xtest.error.manager} ${xtest.ide.commandline.jvmargs} ${xtest.ide.commandline.suffix}"/>
288
        -->
289
        
290
        <property name="args" value="-jdkhome ${jdkhome} -userdir &quot;${xtest.userdir}&quot; -nosplash -cp:p &quot;${xtest.ide.path}&quot; -J-Dnetbeans.mainclass=org.netbeans.xtest.ide.Main -J-Dtest.class=${test.class} -J-Dtest.classpath=&quot;${test.classpath}&quot; -J-Dtest.basedir=&quot;${basedir}&quot; -J-Dtest.ant.file=&quot;${ant.file}&quot; -J-Dtest.target=${test.target} -J-Dtest.reuse.ide=${xtest.reuse.ide} -J-Dxtest.home=&quot;${xtest.home}&quot; -J-Dxtest.includes=&quot;${xtest.includes}&quot; -J-Dxtest.excludes=&quot;${xtest.excludes}&quot; -J-Dtbag.classpath=&quot;${tbag.classpath}&quot; -J-Dtbag.patternset.include=${tbag.patternset.include} -J-Dtbag.patternset.exclude=${tbag.patternset.exclude} -J-Dtbag.testtype=${tbag.testtype} -J-Dtbag.formater=${tbag.formater} -J-Dtbag.name=&quot;${tbag.name}&quot; -J-Dtbag.executor=${tbag.executor} -J-Dxtest.module=&quot;${xtest.module}&quot; -J-Dxtest.attribs=&quot;${xtest.attribs}&quot; -J-Dxtest.distexec=true -J-Dtest.exit=${xtest.ide.exit} -J-Dtest.propertyfile=&quot;${test.propertyfile}&quot; -J-Dxtest.workdir=&quot;${xtest.workdir}&quot; -J-Dxtest.results=&quot;${xtest.results}&quot; -J-Dxtest.results.testrun.dir=&quot;${xtest.results.testrun.dir}&quot; -J-Dtest.output.redirect=true -J-Dnetbeans.full.hack=true -J-Djunit.properties.file=${junit.properties.file} -J-Dnetbeans.windows=${xtest.ide.winsys} -J-Dxtest.error.manager=${xtest.error.manager} ${xtest.ide.commandline.jvmargs} ${xtest.ide.commandline.suffix}"/>
291
        
287
        <echo message="ARGUMENTS = ${args}"/>
292
        <echo message="ARGUMENTS = ${args}"/>
288
293
294
        <!--
289
        <copy file="${xtest.home}/lib/patches/testmain.jar" todir="${netbeans.home}/lib/patches"/>
295
        <copy file="${xtest.home}/lib/patches/testmain.jar" todir="${netbeans.home}/lib/patches"/>
296
        -->
297
        <!--
298
        <copy file="${xtest.home}/lib/xtest-ide.jar" todir="${netbeans.home}/lib"/>
290
        <copy file="${xtest.home}/lib/xtest.jar" todir="${netbeans.home}/lib/ext"/>
299
        <copy file="${xtest.home}/lib/xtest.jar" todir="${netbeans.home}/lib/ext"/>
291
        <copy file="${xtest.home}/lib/xtest-ext.jar" todir="${netbeans.home}/lib/ext"/>
300
        <copy file="${xtest.home}/lib/xtest-ext.jar" todir="${netbeans.home}/lib/ext"/>
292
        <copy file="${xtest.home}/lib/junit.jar" todir="${netbeans.home}/lib/ext"/>
301
        <copy file="${xtest.home}/lib/junit.jar" todir="${netbeans.home}/lib/ext"/>
293
        <copy file="${xtest.home}/lib/junit-ext.jar" todir="${netbeans.home}/lib/ext"/>
302
        <copy file="${xtest.home}/lib/junit-ext.jar" todir="${netbeans.home}/lib/ext"/>
294
 
303
        -->
304
        <copy file="${xtest.home}/lib/xtest-ide.jar" todir="${netbeans.home}/lib"/>
305
        <copy file="${xtest.home}/lib/xtest.jar" todir="${netbeans.home}/lib"/>
306
        <copy file="${xtest.home}/lib/xtest-ext.jar" todir="${netbeans.home}/lib"/>
307
        <copy file="${xtest.home}/lib/junit.jar" todir="${netbeans.home}/lib"/>
308
        <copy file="${xtest.home}/lib/junit-ext.jar" todir="${netbeans.home}/lib"/>
295
 	<antcall target="copy-user-jars"/>
309
 	<antcall target="copy-user-jars"/>
296
 	
310
 	
297
 	<condition property="xtest.ide.timeout" value="0">
311
 	<condition property="xtest.ide.timeout" value="0">
Lines 311-317 Link Here
311
            <arg line="runide.sh ${args}"/>
325
            <arg line="runide.sh ${args}"/>
312
        </ideexec>
326
        </ideexec>
313
327
328
        <!--
314
        <delete file="${netbeans.home}/lib/patches/testmain.jar"/>
329
        <delete file="${netbeans.home}/lib/patches/testmain.jar"/>
330
        -->
331
        <delete file="${netbeans.home}/lib/xtest-ide.jar"/>
315
        <delete file="${netbeans.home}/lib/ext/xtest.jar"/>
332
        <delete file="${netbeans.home}/lib/ext/xtest.jar"/>
316
        <delete file="${netbeans.home}/lib/ext/xtest-ext.jar"/>
333
        <delete file="${netbeans.home}/lib/ext/xtest-ext.jar"/>
317
        <delete file="${netbeans.home}/lib/ext/junit.jar"/>
334
        <delete file="${netbeans.home}/lib/ext/junit.jar"/>
(-)nb_all/xtest/src/org/netbeans/Main.java (-644 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-2000 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans;
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] 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,"XTest: Stopping task (via Execution Engine): "+task.toString() );
105
                    task.stop();
106
                    int result = task.result();
107
                    errMan.log(ErrorManager.USER,"XTest: 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.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
    
202
    /** Starts the IDE.
203
     * @param args the command line arguments
204
     */
205
    public static void main(String args[]) {
206
        
207
        // create the IDE flag file
208
        String workdir = System.getProperty("xtest.workdir");
209
        if (workdir!=null) {
210
            // create flag file indicating running tests
211
            ideRunning = new File(workdir,"ide.flag");
212
            File idePID = new File(workdir,"ide.pid");
213
            PrintWriter writer = null;
214
             try {
215
                ideRunning.createNewFile();
216
                idePID.createNewFile();
217
                writer = new PrintWriter(new FileOutputStream(idePID));
218
                // get my pid
219
                JNIKill kill = new JNIKill();
220
                long myPID = kill.getMyPID();
221
                System.out.println("IDE is running under PID:"+myPID);
222
                writer.println(myPID);
223
            } catch (IOException ioe) {
224
                System.out.println("cannot create flag file:"+ideRunning);
225
                ideRunning = null;
226
            } catch (Throwable e) {
227
                System.out.println("There was a problem: " + e);
228
            } finally {
229
                if (writer != null)
230
                	writer.close();
231
            }
232
        } else {
233
            System.out.println("cannot get xtest.workdir property - it has to be set to a valid working directory");
234
        }
235
        
236
        // do the expected stuff
237
        try {
238
           org.netbeans.core.Main.main(args);
239
        }
240
        catch (Exception e) {
241
           e.printStackTrace();
242
           exit();
243
        }
244
245
        // install XTest error manager (only if xtest.error.manager=true)
246
        // and openide version > 2
247
248
        // get openide version - if sys property is not found - assume it is version 0
249
        float openideVersion = 0;
250
        try {
251
            openideVersion = Float.parseFloat(System.getProperty("org.openide.specification.version","0"));
252
        } catch (NumberFormatException nfe) {
253
            // property is not found - go on with 0
254
        }
255
        
256
        if (System.getProperty("xtest.error.manager","false").equals("true")) {
257
            if (openideVersion > 2.0) {                
258
                boolean result = installXTestErrorManager();
259
                if (result==false) {
260
                    System.out.println("Cannot install XTestErrorManager");
261
                } else {
262
                    System.setProperty("xtest.error.manager","installed");
263
                }                
264
            } else {
265
                System.out.println("OpenIDE version must be over 2.0 to use XTestErrorManager");
266
                System.out.println("Current version is "+openideVersion);
267
            }
268
        }
269
    
270
271
        
272
273
        
274
        // get the static ErrorManager instance
275
        errMan = TopManager.getDefault().getErrorManager();
276
        
277
        // some threads may be still active, wait for the event queue to become quiet
278
        Thread initThread = new Thread(new Runnable() {
279
            public void run() {
280
                try {
281
                    new QueueEmpty().waitEventQueueEmpty(2000);
282
                }
283
                catch (Exception ex) {
284
                    TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex);
285
                }
286
            }
287
        });
288
        // start the init thread
289
        initThread.start();
290
        try {
291
            initThread.join(60000L);  // wait 1 minute at the most
292
        }
293
        catch (InterruptedException iex) {
294
            errMan.notify(ErrorManager.EXCEPTION, iex);
295
            
296
        }
297
        if (initThread.isAlive()) {
298
            // time-out expired, event queue still busy -> interrupt the init thread
299
            errMan.log(ErrorManager.USER, new Date().toString() + ": EventQueue still busy, starting anyway.");
300
            initThread.interrupt();
301
        }
302
        // ok. The IDE should be up and fully initialized
303
        // let's run the test now
304
        try {
305
            doTestPart();
306
        }
307
        catch (RuntimeException ex) {
308
            ex.printStackTrace();
309
        }
310
    }
311
    
312
    
313
    private static final String TEST_CLASS = "test.class";
314
    private static final String TEST_CLASSPATH = "test.classpath";
315
    private static final String TEST_ARGS = "test.arguments";
316
    private static final String TEST_EXECUTOR = "test.executor";
317
    private static final String TEST_EXIT = "test.exit";
318
    private static final String TEST_FINISHED = "test.finished";
319
    private static final String TEST_TIMEOUT = "test.timeout";
320
    private static final String TEST_REDIRECT = "test.output.redirect";
321
    private static final String TEST_REUSE_IDE = "test.reuse.ide";
322
    
323
    private static final long DEFAULT_TIMEOUT = 30;
324
    
325
    private static void doTestPart() {
326
        
327
        long testTimeout;
328
        
329
        // do nothing if no TEST_CLASS specified
330
        if (System.getProperty(TEST_CLASS) == null)
331
            return;                
332
        
333
        if (System.getProperty(TEST_REDIRECT) != null && System.getProperty(TEST_REDIRECT).equals("true")) {
334
            ((OutputSettings) Lookup.getDefault().lookup( OutputSettings.class )).setRedirection(true);
335
        }
336
        
337
        try {
338
            // default timeout is 30 minutes
339
            testTimeout = Long.parseLong(System.getProperty(TEST_TIMEOUT, "30"));
340
        }
341
        catch (NumberFormatException ex) {
342
            testTimeout = DEFAULT_TIMEOUT;
343
        }
344
        if (testTimeout <= 0) {
345
            testTimeout = DEFAULT_TIMEOUT;
346
        }
347
        // convert to milis
348
        testTimeout *= 60000L;
349
        
350
        StringTokenizer st = new StringTokenizer(System.getProperty(TEST_ARGS, ""));
351
        final String[] params = new String[st.countTokens()];
352
        int i = 0;
353
        while (st.hasMoreTokens()) {
354
            params[i++] = st.nextToken();
355
        }
356
        
357
        final long startTime = System.currentTimeMillis();
358
        final long testTime = testTimeout;
359
        Thread testThread = new Thread( new Runnable() {
360
            public void run() {
361
                try {
362
                    
363
                    // setup the repository
364
                    if (System.getProperty(TEST_CLASSPATH) != null && 
365
                        System.getProperty(TEST_REUSE_IDE, "false").equals("false")) {
366
                            mountFileSystems();
367
                    }
368
                     
369
                    setNodeProperties();
370
                    
371
                    ExecInfo ei = new org.openide.execution.ExecInfo(System.getProperty(TEST_CLASS), params);
372
                    Executor exec = (Executor)Class.forName(System.getProperty(TEST_EXECUTOR, "org.openide.execution.ThreadExecutor")).newInstance();
373
                    
374
                    if (exec != null) {
375
                        System.setProperty(TEST_FINISHED, "false");
376
                        ExecutorTask task = exec.execute(ei);
377
                        
378
                        while (System.getProperty(TEST_FINISHED).equals("false")) {
379
                          try {
380
                            Thread.sleep(2000);
381
                          }
382
                          catch (InterruptedException e) {
383
                            long currentTime = System.currentTimeMillis();
384
                            if (startTime + testTime + 10000 > currentTime) {
385
                                break;
386
                            } 
387
                            else {
388
                                errMan.log(ErrorManager.USER, new Date().toString() + ": False InterruptedException. Continuing running tests");
389
                            }
390
                          } 
391
                        }
392
                    }
393
                }
394
                catch (Exception ex) {
395
                    TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex);
396
                }
397
            }
398
        });
399
        
400
        errMan.log(ErrorManager.USER, new Date().toString() + ": just starting.");
401
        // start the test thread
402
        testThread.start();
403
        try {
404
            testThread.join(testTimeout);
405
        }
406
        catch (InterruptedException iex) {
407
            errMan.notify(ErrorManager.EXCEPTION, iex);
408
        }
409
        if (testThread.isAlive()) {
410
            // time-out expired, test not finished -> interrupt
411
            errMan.log(ErrorManager.USER, new Date().toString() + ": time-out expired - interrupting! ***");
412
            ideInterrupted = true;
413
            testThread.interrupt();
414
        }
415
        
416
        // we're leaving IDE 
417
        // delete the flag file (if ide was not interrupted)
418
        if (ideRunning!=null) {
419
            if (!ideInterrupted) {
420
                if (ideRunning.delete()==false) {
421
                    System.out.println("Cannot delete the flag file "+ideRunning);
422
                }
423
            }
424
        }
425
        
426
        // close IDE
427
        if (System.getProperty(TEST_EXIT, "false").equals("true")) {
428
            Thread exitThread = new Thread(new Runnable() {
429
                public void run() {
430
                    // terminate all running processes
431
                    try {
432
                        terminateProcesses();
433
                    } catch (Exception e) {
434
                        System.out.println("Exception when terminating processes started from IDE");
435
                        e.printStackTrace();
436
                    }
437
                    TopManager.getDefault().exit();
438
                }
439
            });
440
            // try to exit nicely first
441
            errMan.log(ErrorManager.USER, new Date().toString() + ": soft exit attempt.");
442
            exitThread.start();
443
            try {
444
                // wait 90 seconds for the IDE to exit
445
                exitThread.join(90000);
446
            }
447
            catch (InterruptedException iex) {
448
                errMan.notify(ErrorManager.EXCEPTION, iex);
449
            }
450
            if (exitThread.isAlive()) {
451
                // IDE refuses to shutdown, terminate unconditionally
452
                errMan.log(ErrorManager.USER, new Date().toString() + ": hard exit attempt!!!.");
453
                exitThread.interrupt();
454
                exit();
455
            }
456
        }
457
    }
458
    
459
    private static void exit() {
460
        try {
461
           Class param[] = new Class[1];
462
           param[0] = int.class;
463
           Class c = org.netbeans.core.execution.TopSecurityManager.class;
464
           java.lang.reflect.Method m = c.getMethod("exit",param);
465
           Integer intparam[] = {new Integer(1)};
466
           errMan.log(ErrorManager.USER, new Date().toString() + ": using TopSecurityManager.exit(1) to exit IDE.");
467
           // exit
468
           m.invoke(null,intparam);
469
        }
470
        catch (Exception e) {
471
           errMan.log(ErrorManager.USER, new Date().toString() + ": using System.exit(1) to exit IDE.");
472
           // exit
473
           System.exit(1);
474
        }
475
    }
476
    
477
    
478
    private static void mountFileSystems() {
479
        Repository repo = TopManager.getDefault().getRepository();
480
        
481
        // unmount the currently mounted filesystems
482
        // (could be more sofisticated some day)
483
        Enumeration all = repo.getFileSystems();
484
        while (all.hasMoreElements()) {
485
            FileSystem fs = (FileSystem)all.nextElement();
486
            // preserve the hidden and default filesystems
487
            if (!fs.isHidden() && !fs.isDefault())
488
                repo.removeFileSystem(fs);
489
        }        
490
        // mount new filesystems as specified in TEST_CLASSPATH
491
        StringTokenizer stok = new StringTokenizer(System.getProperty(TEST_CLASSPATH), System.getProperty("path.separator"));
492
        while (stok.hasMoreElements()) {
493
            String pathelem = stok.nextToken();
494
            try {
495
                if (pathelem.endsWith(".jar") || pathelem.endsWith(".zip")) {
496
                    JarFileSystem jfs = new JarFileSystem();
497
                    jfs.setJarFile(new java.io.File(pathelem));
498
                    repo.addFileSystem(jfs);
499
                }
500
                else {
501
                    LocalFileSystem lfs = new LocalFileSystem();
502
                    lfs.setRootDirectory(new java.io.File(pathelem));
503
                    repo.addFileSystem(lfs);
504
                }
505
            }
506
            catch (Exception ex) {
507
                TopManager.getDefault().getErrorManager().notify(ErrorManager.EXCEPTION, ex);
508
            }
509
        }
510
    }
511
    
512
    
513
    private static void setNodeProperties() {
514
        FileObject fo = TopManager.getDefault().getRepository().findResource(System.getProperty(TEST_CLASS) + ".java");
515
        if (fo != null) {
516
            try {
517
                DataObject obj = DataObject.find(fo);
518
                Node nod = obj.getNodeDelegate();
519
                Node.PropertySet[] psets = nod.getPropertySets();
520
                Node.Property[] props = null;
521
                
522
                // get the Execution property set
523
                for (int i = 0; i < psets.length; i++) {
524
                    if (psets[i].getName().equals("Execution")) {
525
                        props = psets[i].getProperties();
526
                        break;
527
                    }
528
                }
529
                // get the "params" property and try to set it
530
                if (props != null) {
531
                    for (int i = 0; i < props.length; i++) {
532
                        if (props[i].getName().equals("params")) {
533
                            if (System.getProperty(TEST_ARGS) != null) {
534
                                props[i].setValue(System.getProperty(TEST_ARGS));
535
                            }
536
                        }
537
                    }
538
                }
539
            }
540
            catch (java.lang.Exception ex) {
541
                // ok, not able to set the Arguments property
542
                // it's still worth trying to proceed with the test
543
                // the FileObject may just be read-only
544
            }
545
            
546
        }
547
        
548
    }
549
    
550
551
    private static class QueueEmpty implements java.awt.event.AWTEventListener {
552
        
553
        private long eventDelayTime = 100; // 100 millis
554
        private long lastEventTime;
555
        
556
        /** Creates a new QueueEmpty instance */
557
        public QueueEmpty() {
558
        }
559
        
560
        /** method called every time when AWT Event is dispatched
561
         * @param event event dispatched from AWT Event Queue
562
         */
563
        public void eventDispatched(java.awt.AWTEvent awtEvent) {
564
            lastEventTime = System.currentTimeMillis();
565
        }
566
        
567
        /** constructor with user defined value
568
         * @param eventdelaytime maximum delay between two events of one redraw action
569
         */
570
        public synchronized void waitEventQueueEmpty(long eventDelayTime) throws InterruptedException {
571
            this.eventDelayTime = eventDelayTime;
572
            waitEventQueueEmpty();
573
        }
574
        
575
        /** Waits until the AWTEventQueue is empty for a specified interval
576
         */
577
        public synchronized void waitEventQueueEmpty() throws InterruptedException {
578
            // store current time as the start time
579
            long startTime = System.currentTimeMillis();
580
            // register itself as an AWTEventListener
581
            Toolkit.getDefaultToolkit().addAWTEventListener(this,
582
            AWTEvent.ACTION_EVENT_MASK |
583
            AWTEvent.ADJUSTMENT_EVENT_MASK |
584
            AWTEvent.COMPONENT_EVENT_MASK |
585
            AWTEvent.CONTAINER_EVENT_MASK |
586
            AWTEvent.FOCUS_EVENT_MASK |
587
            AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK |
588
            AWTEvent.HIERARCHY_EVENT_MASK |
589
            AWTEvent.INPUT_METHOD_EVENT_MASK |
590
            AWTEvent.INVOCATION_EVENT_MASK |
591
            AWTEvent.ITEM_EVENT_MASK |
592
            AWTEvent.KEY_EVENT_MASK |
593
            AWTEvent.MOUSE_EVENT_MASK |
594
            AWTEvent.MOUSE_MOTION_EVENT_MASK |
595
            AWTEvent.PAINT_EVENT_MASK |
596
            AWTEvent.TEXT_EVENT_MASK |
597
            AWTEvent.WINDOW_EVENT_MASK);
598
            
599
            // set last event time to the current time
600
            lastEventTime=System.currentTimeMillis();
601
            // get the thread to be put asleep
602
            Thread t = Thread.currentThread();
603
            // get current AWT Event Queue
604
            EventQueue queue=Toolkit.getDefaultToolkit().getSystemEventQueue();
605
            
606
            try {
607
                
608
                // while AWT Event Queue is not empty and timedelay from last event is shorter then eventdelaytime
609
                
610
                //wait till the queue is empty
611
                while ( queue.peekEvent() != null ) Thread.currentThread().sleep(100);
612
                //test it - post my own task and wait for it
613
                synchronized(this){
614
                    Runnable r = new Runnable() {
615
                        public void run() {
616
                            synchronized(QueueEmpty.this){QueueEmpty.this.notifyAll();}
617
                        }
618
                    };
619
                    queue.invokeLater(r);
620
                    wait();
621
                }
622
                //now 2 sec continuously should be silence
623
                while (System.currentTimeMillis() - lastEventTime < eventDelayTime) {
624
                    //sleep for the rest of eventDelay time
625
                    t.sleep(eventDelayTime + lastEventTime - System.currentTimeMillis());
626
                }
627
628
                //if (queue.peekEvent()==null) System.out.println("The AWT event queue seems to be empty.");
629
                //else System.out.println("Ops, in the AWT event queue still seems to be some tasks!");
630
631
            }
632
            catch (InterruptedException ex) {
633
                throw ex;
634
            }
635
            finally {
636
                //removing from listeners
637
                Toolkit.getDefaultToolkit().removeAWTEventListener(this);
638
            }
639
        }
640
        
641
        
642
    }
643
}
644
(-)nb_all/xtest/src/org/netbeans/core/modules/Module.java (-942 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
// THIS CLASS OUGHT NOT USE NbBundle NOR org.openide CLASSES
17
// OUTSIDE OF openide-util.jar! UI AND FILESYSTEM/DATASYSTEM
18
// INTERACTIONS SHOULD GO ELSEWHERE.
19
// (NbBundle.getLocalizedValue is OK here.)
20
21
import org.openide.modules.ModuleInfo;
22
import org.openide.ErrorManager;
23
import java.io.*;
24
import java.util.*;
25
import java.util.jar.*;
26
import java.net.URL;
27
import java.security.*;
28
import org.openide.util.NbBundle;
29
import java.util.zip.ZipEntry;
30
import org.openide.modules.SpecificationVersion;
31
import org.openide.modules.Dependency;
32
33
/** Object representing one module, possibly installed.
34
 * Responsible for opening of module JAR file; reading
35
 * manifest; parsing basic information such as dependencies;
36
 * and creating a classloader for use by the installer.
37
 * Methods not defined in ModuleInfo must be called from within
38
 * the module manager's read mutex as a rule.
39
 * @author Jesse Glick
40
 */
41
public final class Module extends ModuleInfo {
42
    
43
    public static final String PROP_RELOADABLE = "reloadable"; // NOI18N
44
    public static final String PROP_CLASS_LOADER = "classLoader"; // NOI18N
45
    public static final String PROP_MANIFEST = "manifest"; // NOI18N
46
    public static final String PROP_VALID = "valid"; // NOI18N
47
    public static final String PROP_PROBLEMS = "problems"; // NOI18N
48
    
49
    /** manager which owns this module */
50
    private final ModuleManager mgr;
51
    /** event logging (should not be much here) */
52
    private final Events ev;
53
    /** associated history object
54
     * @see ModuleHistory
55
     */
56
    private final Object history;
57
    /** JAR file holding the module */
58
    private final File jar;
59
    /** if reloadable, temporary JAR file actually loaded from */
60
    private File physicalJar = null;
61
    /** true if currently enabled; manipulated by ModuleManager */
62
    private boolean enabled;
63
    /** whether it is supposed to be easily reloadable */
64
    private boolean reloadable;
65
    /** whether it is supposed to be automatically loaded when required */
66
    private final boolean autoload;
67
    /** if true, this module is eagerly turned on whenever it can be */
68
    private final boolean eager;
69
    /** module manifest */
70
    private Manifest manifest;
71
    /** code name base (no slash) */
72
    private String codeNameBase;
73
    /** code name release, or -1 if undefined */
74
    private int codeNameRelease;
75
    /** provided tokens */
76
    private String[] provides;
77
    /** set of dependencies parsed from manifest */
78
    private Set dependencies;
79
    /** specification version parsed from manifest, or null */
80
    private SpecificationVersion specVers;
81
    /** currently active module classloader */
82
    private ClassLoader classloader = null;
83
    /** localized properties, or null to use only manifest */
84
    private Properties localizedProps;
85
    
86
    /** Map from extension JARs to sets of JAR that load them via Class-Path.
87
     * Used only for debugging purposes, so that a warning is printed if two
88
     * different modules try to load the same extension (which would cause them
89
     * to both load their own private copy, which may not be intended).
90
     */
91
    private static final Map extensionOwners = new HashMap(); // Map<File,Set<File>>
92
93
    /** Set of locale-variants JARs for this module.
94
     * Added explicitly to classloader, and can be used by execution engine.
95
     */
96
    private final Set localeVariants = new HashSet(); // Set<File>
97
    /** Set of extension JARs that this module loads via Class-Path.
98
     * Can be used e.g. by execution engine. (#9617)
99
     */
100
    private final Set plainExtensions = new HashSet(); // Set<File>
101
    /** Set of localized extension JARs derived from plainExtensions.
102
     * Used to add these to the classloader. (#9348)
103
     * Can be used e.g. by execution engine.
104
     */
105
    private final Set localeExtensions = new HashSet(); // Set<File>
106
107
    /** Use ModuleManager.create as a factory. */
108
    Module(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
109
        if (autoload && eager) throw new IllegalArgumentException("A module may not be both autoload and eager"); // NOI18N
110
        this.mgr = mgr;
111
        this.ev = ev;
112
        this.jar = jar;
113
        this.history = history;
114
        this.reloadable = reloadable;
115
        this.autoload = autoload;
116
        this.eager = eager;
117
        enabled = false;
118
        loadManifest();
119
        parseManifest();
120
    }
121
    
122
    
123
     /**  hack !!! - old (release33) constructor */
124
     Module(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload) throws IOException {
125
        this(mgr,ev,jar,history,reloadable,autoload,false);
126
    }
127
128
    
129
    
130
    /** Create a special-purpose "fixed" JAR. */
131
    Module(ModuleManager mgr, Events ev, Manifest manifest, Object history, ClassLoader classloader) throws InvalidException {
132
        this.mgr = mgr;
133
        this.ev = ev;
134
        this.manifest = manifest;
135
        this.history = history;
136
        this.classloader = classloader;
137
        jar = null;
138
        reloadable = false;
139
        autoload = false;
140
        eager = false;
141
        enabled = false;
142
        parseManifest();
143
    }
144
    
145
    /** Get the associated module manager. */
146
    public ModuleManager getManager() {
147
        return mgr;
148
    }
149
    
150
    public boolean isEnabled() {
151
        return enabled;
152
    }
153
    
154
    // Access from ModuleManager:
155
    void setEnabled(boolean enabled) {
156
        /* #13647: actually can happen if loading of bootstrap modules is rolled back:
157
        if (isFixed() && ! enabled) throw new IllegalStateException("Cannot disable a fixed module: " + this); // NOI18N
158
        */
159
        this.enabled = enabled;
160
    }
161
    
162
    /** Normally a module once created and managed is valid
163
     * (that is, either installed or not, but at least managed).
164
     * If it is deleted any remaining references to it become
165
     * invalid.
166
     */
167
    public boolean isValid() {
168
        return mgr.get(getCodeNameBase()) == this;
169
    }
170
    
171
    /** Is this module automatically loaded?
172
     * If so, no information about its state is kept
173
     * permanently beyond the existence of its JAR file;
174
     * it is enabled when some real module needs it to be,
175
     * and disabled when this is no longer the case.
176
     * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=9779">#9779</a>
177
     */
178
    public boolean isAutoload() {
179
        return autoload;
180
    }
181
    
182
    /** Is this module eagerly enabled?
183
     * If so, no information about its state is kept permanently.
184
     * It is turned on whenever it can be, i.e. whenever it meets all of
185
     * its dependencies. This may be used to implement "bridge" modules with
186
     * simple functionality that just depend on two normal modules.
187
     * A module may not be simultaneously eager and autoload.
188
     * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=17501">#17501</a>
189
     * @since org.netbeans.core/1 1.3
190
     */
191
    public boolean isEager() {
192
        return eager;
193
    }
194
    
195
    /** Get an associated arbitrary attribute.
196
     * Right now, simply provides the main attributes of the manifest.
197
     * In the future some of these could be suppressed (if only of dangerous
198
     * interest, e.g. Class-Path) or enhanced with other information available
199
     * from the core (if needed).
200
     */
201
    public Object getAttribute(String attr) {
202
        return getManifest().getMainAttributes().getValue(attr);
203
    }
204
    
205
    /** Get a localized attribute.
206
     * First, if OpenIDE-Module-Localizing-Bundle was given, the specified
207
     * bundle file (in all locale JARs as well as base JAR) is searched for
208
     * a key of the specified name.
209
     * Otherwise, the manifest's main attributes are searched for an attribute
210
     * with the specified name, possibly with a locale suffix.
211
     * If the attribute name contains a slash, and there is a manifest section
212
     * named according to the part before the last slash, then this section's attributes
213
     * are searched instead of the main attributes, and for the attribute listed
214
     * after the slash. Currently this would only be useful for localized filesystem
215
     * names. E.g. you may request the attribute org/foo/MyFileSystem.class/Display-Name.
216
     * In the future certain attributes known to be dangerous could be
217
     * explicitly suppressed from this list; should only be used for
218
     * documented localizable attributes such as OpenIDE-Module-Name etc.
219
     */
220
    public Object getLocalizedAttribute(String attr) {
221
        if (localizedProps != null) {
222
            // Permit localized attributes to be defined in a separate bundle.
223
            String val = localizedProps.getProperty(attr);
224
            if (val != null) {
225
                return val;
226
            }
227
        }
228
        int idx = attr.lastIndexOf('/'); // NOI18N
229
        if (idx == -1) {
230
            // Simple main attribute.
231
            return NbBundle.getLocalizedValue(getManifest().getMainAttributes(), new Attributes.Name(attr));
232
        } else {
233
            // Attribute of a manifest section.
234
            String section = attr.substring(0, idx);
235
            String realAttr = attr.substring(idx + 1);
236
            Attributes attrs = getManifest().getAttributes(section);
237
            if (attrs != null) {
238
                return NbBundle.getLocalizedValue(attrs, new Attributes.Name(realAttr));
239
            } else {
240
                return null;
241
            }
242
        }
243
    }
244
    
245
    public String getCodeName() {
246
        return (String)getAttribute("OpenIDE-Module"); // NOI18N
247
    }
248
    
249
    public String getCodeNameBase() {
250
        return codeNameBase;
251
    }
252
    
253
    public int getCodeNameRelease() {
254
        return codeNameRelease;
255
    }
256
    
257
    public String[] getProvides() {
258
        return provides;
259
    }
260
    /** Test whether the module provides a given token or not. */
261
    final boolean provides(String token) {
262
        for (int i = 0; i < provides.length; i++) {
263
            if (provides[i].equals(token)) {
264
                return true;
265
            }
266
        }
267
        return false;
268
    }
269
    
270
    public Set getDependencies() {
271
        return dependencies;
272
    }
273
    // Just for binary compatibility, this is not the real impl in core:
274
    final Dependency[]  getDependenciesArray() {
275
        return (Dependency[])dependencies.toArray(new Dependency[dependencies.size()]);
276
    }
277
    
278
    public SpecificationVersion getSpecificationVersion() {
279
        return specVers;
280
    }
281
    
282
    public boolean owns(Class clazz) {
283
        ClassLoader cl = clazz.getClassLoader();
284
        if (cl instanceof Util.ModuleProvider) {
285
            return ((Util.ModuleProvider) cl).getModule() == this;
286
        }
287
        return false;
288
        
289
    }
290
    
291
    /** Original parseManifest - will decide whether to call
292
     *  parseManifest_New for trunk release or parseManifest_Old 
293
     * for release 33
294
     */
295
    private void parseManifest() throws InvalidException {
296
        // have to use reflection and try to obtain
297
        // ModuleManager.refineDependencies()
298
        // if any problem is encountered with reflection -- fallback to 
299
        // the new version of parseManifest
300
        try {
301
            Class parameterTypes[] = new Class[2];
302
            parameterTypes[0] = this.getClass();
303
            parameterTypes[1] = Set.class;
304
            java.lang.reflect.Method aMethod = mgr.getClass().getDeclaredMethod("refineDependencies",parameterTypes);                        
305
            // good call parseManifest_New() - in finally blockk;
306
        } catch (NoSuchMethodException nsme) {
307
            // using old parseManifest
308
            //System.out.println("XTest hack in org.netbeans.core.modules.Module.java: using old parseManifest()");
309
            parseManifest_Old();
310
            return;
311
        } catch (Throwable t) {  
312
            // any problem - use new parseManifest            
313
            //System.out.println("XTest hack in org.netbeans.core.modules.Module.java: using new parseManifest() cannot get info on ModuleManager");
314
            parseManifest_New();        
315
        }
316
        //System.out.println("XTest hack in org.netbeans.core.modules.Module.java: using new parseManifest()");
317
        parseManifest_New(); 
318
        
319
    }
320
    
321
    
322
    /** Parse information from the current manifest.
323
     * Includes code name, specification version, and dependencies.
324
     * If anything is in an invalid format, throws an exception with
325
     * some kind of description of the problem.
326
     */
327
    private void parseManifest_New() throws InvalidException {
328
        Attributes attr = manifest.getMainAttributes();
329
        // Code name
330
        String codeName = attr.getValue("OpenIDE-Module"); // NOI18N
331
        if (codeName == null) throw new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + /* #17629: important! */jar); // NOI18N
332
        try {
333
            // This has the side effect of checking syntax:
334
            if (codeName.indexOf(',') != -1) {
335
                throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module: " + codeName); // NOI18N
336
            }
337
            Dependency.create(Dependency.TYPE_MODULE, codeName);
338
            int idx = codeName.lastIndexOf('/'); // NOI18N
339
            if (idx == -1) {
340
                codeNameBase = codeName;
341
                codeNameRelease = -1;
342
            } else {
343
                codeNameBase = codeName.substring(0, idx);
344
                codeNameRelease = Integer.parseInt(codeName.substring(idx + 1));
345
            }
346
            // Spec vers
347
            String specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); // NOI18N
348
            if (specVersS != null) {
349
                try {
350
                    specVers = new SpecificationVersion(specVersS);
351
                } catch (NumberFormatException nfe) {
352
                    InvalidException ie = new InvalidException("While parsing OpenIDE-Module-Specification-Version: " + nfe.toString()); // NOI18N
353
                    Util.err.annotate(ie, nfe);
354
                    throw ie;
355
                }
356
            } else {
357
                specVers = null;
358
            }
359
            // Token provides
360
            String providesS = attr.getValue("OpenIDE-Module-Provides"); // NOI18N
361
            if (providesS == null) {
362
                provides = new String[] {};
363
            } else {
364
                StringTokenizer tok = new StringTokenizer(providesS, ", "); // NOI18N
365
                provides = new String[tok.countTokens()];
366
                for (int i = 0; i < provides.length; i++) {
367
                    String provide = tok.nextToken();
368
                    if (provide.indexOf(',') != -1) {
369
                        throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module-Provides: " + provide); // NOI18N
370
                    }
371
                    Dependency.create(Dependency.TYPE_MODULE, provide);
372
                    if (provide.lastIndexOf('/') != -1) throw new IllegalArgumentException("Illegal OpenIDE-Module-Provides: " + provide);
373
                    provides[i] = provide;
374
                }
375
                if (new HashSet(Arrays.asList(provides)).size() < provides.length) {
376
                    throw new IllegalArgumentException("Duplicate entries in OpenIDE-Module-Provides: " + providesS);
377
                }
378
            }
379
            // Dependencies
380
            Set dependencies = new HashSet(20); // Set<Dependency>
381
            dependencies.addAll(Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies"))); // NOI18N
382
            dependencies.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); // NOI18N
383
            dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); // NOI18N
384
            dependencies.addAll(Dependency.create(Dependency.TYPE_PACKAGE, attr.getValue("OpenIDE-Module-Package-Dependencies"))); // NOI18N
385
            dependencies.addAll(Dependency.create(Dependency.TYPE_REQUIRES, attr.getValue("OpenIDE-Module-Requires"))); // NOI18N
386
            // Permit the concrete installer to make some changes:
387
            mgr.refineDependencies(this, dependencies);
388
            // Now copy (avoid synch problems):
389
            this.dependencies = Collections.unmodifiableSet(dependencies);
390
        } catch (IllegalArgumentException iae) {
391
            InvalidException ie = new InvalidException("While parsing a dependency attribute: " + iae.toString()); // NOI18N
392
            Util.err.annotate(ie, iae);
393
            throw ie;
394
        }
395
    }
396
397
    /** Old version of parse manifest - for release33 compatibility 
398
     *  Use at your own risk
399
     */
400
    private void parseManifest_Old() throws InvalidException {
401
        Attributes attr = manifest.getMainAttributes();
402
        // Code name
403
        String codeName = attr.getValue("OpenIDE-Module"); // NOI18N
404
        if (codeName == null) throw new InvalidException("Not a module: no OpenIDE-Module tag"); // NOI18N
405
        try {
406
            // This has the side effect of checking syntax:
407
            if (codeName.indexOf(',') != -1) {
408
                throw new InvalidException("Illegal code name syntax: " + codeName); // NOI18N
409
            }
410
            Dependency.create(Dependency.TYPE_MODULE, codeName);
411
            int idx = codeName.lastIndexOf('/'); // NOI18N
412
            if (idx == -1) {
413
                codeNameBase = codeName;
414
                codeNameRelease = -1;
415
            } else {
416
                codeNameBase = codeName.substring(0, idx);
417
                codeNameRelease = Integer.parseInt(codeName.substring(idx + 1));
418
            }
419
            // Spec vers
420
            String specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); // NOI18N
421
            if (specVersS != null) {
422
                try {
423
                    specVers = new SpecificationVersion(specVersS);
424
                } catch (NumberFormatException nfe) {
425
                    InvalidException ie = new InvalidException(nfe.toString());
426
                    Util.err.annotate(ie, nfe);
427
                    throw ie;
428
                }
429
            } else {
430
                specVers = null;
431
            }
432
            // Dependencies
433
            Set dependencies = new HashSet(20); // Set<Dependency>
434
            dependencies.addAll(Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies"))); // NOI18N
435
            dependencies.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); // NOI18N
436
            dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); // NOI18N
437
            dependencies.addAll(Dependency.create(Dependency.TYPE_PACKAGE, attr.getValue("OpenIDE-Module-Package-Dependencies"))); // NOI18N
438
            // Now copy (avoid synch problems):
439
            this.dependencies = Collections.unmodifiableSet(dependencies);
440
        } catch (IllegalArgumentException iae) {
441
            InvalidException ie = new InvalidException(iae.toString());
442
            Util.err.annotate(ie, iae);
443
            throw ie;
444
        }
445
    }
446
    
447
    
448
    
449
    /** Get the JAR this module is packaged in.
450
     * May be null for modules installed specially, e.g.
451
     * automatically from the classpath.
452
     * @see #isFixed
453
     */
454
    public File getJarFile() {
455
        return jar;
456
    }
457
    
458
    /** Check if this is a "fixed" module.
459
     * Fixed modules are installed automatically (e.g. based on classpath)
460
     * and cannot be uninstalled or manipulated in any way.
461
     */
462
    public boolean isFixed() {
463
        return jar == null;
464
    }
465
466
    /** Create a temporary test JAR if necessary.
467
     * This is primarily necessary to work around a Java bug,
468
     * #4405789, which might be fixed in 1.4--check up on this.
469
     */
470
    private void ensurePhysicalJar() throws IOException {
471
        if (reloadable && physicalJar == null) {
472
            physicalJar = Util.makeTempJar(jar);
473
        }
474
    }
475
    private void destroyPhysicalJar() {
476
        if (physicalJar != null) {
477
            if (! physicalJar.delete()) {
478
                Util.err.log(ErrorManager.WARNING, "Warning: temporary JAR " + physicalJar + " not currently deletable.");
479
            } else {
480
                Util.err.log("deleted: " + physicalJar);
481
            }
482
            physicalJar = null;
483
        } else {
484
            Util.err.log("no physicalJar to delete for " + this);
485
        }
486
    }
487
    
488
    /** Open the JAR, load its manifest, and do related things. */
489
    private void loadManifest() throws IOException {
490
        Util.err.log("loading manifest of " + jar);
491
        JarFile jarFile;
492
        if (reloadable) {
493
            ensurePhysicalJar();
494
            jarFile = new JarFile(physicalJar);
495
        } else {
496
            jarFile = new JarFile(jar);
497
        }
498
        try {
499
            Manifest m = jarFile.getManifest();
500
            findExtensionsAndVariants(m);
501
            loadLocalizedProps(jarFile, m);
502
            manifest = m;
503
        } finally {
504
            jarFile.close();
505
        }
506
    }
507
    
508
    /** Find any extensions loaded by the module, as well as any localized
509
     * variants of the module or its extensions.
510
     */
511
    private void findExtensionsAndVariants(Manifest m) {
512
        localeVariants.clear();
513
        localeVariants.addAll(Util.findLocaleVariantsOf(jar, false));
514
        plainExtensions.clear();
515
        localeExtensions.clear();
516
        String classPath = m.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
517
        if (classPath != null) {
518
            StringTokenizer tok = new StringTokenizer(classPath);
519
            while (tok.hasMoreTokens()) {
520
                String ext = tok.nextToken();
521
                File extfile = new File(jar.getParentFile(), ext.replace('/', File.separatorChar));
522
                if (! extfile.exists()) {
523
                    // Ignore unloadable extensions.
524
                    continue;
525
                }
526
                synchronized (extensionOwners) {
527
                    Set owners = (Set)extensionOwners.get(extfile);
528
                    if (owners == null) {
529
                        owners = new HashSet(2);
530
                        owners.add(jar);
531
                        extensionOwners.put(extfile, owners);
532
                    } else if (! owners.contains(jar)) {
533
                        owners.add(jar);
534
                        ev.log(Events.EXTENSION_MULTIPLY_LOADED, extfile, owners);
535
                    } // else already know about it (OK or warned)
536
                }
537
                plainExtensions.add(extfile);
538
                localeExtensions.addAll(Util.findLocaleVariantsOf(extfile, false));
539
            }
540
        }
541
        Util.err.log("localeVariants of " + jar + ": " + localeVariants);
542
        Util.err.log("plainExtensions of " + jar + ": " + plainExtensions);
543
        Util.err.log("localeExtensions of " + jar + ": " + localeExtensions);
544
    }
545
    
546
    /** Check if there is any need to load localized properties.
547
     * If so, try to load them. Throw an exception if they cannot
548
     * be loaded for some reason. Uses an open JAR file for the
549
     * base module at least, though may also open locale variants
550
     * as needed.
551
     * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=12549">#12549</a>
552
     */
553
    private void loadLocalizedProps(JarFile jarFile, Manifest m) throws IOException {
554
        String locbundle = m.getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
555
        if (locbundle != null) {
556
            // Something requested, read it in.
557
            // locbundle is a resource path.
558
            {
559
                ZipEntry bundleFile = jarFile.getEntry(locbundle);
560
                // May not be present in base JAR: might only be in e.g. default locale variant.
561
                if (bundleFile != null) {
562
                    localizedProps = new Properties();
563
                    InputStream is = jarFile.getInputStream(bundleFile);
564
                    try {
565
                        localizedProps.load(is);
566
                    } finally {
567
                        is.close();
568
                    }
569
                }
570
            }
571
            {
572
                // Check also for localized variant JARs and load in anything from them as needed.
573
                // Note we need to go in the reverse of the usual search order, so as to
574
                // overwrite less specific bundles with more specific.
575
                int idx = locbundle.lastIndexOf('.'); // NOI18N
576
                String name, ext;
577
                if (idx == -1) {
578
                    name = locbundle;
579
                    ext = ""; // NOI18N
580
                } else {
581
                    name = locbundle.substring(0, idx);
582
                    ext = locbundle.substring(idx);
583
                }
584
                List pairs = Util.findLocaleVariantsOf(jar, true);
585
                Collections.reverse(pairs);
586
                Iterator it = pairs.iterator();
587
                while (it.hasNext()) {
588
                    Object[] pair = (Object[])it.next();
589
                    File localeJar = (File)pair[0];
590
                    String suffix = (String)pair[1];
591
                    String rsrc = name + suffix + ext;
592
                    JarFile localeJarFile = new JarFile(localeJar);
593
                    try {
594
                        ZipEntry bundleFile = localeJarFile.getEntry(rsrc);
595
                        // Need not exist in all locale variants.
596
                        if (bundleFile != null) {
597
                            if (localizedProps == null) {
598
                                localizedProps = new Properties();
599
                            } // else append and overwrite base-locale values
600
                            InputStream is = localeJarFile.getInputStream(bundleFile);
601
                            try {
602
                                localizedProps.load(is);
603
                            } finally {
604
                                is.close();
605
                            }
606
                        }
607
                    } finally {
608
                        localeJarFile.close();
609
                    }
610
                }
611
            }
612
            if (localizedProps == null) {
613
                // We should have loaded from at least some bundle in there...
614
                throw new IOException("Could not find localizing bundle: " + locbundle); // NOI18N
615
            }
616
            /* Don't log; too large and annoying:
617
            if (Util.err.isLoggable(ErrorManager.UNKNOWN)) {
618
                Util.err.log("localizedProps=" + localizedProps);
619
            }
620
            */
621
        }
622
    }
623
624
    /** Get all JARs loaded by this module.
625
     * Includes the module itself, any locale variants of the module,
626
     * any extensions specified with Class-Path, any locale variants
627
     * of those extensions.
628
     * If patches are implemented (#9273), the list will be in classpath order (patches first).
629
     * Currently the temp JAR is provided in the case of test modules, to prevent
630
     * sporadic ZIP file exceptions when background threads (like Java parsing) tries
631
     * to open libraries found in the library path.
632
     * JARs already present in the classpath are <em>not</em> listed.
633
     * @return a <code>List&lt;File&gt;</code> of JARs
634
     */
635
    public List getAllJars() {
636
        if (jar == null) {
637
            // Classpath module.
638
            return Collections.EMPTY_LIST;
639
        }
640
        List l = new ArrayList (); // List<File>
641
        l.add (reloadable ? physicalJar : jar);
642
        l.addAll (plainExtensions);
643
        l.addAll (localeVariants);
644
        l.addAll (localeExtensions);
645
        return l;
646
    }
647
648
    /** Is this module supposed to be easily reloadable?
649
     * If so, it is suitable for testing inside the IDE.
650
     * Controls whether a copy of the JAR file is made before
651
     * passing it to the classloader, which can affect locking
652
     * and refreshing of the JAR.
653
     */
654
    public boolean isReloadable() {
655
        return reloadable;
656
    }
657
    
658
    /** Set whether this module is supposed to be reloadable.
659
     * Has no immediate effect, only impacts what happens the
660
     * next time it is enabled (after having been disabled if
661
     * necessary).
662
     */
663
    public void setReloadable(boolean r) {
664
        if (isFixed()) throw new IllegalStateException();
665
        if (reloadable != r) {
666
            reloadable = r;
667
            mgr.fireReloadable(this);
668
        }
669
    }
670
    
671
    /** Used as a flag to tell if this module was really successfully released.
672
     * Currently does not work, so if it cannot be made to work, delete it.
673
     * (Someone seems to be holding a strong reference to the classloader--who?!)
674
     */
675
    private transient boolean released;
676
    /** Count which release() call is really being checked. */
677
    private transient int releaseCount = 0;
678
679
    /** Reload this module. Access from ModuleManager.
680
     * If an exception is thrown, the module is considered
681
     * to be in an invalid state.
682
     */
683
    void reload() throws IOException {
684
        if (isFixed()) throw new IllegalStateException();
685
        // Probably unnecessary but just in case:
686
        destroyPhysicalJar();
687
        String codeNameBase1 = getCodeNameBase();
688
        localizedProps = null;
689
        loadManifest();
690
        parseManifest();
691
        String codeNameBase2 = getCodeNameBase();
692
        if (! codeNameBase1.equals(codeNameBase2)) {
693
            throw new InvalidException("Code name base changed during reload: " + codeNameBase1 + " -> " + codeNameBase2); // NOI18N
694
        }
695
    }
696
    
697
    /** Get the classloader capable of retrieving
698
     * things from this module.
699
     * If the module is disabled, this will be null (unless this module is fixed).
700
     * If it is enabled, it must not be null.
701
     * It is not guaranteed that change events will be fired
702
     * for changes in this property.
703
     */
704
    public ClassLoader getClassLoader() {
705
        return classloader;
706
    }
707
    // Access from ModuleManager:
708
    /** Turn on the classloader. Passed a list of parent modules to use.
709
     * The parents should already have had their classloaders initialized.
710
     */
711
    void classLoaderUp(Set parents) throws IOException {
712
        if (isFixed()) return; // no need
713
        Util.err.log("classLoaderUp on " + this + " with parents " + parents);
714
        // Find classloaders for dependent modules and parent to them.
715
        ClassLoader[] loaders = new ClassLoader[parents.size()];
716
        Iterator it = parents.iterator();
717
        int i = 0;
718
        while (it.hasNext()) {
719
            Module parent = (Module)it.next();
720
            loaders[i++] = parent.getClassLoader();
721
        }
722
        List classp = new ArrayList(3); // List<File|JarFile>
723
        // #9273: load any modules/patches/this-code-name/*.jar files first:
724
        File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
725
                                 getCodeNameBase().replace('.', '-')); // NOI18N
726
        if (patchdir.isDirectory()) {
727
            File[] jars = patchdir.listFiles(Util.jarFilter());
728
            if (jars != null) {
729
                for (int j = 0; j < jars.length; j++) {
730
                    ev.log(Events.PATCH, jars[j]);
731
                    classp.add(new JarFile(jars[j]));
732
                }
733
            } else {
734
                Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir);
735
            }
736
        }
737
        
738
        // load tests by the same classloader as module classes
739
        // this classpath was formerly mounted to repository
740
        String testcp = System.getProperty("tbag.classpath");
741
        String xclname = System.getProperty("xtest.useclassloader");
742
        if ( xclname != null && xclname.equals ( getCodeNameBase() ) ) {
743
            if ( testcp != null ) {
744
                StringTokenizer stok = new StringTokenizer( testcp, System.getProperty("path.separator") );
745
                while ( stok.hasMoreElements() ) {
746
                    String testp = (String) stok.nextElement();
747
                    File testdir = new File ( testp );
748
                    if ( testdir.isDirectory() ) {
749
                        Util.err.log(ErrorManager.WARNING, "---> Adding test dir: " + testdir + " for " + getCodeNameBase());
750
                        File [] jars = testdir.listFiles( Util.jarFilter() );
751
                        if ( jars != null ) {
752
                            for ( int j = 0; j < jars.length; j++ ) {
753
                                // add all jar files
754
                                classp.add( new JarFile( jars[j] ) );
755
                            }
756
                        }
757
                        // add dir itself
758
                        classp.add ( (Object) testdir );
759
                    }
760
                }
761
            }
762
        }
763
        
764
        if (reloadable) {
765
            ensurePhysicalJar();
766
            classp.add(new JarFile(physicalJar));
767
        } else {
768
            classp.add(new JarFile(jar));
769
        }
770
        // URLClassLoader would not otherwise find these, so:
771
        for (it = localeVariants.iterator(); it.hasNext(); ) {
772
            classp.add(new JarFile((File)it.next()));
773
        }
774
        for (it = localeExtensions.iterator(); it.hasNext(); ) {
775
            File act = (File)it.next();
776
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act));
777
        }
778
        for( it = plainExtensions.iterator(); it.hasNext(); ) {
779
            File act = (File)it.next();
780
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act));
781
        }
782
        try {
783
            classloader = new OneModuleClassLoader(classp, loaders);
784
        } catch (IllegalArgumentException iae) {
785
            // Should not happen, but just in case.
786
            IOException ioe = new IOException(iae.toString());
787
            Util.err.annotate(ioe, iae);
788
            throw ioe;
789
        }
790
    }
791
    /** Turn off the classloader and release all resources. */
792
    void classLoaderDown() {
793
        if (isFixed()) return; // don't touch it
794
        if (classloader instanceof ProxyClassLoader) {
795
            // Remove references to it from other places, i.e. ModuleClassLoader:
796
            ((ProxyClassLoader)classloader).destroy();
797
        }
798
        classloader = null;
799
        Util.err.log("classLoaderDown on " + this + ": releaseCount=" + releaseCount + " released=" + released);
800
        released = false;
801
        System.gc(); // hope OneModuleClassLoader.finalize() is called...
802
        // but probably it won't be. See #4405807.
803
        if (! released) {
804
            Util.err.log("Warning: not all resources associated with module " + jar + " were successfully released.");
805
            released = true;
806
        } else {
807
            Util.err.log ("All resources associated with module " + jar + " were successfully released.");
808
        }
809
        destroyPhysicalJar();
810
    }
811
    /** For compat only! */
812
    void cleanup() {}
813
    void destroy() {}
814
    
815
    /** Get the JAR manifest.
816
     * Should never be null, even if disabled.
817
     * Might change if a module is reloaded.
818
     * It is not guaranteed that change events will be fired
819
     * for changes in this property.
820
     */
821
    public Manifest getManifest() {
822
        return manifest;
823
    }
824
    
825
    /** Get a set of {@link org.openide.modules.Dependency} objects representing missed dependencies.
826
     * This module is examined to see
827
     * why it would not be installable.
828
     * If it is enabled, there are no problems.
829
     * If it is in fact installable (possibly only
830
     * by also enabling some other managed modules which are currently disabled), and
831
     * all of its non-module dependencies are met, the returned set will be empty.
832
     * Otherwise it will contain a list of reasons why this module cannot be installed:
833
     * non-module dependencies which are not met; and module dependencies on modules
834
     * which either do not exist in the managed set, or are the wrong version,
835
     * or themselves cannot be installed
836
     * for some reason or another (which may be separately examined).
837
     * Note that in the (illegal) situation of two or more modules forming a cyclic
838
     * dependency cycle, none of them will be installable, and the missing dependencies
839
     * for each will be stated as the dependencies on the others. Again other modules
840
     * dependent on modules in the cycle will list failed dependencies on the cyclic modules.
841
     * Missing package dependencies are not guaranteed to be reported unless an install
842
     * of the module has already been attempted, and failed due to them.
843
     * The set may also contain {@link InvalidException}s representing known failures
844
     * of the module to be installed, e.g. due to classloader problems, missing runtime
845
     * resources, or failed ad-hoc dependencies. Again these are not guaranteed to be
846
     * reported unless an install has already been attempted and failed due to them.
847
     */
848
    public Set getProblems() {
849
        if (! isValid()) throw new IllegalStateException("Not valid: " + this); // NOI18N
850
        if (isEnabled()) return Collections.EMPTY_SET;
851
        return Collections.unmodifiableSet(mgr.missingDependencies(this));
852
    }
853
    
854
    // Access from ChangeFirer:
855
    final void firePropertyChange0(String prop, Object old, Object nue) {
856
        if (Util.err.isLoggable(ErrorManager.UNKNOWN)) {
857
            Util.err.log("Module.propertyChange: " + this + " " + prop + ": " + old + " -> " + nue);
858
        }
859
        firePropertyChange(prop, old, nue);
860
    }
861
    
862
    /** Get the history object representing what has happened to this module before.
863
     * @see ModuleHistory
864
     */
865
    public final Object getHistory() {
866
        return history;
867
    }
868
    
869
    /** String representation for debugging. */
870
    public String toString() {
871
        String s = "Module[" + getCodeNameBase() + "]"; // NOI18N
872
        if (!isValid()) s += "[invalid]"; // NOI18N
873
        return s;
874
    }
875
    
876
    /** PermissionCollection with an instance of AllPermission. */
877
    private static PermissionCollection modulePermissions;
878
    /** @return initialized @see #modulePermission */
879
    private static synchronized PermissionCollection getAllPermission() {
880
        if (modulePermissions == null) {
881
            modulePermissions = new Permissions();
882
            modulePermissions.add(new AllPermission());
883
            modulePermissions.setReadOnly();
884
        }
885
        return modulePermissions;
886
    }
887
888
    /** Class loader to load a single module.
889
     * Auto-localizing, multi-parented, permission-granting, the works.
890
     */
891
    private class OneModuleClassLoader extends JarClassLoader implements Util.ModuleProvider, Util.PackageAccessibleClassLoader {
892
        private int rc;
893
        /** Create a new loader for a module.
894
         * @param classp the List of all module jars of code directories;
895
         *      includes the module itself, its locale variants,
896
         *      variants of extensions and Class-Path items from Manifest.
897
         *      The items are JarFiles for jars and Files for directories
898
         * @param parents a set of parent classloaders (from other modules)
899
         */
900
        public OneModuleClassLoader(List classp, ClassLoader[] parents) throws IllegalArgumentException {
901
            super(classp, parents);
902
            rc = releaseCount++;
903
        }
904
        
905
        public Module getModule() {
906
            return Module.this;
907
        }
908
        
909
        /** Inherited.
910
         * @param cs is ignored
911
         * @return PermissionCollection with an AllPermission instance
912
         */
913
        protected PermissionCollection getPermissions(CodeSource cs) {
914
            return getAllPermission();
915
        }
916
        /** look for JNI libraries also in modules/bin/ */
917
        protected String findLibrary(String libname) {
918
            String mapped = System.mapLibraryName(libname);
919
            File lib = new File(new File(jar.getParentFile(), "bin"), mapped); // NOI18N
920
            if (lib.isFile()) {
921
                return lib.getAbsolutePath();
922
            } else {
923
                return null;
924
            }
925
        }
926
        public String toString() {
927
            return super.toString() + "[" + getCodeNameBase() + "]"; // NOI18N
928
        }
929
930
        protected void finalize() throws Throwable {
931
            super.finalize();
932
            Util.err.log("Finalize for " + this + ": rc=" + rc + " releaseCount=" + releaseCount + " released=" + released); // NOI18N
933
            if (rc == releaseCount) {
934
                // Hurrah! release() worked.
935
                released = true;
936
            } else {
937
                Util.err.log("Now resources for " + getCodeNameBase() + " have been released."); // NOI18N
938
            }
939
        }
940
    }
941
942
}
(-)nb_all/xtest/src/org/netbeans/xtest/NbMultiTaskDef.java (-2 / +4 lines)
Lines 24-30 Link Here
24
import java.util.LinkedList;
24
import java.util.LinkedList;
25
import java.util.Iterator;
25
import java.util.Iterator;
26
26
27
import org.openide.TopManager;
27
//import org.openide.TopManager;
28
28
29
/**
29
/**
30
 *
30
 *
Lines 72-78 Link Here
72
    public void execute () throws BuildException {
72
    public void execute () throws BuildException {
73
        if (null != System.getProperty("test.ant.file")) {
73
        if (null != System.getProperty("test.ant.file")) {
74
            log("Using Netbeans classloader.", Project.MSG_DEBUG);
74
            log("Using Netbeans classloader.", Project.MSG_DEBUG);
75
            loader = TopManager.getDefault().currentClassLoader();
75
            //loader = org.openide.TopManager.getDefault().currentClassLoader();
76
            loader = Thread.currentThread().getContextClassLoader();
77
            System.out.println("NetBeans class loader: "+loader);
76
        }
78
        }
77
79
78
        if (classpath != null) {
80
        if (classpath != null) {
(-)nb_all/xtest/src/org/netbeans/xtest/XTestErrorManager.java (-157 lines)
Removed Link Here
1
/*
2
 * XTestErrorManager.java
3
 *
4
 * Created on April 24, 2002, 3:52 PM
5
 */
6
7
package org.netbeans.xtest;
8
9
import org.openide.ErrorManager;
10
import org.openide.ErrorManager.Annotation;
11
import org.openide.TopManager;
12
import org.netbeans.core.TopLogging;
13
import java.util.*;
14
import java.io.*;
15
import java.lang.ref.*;
16
17
/**
18
 *
19
 * @author  mb115822
20
 */
21
public class XTestErrorManager extends ErrorManager  {
22
    
23
24
    
25
    // here's XTest ErrorManager
26
    private static ErrorManager errorManager = null;
27
    
28
29
    // here are stored notifications
30
    private static StringBuffer errorLog = new StringBuffer();        
31
    
32
    // getter for notifications
33
    public static synchronized String getNotifications() {
34
        if (errorLog.length() > 0) {
35
            return errorLog.toString();
36
        } else {
37
            return null;
38
        }
39
    }
40
    
41
    // clear stuff for notifications
42
    public static synchronized void clearNotifications() {
43
        errorLog = new StringBuffer();
44
    }
45
    
46
47
    // get if there were any notifications and clear the status
48
    public static synchronized boolean anyNotifications() {
49
        if (getNotifications() == null) {
50
            return false;
51
        } else {
52
            clearNotifications();
53
            return true;
54
        }
55
    }
56
    
57
        
58
    
59
    /** Creates new NbExceptionManager. */
60
    public XTestErrorManager() {
61
        if (errorManager == null) {
62
            errorManager = this;
63
        }
64
    }
65
    
66
    
67
    
68
    public org.openide.ErrorManager getInstance(String name)  {
69
        return getInstance();
70
    }
71
    
72
    public static org.openide.ErrorManager getInstance() {
73
         if (errorManager == null) {
74
            errorManager = new XTestErrorManager();
75
        }
76
        return errorManager;
77
    }
78
    
79
    /** Adds these values. All the
80
     * previous annotations are kept and this new is added at
81
     * the top of the annotation stack (index 0 of the annotation
82
     * array).
83
     *
84
     * @param severity integer describing severity (one of const values
85
     *   from this class)
86
     * @param date date or null
87
     * @param message message to attach to the exception or null
88
     * @param localizedMessage localized message for the user or null
89
     * @param stackTrace exception representing the stack trace or null
90
     */
91
    public synchronized Throwable annotate(
92
    Throwable t,
93
    int severity, String message, String localizedMessage,
94
    Throwable stackTrace, java.util.Date date
95
    ) {
96
        return null;
97
    }
98
    
99
    
100
    /** Associates annotations with this thread.
101
     *
102
     * @param arr array of annotations (or null)
103
     */
104
    public synchronized Throwable attachAnnotations(Throwable t, Annotation[] arr) {      
105
        return null;
106
    }
107
    
108
    /** Notifies all the exceptions associated with
109
     * this thread.
110
     * @param clear should the current exception be cleared or not?
111
     */
112
    public synchronized void notify(int severity, Throwable t) {
113
        // synchronized to ensure that only one exception is
114
        // written to the thread
115
        
116
        
117
        if (severity > ErrorManager.USER ) {
118
            // let's print the stuff to theByteArray ....
119
            
120
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
121
            
122
            PrintWriter ps = new PrintWriter(bs);
123
            
124
            ps.println("*********** Exception occured ************"); // NOI18N
125
            
126
            // log into the byte array
127
            t.printStackTrace(ps);
128
            
129
            ps.flush();
130
            
131
            ps.close();
132
            
133
            // add the notification to the string buffer
134
            errorLog.append(bs.toString()+"\n");
135
        /*
136
        ErrorManager.getDefault().log(ErrorManager.ERROR,"#\n#\n############# XTestEM notification: "+t+"\n#\n#\n");
137
         */
138
        }
139
    }
140
    
141
    
142
    /** Finds annotations associated with given exception.
143
     * @param t the exception
144
     * @return array of annotations or null
145
     */
146
    public synchronized Annotation[] findAnnotations(Throwable t) {
147
        return null;
148
    }
149
    
150
    // log !!!
151
    public void log(int severity, String s) {
152
    }
153
       
154
    
155
    
156
    
157
}
(-)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-2000 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 (+157 lines)
Added Link Here
1
/*
2
 * XTestErrorManager.java
3
 *
4
 * Created on April 24, 2002, 3:52 PM
5
 */
6
7
package org.netbeans.xtest.ide;
8
9
import org.openide.ErrorManager;
10
import org.openide.ErrorManager.Annotation;
11
import org.openide.TopManager;
12
import org.netbeans.core.TopLogging;
13
import java.util.*;
14
import java.io.*;
15
import java.lang.ref.*;
16
17
/**
18
 *
19
 * @author  mb115822
20
 */
21
public class XTestErrorManager extends ErrorManager  {
22
    
23
24
    
25
    // here's XTest ErrorManager
26
    private static ErrorManager errorManager = null;
27
    
28
29
    // here are stored notifications
30
    private static StringBuffer errorLog = new StringBuffer();        
31
    
32
    // getter for notifications
33
    public static synchronized String getNotifications() {
34
        if (errorLog.length() > 0) {
35
            return errorLog.toString();
36
        } else {
37
            return null;
38
        }
39
    }
40
    
41
    // clear stuff for notifications
42
    public static synchronized void clearNotifications() {
43
        errorLog = new StringBuffer();
44
    }
45
    
46
47
    // get if there were any notifications and clear the status
48
    public static synchronized boolean anyNotifications() {
49
        if (getNotifications() == null) {
50
            return false;
51
        } else {
52
            clearNotifications();
53
            return true;
54
        }
55
    }
56
    
57
        
58
    
59
    /** Creates new NbExceptionManager. */
60
    public XTestErrorManager() {
61
        if (errorManager == null) {
62
            errorManager = this;
63
        }
64
    }
65
    
66
    
67
    
68
    public org.openide.ErrorManager getInstance(String name)  {
69
        return getInstance();
70
    }
71
    
72
    public static org.openide.ErrorManager getInstance() {
73
         if (errorManager == null) {
74
            errorManager = new XTestErrorManager();
75
        }
76
        return errorManager;
77
    }
78
    
79
    /** Adds these values. All the
80
     * previous annotations are kept and this new is added at
81
     * the top of the annotation stack (index 0 of the annotation
82
     * array).
83
     *
84
     * @param severity integer describing severity (one of const values
85
     *   from this class)
86
     * @param date date or null
87
     * @param message message to attach to the exception or null
88
     * @param localizedMessage localized message for the user or null
89
     * @param stackTrace exception representing the stack trace or null
90
     */
91
    public synchronized Throwable annotate(
92
    Throwable t,
93
    int severity, String message, String localizedMessage,
94
    Throwable stackTrace, java.util.Date date
95
    ) {
96
        return null;
97
    }
98
    
99
    
100
    /** Associates annotations with this thread.
101
     *
102
     * @param arr array of annotations (or null)
103
     */
104
    public synchronized Throwable attachAnnotations(Throwable t, Annotation[] arr) {      
105
        return null;
106
    }
107
    
108
    /** Notifies all the exceptions associated with
109
     * this thread.
110
     * @param clear should the current exception be cleared or not?
111
     */
112
    public synchronized void notify(int severity, Throwable t) {
113
        // synchronized to ensure that only one exception is
114
        // written to the thread
115
        
116
        
117
        if (severity > ErrorManager.USER ) {
118
            // let's print the stuff to theByteArray ....
119
            
120
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
121
            
122
            PrintWriter ps = new PrintWriter(bs);
123
            
124
            ps.println("*********** Exception occured ************"); // NOI18N
125
            
126
            // log into the byte array
127
            t.printStackTrace(ps);
128
            
129
            ps.flush();
130
            
131
            ps.close();
132
            
133
            // add the notification to the string buffer
134
            errorLog.append(bs.toString()+"\n");
135
        /*
136
        ErrorManager.getDefault().log(ErrorManager.ERROR,"#\n#\n############# XTestEM notification: "+t+"\n#\n#\n");
137
         */
138
        }
139
    }
140
    
141
    
142
    /** Finds annotations associated with given exception.
143
     * @param t the exception
144
     * @return array of annotations or null
145
     */
146
    public synchronized Annotation[] findAnnotations(Throwable t) {
147
        return null;
148
    }
149
    
150
    // log !!!
151
    public void log(int severity, String s) {
152
    }
153
       
154
    
155
    
156
    
157
}
(-)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>
(-)nbextra/xtest/src/org/netbeans/xtest/junit/.cvsignore (+1 lines)
Added Link Here
1
*.class
(-)nbextra/xtest/src/org/netbeans/xtest/pe/junit/.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.*;
(-)nbextra/xtest/src/org/netbeans/xtest/util/.cvsignore (+1 lines)
Added Link Here
1
*.class

Return to bug 26126