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 14722
Collapse All | Expand All

(-)core/src/org/netbeans/core/NbTopManager.java (-14 / +58 lines)
Lines 18-23 Link Here
18
import java.awt.event.*;
18
import java.awt.event.*;
19
import java.beans.*;
19
import java.beans.*;
20
import java.io.*;
20
import java.io.*;
21
import java.lang.reflect.Constructor;
21
import java.lang.reflect.Method;
22
import java.lang.reflect.Method;
22
import java.net.URL;
23
import java.net.URL;
23
import java.util.Enumeration;
24
import java.util.Enumeration;
Lines 40-45 Link Here
40
import org.openide.filesystems.*;
41
import org.openide.filesystems.*;
41
import org.openide.filesystems.FileSystem;
42
import org.openide.filesystems.FileSystem;
42
import org.openide.filesystems.JarFileSystem;
43
import org.openide.filesystems.JarFileSystem;
44
import org.openide.modules.Dependency;
45
import org.openide.modules.SpecificationVersion;
43
import org.openide.options.ControlPanel;
46
import org.openide.options.ControlPanel;
44
import org.openide.windows.WindowManager;
47
import org.openide.windows.WindowManager;
45
import org.openide.windows.OutputWriter;
48
import org.openide.windows.OutputWriter;
Lines 59-71 Link Here
59
import org.netbeans.core.windows.WindowManagerImpl;
62
import org.netbeans.core.windows.WindowManagerImpl;
60
import org.netbeans.core.compiler.CompilationEngineImpl;
63
import org.netbeans.core.compiler.CompilationEngineImpl;
61
import org.netbeans.core.perftool.StartLog;
64
import org.netbeans.core.perftool.StartLog;
65
import org.netbeans.core.modules.ModuleManager;
62
import org.netbeans.core.modules.ModuleSystem;
66
import org.netbeans.core.modules.ModuleSystem;
63
import org.openide.modules.Dependency;
64
import org.openide.modules.SpecificationVersion;
65
67
66
/** This class is a TopManager for Corona environment.
68
/** This class is a TopManager for Corona environment.
67
*
69
*
68
* @author Ales Novak, Jaroslav Tulach, Ian Formanek, Petr Hamernik, Jan Jancura
70
* @author Ales Novak, Jaroslav Tulach, Ian Formanek, Petr Hamernik, Jan Jancura, Jesse Glick
69
*/
71
*/
70
public abstract class NbTopManager extends TopManager {
72
public abstract class NbTopManager extends TopManager {
71
    /* masks to define the interactivity level */
73
    /* masks to define the interactivity level */
Lines 150-156 Link Here
150
        // Set up module-versioning properties, which logger prints.
152
        // Set up module-versioning properties, which logger prints.
151
        Package p = Package.getPackage ("org.openide"); // NOI18N
153
        Package p = Package.getPackage ("org.openide"); // NOI18N
152
        
154
        
153
        putSystemProperty ("org.openide.specification.version", p.getSpecificationVersion (), "1.1.6"); // NOI18N
155
        putSystemProperty ("org.openide.specification.version", p.getSpecificationVersion (), "2.3"); // NOI18N
154
        putSystemProperty ("org.openide.version", p.getImplementationVersion (), "OwnBuild"); // NOI18N
156
        putSystemProperty ("org.openide.version", p.getImplementationVersion (), "OwnBuild"); // NOI18N
155
        putSystemProperty ("org.openide.major.version", p.getSpecificationTitle (), "IDE/1"); // NOI18N
157
        putSystemProperty ("org.openide.major.version", p.getSpecificationTitle (), "IDE/1"); // NOI18N
156
        putSystemProperty ("netbeans.buildnumber", p.getImplementationVersion (), "OwnBuild"); // NOI18N
158
        putSystemProperty ("netbeans.buildnumber", p.getImplementationVersion (), "OwnBuild"); // NOI18N
Lines 938-955 Link Here
938
        public Lkp () {
940
        public Lkp () {
939
            super (new Lookup[] {
941
            super (new Lookup[] {
940
                new org.netbeans.core.lookup.TMLookup(),
942
                new org.netbeans.core.lookup.TMLookup(),
943
                // #14722: pay attention also to META-INF/services/class.Name resources:
944
                createMetaInfServicesLookup(false),
941
                createInitialErrorManagerLookup(),
945
                createInitialErrorManagerLookup(),
942
            });
946
            });
943
            //System.err.println("creating default lookup");
947
            //System.err.println("creating default lookup");
944
        }
948
        }
945
        
949
        
950
        /** @param modules if true, use module classloader, else not */
951
        private static Lookup createMetaInfServicesLookup(boolean modules) {
952
            try {
953
                Class clazz = Class.forName("org.openide.util.MetaInfServicesLookup"); // NOI18N
954
                Constructor c = clazz.getDeclaredConstructor(new Class[] {ClassLoader.class});
955
                c.setAccessible(true);
956
                ClassLoader loader;
957
                if (modules) {
958
                    loader = get().getModuleSystem().getManager().getClassLoader();
959
                } else {
960
                    loader = Lkp.class.getClassLoader();
961
                }
962
                return (Lookup)c.newInstance(new Object[] {loader});
963
            } catch (Exception e) {
964
                e.printStackTrace();
965
                return Lookup.EMPTY;
966
            }
967
        }
968
        
946
        private static Lookup createInitialErrorManagerLookup() {
969
        private static Lookup createInitialErrorManagerLookup() {
947
            InstanceContent c = new InstanceContent();
970
            InstanceContent c = new InstanceContent();
948
            c.add(Boolean.TRUE, new InitialErrorManagerConvertor());
971
            c.add(Boolean.TRUE, new ConvertorListener());
949
            return new AbstractLookup(c);
972
            return new AbstractLookup(c);
950
        }
973
        }
951
        
974
        
952
        private static final class InitialErrorManagerConvertor implements InstanceContent.Convertor, TaskListener {
975
        private static final class ConvertorListener
976
                implements InstanceContent.Convertor, TaskListener, PropertyChangeListener {
953
            public Object convert(Object obj) {
977
            public Object convert(Object obj) {
954
                //System.err.println("IEMC.convert");
978
                //System.err.println("IEMC.convert");
955
                return getDefaultErrorManager();
979
                return getDefaultErrorManager();
Lines 972-990 Link Here
972
                if (lookup instanceof Lkp) {
996
                if (lookup instanceof Lkp) {
973
                    Lkp lkp = (Lkp)lookup;
997
                    Lkp lkp = (Lkp)lookup;
974
                    Lookup[] old = lkp.getLookups();
998
                    Lookup[] old = lkp.getLookups();
975
                    if (old.length != 5) throw new IllegalStateException();
999
                    if (old.length != 6) throw new IllegalStateException();
976
                    Lookup[] nue = new Lookup[] {
1000
                    Lookup[] nue = new Lookup[] {
977
                        old[0], // TMLookup
1001
                        old[0], // TMLookup
1002
                        old[1], // metaInfServicesLookup
978
                        // do NOT include initialErrorManagerLookup; this is now replaced by the layer entry
1003
                        // do NOT include initialErrorManagerLookup; this is now replaced by the layer entry
979
                        // Services/Hidden/org-netbeans-core-default-error-manager.instance
1004
                        // Services/Hidden/org-netbeans-core-default-error-manager.instance
980
                        old[2], // NbTM.instanceLookup
1005
                        old[3], // NbTM.instanceLookup
981
                        old[3], // FolderLookup
1006
                        old[4], // FolderLookup
982
                        old[4], // moduleLookup
1007
                        old[5], // moduleLookup
983
                    };
1008
                    };
984
                    lkp.setLookups(nue);
1009
                    lkp.setLookups(nue);
985
                }
1010
                }
986
            }
1011
            }
987
            
1012
            public void propertyChange(PropertyChangeEvent evt) {
1013
                //System.err.println("modules changed; changing metaInfServicesLookup");
1014
                if (ModuleManager.PROP_ENABLED_MODULES.equals(evt.getPropertyName())) {
1015
                    // Time to refresh META-INF/services/ lookup; modules turned on or off.
1016
                    Lookup lookup = Lookup.getDefault();
1017
                    if (lookup instanceof Lkp) {
1018
                        Lkp lkp = (Lkp)lookup;
1019
                        Lookup[] old = lkp.getLookups();
1020
                        Lookup[] nue = (Lookup[])old.clone();
1021
                        nue[1] = createMetaInfServicesLookup(true);
1022
                        lkp.setLookups(nue);
1023
                        //System.err.println("lookups: " + java.util.Arrays.asList(arr));
1024
                    }
1025
                }
1026
            }
988
        }
1027
        }
989
1028
990
        /** When all module classes are accessible thru systemClassLoader, this
1029
        /** When all module classes are accessible thru systemClassLoader, this
Lines 1011-1025 Link Here
1011
                    StartLog.logProgress ("Got Services folder"); // NOI18N
1050
                    StartLog.logProgress ("Got Services folder"); // NOI18N
1012
1051
1013
                    FolderLookup folder = new FolderLookup (df, "SL["); // NOI18N
1052
                    FolderLookup folder = new FolderLookup (df, "SL["); // NOI18N
1014
                    folder.addTaskListener(new InitialErrorManagerConvertor());
1053
                    folder.addTaskListener(new ConvertorListener());
1015
                    StartLog.logProgress ("created FolderLookup"); // NOI18N
1054
                    StartLog.logProgress ("created FolderLookup"); // NOI18N
1016
                    
1055
                    
1017
                    // extend the lookup
1056
                    // extend the lookup
1018
                    Lookup[] arr = new Lookup[] {
1057
                    Lookup[] arr = new Lookup[] {
1019
                        lkp.getLookups ()[0],
1058
                        lkp.getLookups ()[0], // TMLookup
1059
                        // replace metaInfServicesLookup with a new one from modules
1060
                        createMetaInfServicesLookup(true),
1020
                        // Include initialErrorManagerLookup provisionally, until the folder lookup
1061
                        // Include initialErrorManagerLookup provisionally, until the folder lookup
1021
                        // is actually ready and usable
1062
                        // is actually ready and usable
1022
                        lkp.getLookups()[1],
1063
                        lkp.getLookups()[2], // initialErrorManagerLookup
1023
                        NbTopManager.get ().getInstanceLookup (),
1064
                        NbTopManager.get ().getInstanceLookup (),
1024
                        folder.getLookup (),
1065
                        folder.getLookup (),
1025
                        NbTopManager.get().getModuleSystem().getManager().getModuleLookup(),
1066
                        NbTopManager.get().getModuleSystem().getManager().getModuleLookup(),
Lines 1028-1033 Link Here
1028
1069
1029
                    lkp.setLookups (arr);
1070
                    lkp.setLookups (arr);
1030
                    StartLog.logProgress ("Lookups set"); // NOI18N
1071
                    StartLog.logProgress ("Lookups set"); // NOI18N
1072
                    
1073
                    // Also listen for changes in modules, as META-INF/services/ would change:
1074
                    get().getModuleSystem().getManager().addPropertyChangeListener(new ConvertorListener());
1031
                } catch (java.io.IOException ex) {
1075
                } catch (java.io.IOException ex) {
1032
                    ex.printStackTrace();
1076
                    ex.printStackTrace();
1033
                    throw new IllegalStateException ("Cannot initialize folder Services"); // NOI18N
1077
                    throw new IllegalStateException ("Cannot initialize folder Services"); // NOI18N
(-)openide/src/org/openide/util/Lookup.java (-2 / +2 lines)
Lines 47-53 Link Here
47
                           );
47
                           );
48
        
48
        
49
        if (className == null) {
49
        if (className == null) {
50
            defaultLookup = EMPTY;
50
            defaultLookup = new MetaInfServicesLookup();
51
            return defaultLookup;
51
            return defaultLookup;
52
        }
52
        }
53
53
Lines 55-61 Link Here
55
            Class c = Class.forName(className);
55
            Class c = Class.forName(className);
56
            defaultLookup = (Lookup)c.newInstance();
56
            defaultLookup = (Lookup)c.newInstance();
57
        } catch (Exception ex) {
57
        } catch (Exception ex) {
58
            defaultLookup = EMPTY;
58
            defaultLookup = new MetaInfServicesLookup();
59
            ex.printStackTrace();
59
            ex.printStackTrace();
60
            throw new InternalError ();
60
            throw new InternalError ();
61
        }
61
        }
(-)openide/src/org/openide/util/MetaInfServicesLookup.java (+244 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.util;
15
16
import java.net.URL;
17
import java.util.*;
18
import java.io.*;
19
20
import org.openide.ErrorManager;
21
import org.openide.util.lookup.*;
22
23
/** A lookup that implements the JDK1.3 JAR services mechanism and delegates
24
 * to META-INF/services/name.of.class files.
25
 * <p>It is not dynamic - so if you need to change the classloader or JARs,
26
 * wrap it in a ProxyLookup and change the delegate when necessary.
27
 * Existing instances will be kept if the implementation classes are unchanged,
28
 * so there is "stability" in doing this provided some parent loaders are the same
29
 * as the previous ones.
30
 * <p>If this is to be made public, please move it to the org.openide.util.lookup
31
 * package; currently used by the core via reflection, until it is needed some
32
 * other way.
33
 * @author Jaroslav Tulach, Jesse Glick
34
 * @see #14722
35
 */
36
final class MetaInfServicesLookup extends AbstractLookup {
37
    
38
    private static final Map knownInstances = new WeakHashMap(); // Map<Class,Object>
39
    
40
    /** A set of all requested classes.
41
     * Note that classes that we actually succeeded on can never be removed
42
     * from here because we hold a strong reference to the loader.
43
     * However we also hold classes which are definitely not loadable by
44
     * our loader.
45
     */
46
    private final Set classes = new WeakSet(); // Set<Class>
47
    /** class loader to use */
48
    private final ClassLoader loader;
49
    
50
    /** Create a lookup reading from the classpath.
51
     * That is, the same classloader as this class itself.
52
     */
53
    public MetaInfServicesLookup() {
54
        this(MetaInfServicesLookup.class.getClassLoader());
55
    }
56
    
57
    /** Create a lookup reading from a specified classloader.
58
     */
59
    public MetaInfServicesLookup(ClassLoader loader) {
60
        this.loader = loader;
61
    }
62
    
63
    
64
    /* Tries to load appropriate resources from manifest files.
65
     */
66
    protected synchronized final void beforeLookup(Lookup.Template t) {
67
        Class c = t.getType();
68
        if (classes.add(c)) {
69
            // Added new class, search for it.
70
            List arr = new ArrayList();
71
            search(c, arr);
72
            Iterator it = arr.iterator();
73
            while (it.hasNext()) {
74
                Pair p = (Pair)it.next();
75
                addPair(p);
76
            }
77
        }
78
    }
79
    
80
    /** Finds all pairs and adds them to the collection.
81
     *
82
     * @param clazz class to find
83
     * @param result collection to add Pair to
84
     */
85
    private void search(Class clazz, Collection result) {
86
        String res = "META-INF/services/" + clazz.getName(); // NOI18N
87
        Enumeration en;
88
        try {
89
            en = loader.getResources(res);
90
        } catch (IOException ioe) {
91
            ErrorManager.getDefault().notify(ioe);
92
            return;
93
        }
94
        
95
        // Do not create multiple instances in case more than one JAR
96
        // has the same entry in it (and they load to the same class).
97
        // Probably would not happen, assuming JARs only list classes
98
        // they own, but just in case...
99
        Set foundClasses = new HashSet(); // Set<Class>
100
101
        boolean foundOne = false;
102
        while (en.hasMoreElements()) {
103
104
            if (!foundOne) {
105
                foundOne = true;
106
                // Double-check that in fact we can load the *interface* class.
107
                // For example, say class I is defined in two JARs, J1 and J2.
108
                // There is also an implementation M1 defined in J1, and another
109
                // implementation M2 defined in J2.
110
                // Classloaders C1 and C2 are made from J1 and J2.
111
                // A MetaInfServicesLookup is made from C1. Then the user asks to
112
                // lookup I as loaded from C2. J1 has the services line and lists
113
                // M1, and we can in fact make it. However it is not of the desired
114
                // type to be looked up. Don't do this check, which could be expensive,
115
                // unless we expect to be getting some results, however.
116
                Class realMcCoy = null;
117
                try {
118
                    realMcCoy = loader.loadClass(clazz.getName());
119
                } catch (ClassNotFoundException cnfe) {
120
                    // our loader does not know about it, OK
121
                }
122
                if (realMcCoy != clazz) {
123
                    // Either the interface class is not available at all in our loader,
124
                    // or it is not the same version as we expected. Don't provide results.
125
                    return;
126
                }
127
            }
128
            
129
            URL url = (URL)en.nextElement();
130
            try {
131
                InputStream is = url.openStream();
132
                try {
133
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // NOI18N
134
                    while (true) {
135
                        String line = reader.readLine();
136
                        if (line == null) break;
137
138
                        // Ignore blank lines and comments.
139
                        line = line.trim();
140
                        if (line.length() == 0) continue;
141
                        if (line.charAt(0) == '#') continue; // NOI18N
142
143
                        // Most lines are fully-qualified class names.
144
                        Class inst = Class.forName(line, false, loader);
145
                        if (!clazz.isAssignableFrom(inst)) {
146
                            throw new ClassNotFoundException(inst.getName() + " not a subclass of " + clazz.getName()); // NOI18N
147
                        }
148
                        if (foundClasses.add(inst)) {
149
                            result.add(new P(inst));
150
                        }
151
                    }
152
                } finally {
153
                    is.close();
154
                }
155
            } catch (ClassNotFoundException ex) {
156
                ErrorManager.getDefault().notify(ex);
157
            } catch (IOException ex) {
158
                ErrorManager.getDefault().notify(ex);
159
            }
160
        }
161
    }
162
    
163
    
164
    /** Pair that holds name of a class and maybe the instance.
165
     */
166
    private static final class P extends Pair {
167
        /** May be one of three things:
168
         * 1. The implementation class which was named in the services file.
169
         * 2. An instance of it.
170
         * 3. Null, if creation of the instance resulted in an error.
171
         */
172
        private Object object;
173
        
174
        public P(Class clazz) {
175
            this.object = clazz;
176
        }
177
        
178
        /** Finds the class.
179
         */
180
        private Class clazz() {
181
            Object o = object;
182
            if (o instanceof Class) {
183
                return (Class)o;
184
            } else if (o != null) {
185
                return o.getClass();
186
            } else {
187
                // Broken.
188
                return Object.class;
189
            }
190
        }
191
        
192
        public boolean equals(Object o) {
193
            if (o instanceof P) {
194
                return ((P)o).clazz().equals(clazz());
195
            }
196
            return false;
197
        }
198
        
199
        public int hashCode() {
200
            return clazz().hashCode();
201
        }
202
        
203
        protected boolean instanceOf(Class c) {
204
            return c.isAssignableFrom(clazz());
205
        }
206
        
207
        public Class getType() {
208
            return clazz();
209
        }
210
        
211
        public Object getInstance() {
212
            synchronized (knownInstances) {
213
                if (object instanceof Class) {
214
                    try {
215
                        Class c = ((Class)object);
216
                        object = knownInstances.get(c);
217
                        if (object == null) {
218
                            object = c.newInstance();
219
                            knownInstances.put(c, object);
220
                        }
221
                    } catch (Exception ex) {
222
                        ErrorManager.getDefault().notify(ex);
223
                        object = null;
224
                    }
225
                }
226
                return object;
227
            }
228
        }
229
        
230
        public String getDisplayName() {
231
            return clazz().getName();
232
        }
233
        
234
        public String getId() {
235
            return clazz().getName();
236
        }
237
        
238
        protected boolean creatorOf(Object obj) {
239
            return obj == object;
240
        }
241
        
242
    }
243
    
244
}
(-)core/test/unit/src/org/netbeans/core/lookup/MetaInfServicesTest.java (+180 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.core.lookup;
15
16
import org.netbeans.junit.*;
17
import junit.textui.TestRunner;
18
import org.netbeans.core.NbTopManager;
19
import org.netbeans.core.modules.*;
20
import org.openide.TopManager;
21
import org.openide.util.*;
22
import java.io.File;
23
import java.util.*;
24
import javax.xml.parsers.DocumentBuilderFactory;
25
import javax.xml.parsers.SAXParserFactory;
26
27
/** Test whether modules can really register things in their META-INF/services/class.Name
28
 * files, and whether this behaves correctly when the modules are disabled/enabled.
29
 * Note that Plain loads its classpath modules as soon as you ask for it, so these
30
 * tests do not check what happens on the NetBeans startup classpath.
31
 * @author Jesse Glick
32
 */
33
public class MetaInfServicesTest extends NbTestCase {
34
    
35
    public MetaInfServicesTest(String name) {
36
        super(name);
37
    }
38
    
39
    public static void main(String[] args) throws Exception {
40
        File temp = File.createTempFile("MetaInfServicesTest", ".dummy");
41
        System.setProperty("nbjunit.workdir", new File(temp.getParentFile(), temp.getName().substring(0, temp.getName().length() - 6)).getAbsolutePath());
42
        TestRunner.run(new NbTestSuite(MetaInfServicesTest.class));
43
    }
44
    
45
    private ModuleManager mgr;
46
    private Module m1, m2;
47
    protected void setUp() throws Exception {
48
        //System.err.println("setUp");
49
        //Thread.dumpStack();
50
        clearWorkDir();
51
        // Load Plain.
52
        TopManager.getDefault();
53
        // Make a couple of modules.
54
        mgr = NbTopManager.get().getModuleSystem().getManager();
55
        try {
56
            mgr.mutex().writeAccess(new Mutex.ExceptionAction() {
57
                public Object run() throws Exception {
58
                    File jar1 = new File(MetaInfServicesTest.class.getResource("data/services-jar-1.jar").getPath());
59
                    File jar2 = new File(MetaInfServicesTest.class.getResource("data/services-jar-2.jar").getPath());
60
                    m1 = mgr.create(jar1, new ModuleHistory(), false, false, false);
61
                    m2 = mgr.create(jar2, new ModuleHistory(), false, false, false);
62
                    return null;
63
                }
64
            });
65
        } catch (MutexException me) {
66
            throw me.getException();
67
        }
68
        assertEquals(Collections.EMPTY_SET, m1.getProblems());
69
    }
70
    protected void tearDown() throws Exception {
71
        try {
72
            mgr.mutex().writeAccess(new Mutex.ExceptionAction() {
73
                public Object run() throws Exception {
74
                    if (m2.isEnabled()) mgr.disable(m2);
75
                    mgr.delete(m2);
76
                    if (m1.isEnabled()) mgr.disable(m1);
77
                    mgr.delete(m1);
78
                    return null;
79
                }
80
            });
81
        } catch (MutexException me) {
82
            throw me.getException();
83
        }
84
        m1 = null;
85
        m2 = null;
86
        mgr = null;
87
    }
88
    protected static final int TWIDDLE_ENABLE = 0;
89
    protected static final int TWIDDLE_DISABLE = 1;
90
    protected void twiddle(final Module m, final int action) throws Exception {
91
        try {
92
            mgr.mutex().writeAccess(new Mutex.ExceptionAction() {
93
                public Object run() throws Exception {
94
                    switch (action) {
95
                    case TWIDDLE_ENABLE:
96
                        mgr.enable(m);
97
                        break;
98
                    case TWIDDLE_DISABLE:
99
                        mgr.disable(m);
100
                        break;
101
                    default:
102
                        throw new IllegalArgumentException("bad action: " + action);
103
                    }
104
                    return null;
105
                }
106
            });
107
        } catch (MutexException me) {
108
            throw me.getException();
109
        }
110
    }
111
    
112
    /** Fails to work if you have >1 method per class, because setUp gets run more
113
     * than once (XTest bug I suppose).
114
     */
115
    public void testEverything() throws Exception {
116
        twiddle(m1, TWIDDLE_ENABLE);
117
        Class xface = TopManager.getDefault().systemClassLoader().loadClass("org.foo.Interface");
118
        Lookup.Result r = Lookup.getDefault().lookup(new Lookup.Template(xface));
119
        List instances = new ArrayList(r.allInstances());
120
        // Expect to get Impl1 from first JAR.
121
        assertEquals(1, instances.size());
122
        Object instance1 = instances.get(0);
123
        assertTrue(xface.isInstance(instance1));
124
        assertEquals("org.foo.impl.Implementation1", instance1.getClass().getName());
125
        // Expect to have (same) Impl1 + Impl2.
126
        LookupL l = new LookupL();
127
        r.addLookupListener(l);
128
        twiddle(m2, TWIDDLE_ENABLE);
129
        assert(l.gotSomething());
130
        instances = new ArrayList(r.allInstances());
131
        assertEquals(2, instances.size());
132
        assertEquals(instance1, instances.get(0));
133
        assertEquals("org.bar.Implementation2", instances.get(1).getClass().getName());
134
        // Expect to lose Impl2.
135
        l.count = 0;
136
        twiddle(m2, TWIDDLE_DISABLE);
137
        assert(l.gotSomething());
138
        instances = new ArrayList(r.allInstances());
139
        assertEquals(1, instances.size());
140
        assertEquals(instance1, instances.get(0));
141
        // Expect to lose Impl1 too.
142
        l.count = 0;
143
        twiddle(m1, TWIDDLE_DISABLE);
144
        assert(l.gotSomething());
145
        instances = new ArrayList(r.allInstances());
146
        assertEquals(0, instances.size());
147
        // Expect to not get anything: wrong xface version
148
        l.count = 0;
149
        twiddle(m1, TWIDDLE_ENABLE);
150
        // not really important: assert(!l.gotSomething());
151
        instances = new ArrayList(r.allInstances());
152
        assertEquals(0, instances.size());
153
        Class xface2 = TopManager.getDefault().systemClassLoader().loadClass("org.foo.Interface");
154
        assertTrue(xface != xface2);
155
        Lookup.Result r2 = Lookup.getDefault().lookup(new Lookup.Template(xface2));
156
        instances = new ArrayList(r2.allInstances());
157
        assertEquals(1, instances.size());
158
        // Let's also check up on XML providers, which ought to be in the classpath.
159
        DocumentBuilderFactory dbf = (DocumentBuilderFactory)Lookup.getDefault().lookup(DocumentBuilderFactory.class);
160
        assertNotNull(dbf);
161
        SAXParserFactory spf = (SAXParserFactory)Lookup.getDefault().lookup(SAXParserFactory.class);
162
        assertNotNull(spf);
163
        //System.err.println("dbf=" + dbf + " spf=" + spf);
164
        //System.err.println("all DBFs=" + Lookup.getDefault().lookup(new Lookup.Template(DocumentBuilderFactory.class)).allInstances());
165
    }
166
    
167
    protected static final class LookupL implements LookupListener {
168
        public int count = 0;
169
        public synchronized void resultChanged(LookupEvent ev) {
170
            count++;
171
            notifyAll();
172
        }
173
        public synchronized boolean gotSomething() throws InterruptedException {
174
            if (count > 0) return true;
175
            wait(9999);
176
            return count > 0;
177
        }
178
    }
179
    
180
}
(-)core/test/unit/src/org/netbeans/core/lookup/data/build.xml (-3 / +17 lines)
Lines 8-19 Link Here
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-2001 Sun
11
Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
12
Microsystems, Inc. All Rights Reserved.
12
Microsystems, Inc. All Rights Reserved.
13
-->
13
-->
14
<project basedir="." default="all">
14
<project basedir="." default="all">
15
15
16
    <target name="all" depends="test1,test2"/>
16
    <target name="all" depends="test1,test2,services1,services2"/>
17
17
18
    <target name="test1">
18
    <target name="test1">
19
        <javac srcdir="test1-src" destdir="test1-src"/>
19
        <javac srcdir="test1-src" destdir="test1-src"/>
Lines 28-38 Link Here
28
            <fileset dir="test2-src"/>
28
            <fileset dir="test2-src"/>
29
        </jar>
29
        </jar>
30
    </target>
30
    </target>
31
    
32
    <target name="services1">
33
        <javac srcdir="services-jar-1" destdir="services-jar-1"/>
34
        <jar jarfile="services-jar-1.jar" manifest="services-jar-1.mf">
35
            <fileset dir="services-jar-1"/>
36
        </jar>
37
    </target>
38
39
    <target name="services2" depends="services1">
40
        <javac srcdir="services-jar-2" destdir="services-jar-2" classpath="services-jar-1.jar"/>
41
        <jar jarfile="services-jar-2.jar" manifest="services-jar-2.mf">
42
            <fileset dir="services-jar-2"/>
43
        </jar>
44
    </target>
31
45
32
    <target name="clean">
46
    <target name="clean">
33
        <delete>
47
        <delete>
34
            <fileset dir=".">
48
            <fileset dir=".">
35
                <include name="*src/**/*.class"/>
49
                <include name="**/*.class"/>
36
                <include name="*.jar"/>
50
                <include name="*.jar"/>
37
            </fileset>
51
            </fileset>
38
        </delete>
52
        </delete>
(-)core/test/unit/src/org/netbeans/core/lookup/data/services-jar-1.mf (+5 lines)
Added Link Here
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.foo
3
OpenIDE-Module-Name: Interface & Impl #1
4
OpenIDE-Module-IDE-Dependencies: IDE/1 > 2.2
5
(-)core/test/unit/src/org/netbeans/core/lookup/data/services-jar-2.mf (+6 lines)
Added Link Here
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.bar
3
OpenIDE-Module-Name: Impl #2
4
OpenIDE-Module-Module-Dependencies: org.foo
5
OpenIDE-Module-IDE-Dependencies: IDE/1 > 2.2
6
(-)core/test/unit/src/org/netbeans/core/lookup/data/services-jar-1/META-INF/services/org.foo.Interface (+4 lines)
Added Link Here
1
# Some header info, maybe.
2
3
# Our first impl here:
4
org.foo.impl.Implementation1
(-)core/test/unit/src/org/netbeans/core/lookup/data/services-jar-1/org/foo/Interface.java (+2 lines)
Added Link Here
1
package org.foo;
2
public interface Interface {}
(-)core/test/unit/src/org/netbeans/core/lookup/data/services-jar-1/org/foo/impl/Implementation1.java (+3 lines)
Added Link Here
1
package org.foo.impl;
2
import org.foo.Interface;
3
public class Implementation1 implements Interface {}
(-)core/test/unit/src/org/netbeans/core/lookup/data/services-jar-2/META-INF/services/org.foo.Interface (+1 lines)
Added Link Here
1
org.bar.Implementation2
(-)core/test/unit/src/org/netbeans/core/lookup/data/services-jar-2/org/bar/Implementation2.java (+3 lines)
Added Link Here
1
package org.bar;
2
import org.foo.Interface;
3
public class Implementation2 implements Interface {}
(-)openide/test/build.xml (+3 lines)
Lines 55-60 Link Here
55
    <target name="buildtests" depends="prepare-compile-classpath">
55
    <target name="buildtests" depends="prepare-compile-classpath">
56
       <!-- This calls common build process. -->
56
       <!-- This calls common build process. -->
57
       <!-- You can write your own if you need something special -->
57
       <!-- You can write your own if you need something special -->
58
       <ant dir="unit/src/org/openide/util/data"/>
58
       
59
       
59
       <!-- This property contains classpath used for compilation -->
60
       <!-- This property contains classpath used for compilation -->
60
       <!-- WRITE CORRECT VALUE TO THIS PROPERTY -->
61
       <!-- WRITE CORRECT VALUE TO THIS PROPERTY -->
Lines 77-82 Link Here
77
       <ant dir="." antfile="${xtest.general.antfile}"
78
       <ant dir="." antfile="${xtest.general.antfile}"
78
             target="cleantests">
79
             target="cleantests">
79
       </ant>
80
       </ant>
81
       
82
       <ant dir="unit/src/org/openide/util/data" target="clean"/>
80
    </target> 
83
    </target> 
81
84
82
    <!-- This target runs tests. You should not change this --> 
85
    <!-- This target runs tests. You should not change this --> 
(-)openide/test/unit/src/org/openide/util/MetaInfServicesLookupTest.java (+92 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.util;
15
16
import org.netbeans.junit.*;
17
import junit.textui.TestRunner;
18
import java.net.*;
19
import java.util.*;
20
21
/** Test finding services from manifest.
22
 * @author Jesse Glick
23
 */
24
public class MetaInfServicesLookupTest extends NbTestCase {
25
    
26
    public MetaInfServicesLookupTest(String name) {
27
        super(name);
28
    }
29
    
30
    public static void main(String[] args) {
31
        TestRunner.run(new NbTestSuite(MetaInfServicesLookupTest.class));
32
    }
33
    
34
    ClassLoader c1, c2, c2a, c3, c4;
35
    
36
    protected void setUp() throws Exception {
37
        c1 = new URLClassLoader(new URL[] {
38
            MetaInfServicesLookupTest.class.getResource("data/services-jar-1.jar"),
39
        });
40
        c2 = new URLClassLoader(new URL[] {
41
            MetaInfServicesLookupTest.class.getResource("data/services-jar-2.jar"),
42
        }, c1);
43
        c2a = new URLClassLoader(new URL[] {
44
            MetaInfServicesLookupTest.class.getResource("data/services-jar-2.jar"),
45
        }, c1);
46
        c3 = new URLClassLoader(new URL[] {
47
            MetaInfServicesLookupTest.class.getResource("data/services-jar-2.jar"),
48
        });
49
        c4 = new URLClassLoader(new URL[] {
50
            MetaInfServicesLookupTest.class.getResource("data/services-jar-1.jar"),
51
            MetaInfServicesLookupTest.class.getResource("data/services-jar-2.jar"),
52
        });
53
    }
54
    
55
    public void testBasicUsage() throws Exception {
56
        Lookup l = new MetaInfServicesLookup(c2);
57
        Class xface = c1.loadClass("org.foo.Interface");
58
        List results = new ArrayList(l.lookup(new Lookup.Template(xface)).allInstances());
59
        assertEquals(2, results.size());
60
        // Note that they have to be in order:
61
        assertEquals("org.foo.impl.Implementation1", results.get(0).getClass().getName());
62
        assertEquals("org.bar.Implementation2", results.get(1).getClass().getName());
63
        // Make sure it does not gratuitously replace items:
64
        List results2 = new ArrayList(l.lookup(new Lookup.Template(xface)).allInstances());
65
        assertEquals(results, results2);
66
    }
67
    
68
    public void testLoaderSkew() throws Exception {
69
        Class xface1 = c1.loadClass("org.foo.Interface");
70
        Lookup l3 = new MetaInfServicesLookup(c3);
71
        // If we cannot load Interface, there should be no impls of course... quietly!
72
        assertEquals(Collections.EMPTY_LIST,
73
            new ArrayList(l3.lookup(new Lookup.Template(xface1)).allInstances()));
74
        Lookup l4 = new MetaInfServicesLookup(c4);
75
        // If we can load Interface but it is the wrong one, ignore it.
76
        assertEquals(Collections.EMPTY_LIST,
77
            new ArrayList(l4.lookup(new Lookup.Template(xface1)).allInstances()));
78
        // Make sure l4 is really OK - it can load from its own JARs.
79
        Class xface4 = c4.loadClass("org.foo.Interface");
80
        assertEquals(2, l4.lookup(new Lookup.Template(xface4)).allInstances().size());
81
    }
82
    
83
    public void testStability() throws Exception {
84
        Lookup l = new MetaInfServicesLookup(c2);
85
        Class xface = c1.loadClass("org.foo.Interface");
86
        Object first = l.lookup(new Lookup.Template(xface)).allInstances().iterator().next();
87
        l = new MetaInfServicesLookup(c2a);
88
        Object second = l.lookup(new Lookup.Template(xface)).allInstances().iterator().next();
89
        assertEquals(first, second);
90
    }
91
    
92
}
(-)openide/test/unit/src/org/openide/util/data/.cvsignore (+1 lines)
Added Link Here
1
*.jar
(-)openide/test/unit/src/org/openide/util/data/build.xml (+27 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-2002 Sun
12
Microsystems, Inc. All Rights Reserved.
13
-->
14
15
<project name="org.openide.util test data" basedir="." default="all">
16
    <target name="all">
17
        <javac srcdir="services-jar-1" destdir="services-jar-1"/>
18
        <jar jarfile="services-jar-1.jar" basedir="services-jar-1"/>
19
        <javac srcdir="services-jar-2" destdir="services-jar-2" classpath="services-jar-1.jar"/>
20
        <jar jarfile="services-jar-2.jar" basedir="services-jar-2"/>
21
    </target>
22
    <target name="clean">
23
        <delete>
24
            <fileset dir="." includes="**/*.class, *.jar"/>
25
        </delete>
26
    </target>
27
</project>
(-)openide/test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/org.foo.Interface (+4 lines)
Added Link Here
1
# Some header info, maybe.
2
3
# Our first impl here:
4
org.foo.impl.Implementation1
(-)openide/test/unit/src/org/openide/util/data/services-jar-1/org/foo/Interface.java (+2 lines)
Added Link Here
1
package org.foo;
2
public interface Interface {}
(-)openide/test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Implementation1.java (+3 lines)
Added Link Here
1
package org.foo.impl;
2
import org.foo.Interface;
3
public class Implementation1 implements Interface {}
(-)openide/test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/org.foo.Interface (+1 lines)
Added Link Here
1
org.bar.Implementation2
(-)openide/test/unit/src/org/openide/util/data/services-jar-2/org/bar/Implementation2.java (+3 lines)
Added Link Here
1
package org.bar;
2
import org.foo.Interface;
3
public class Implementation2 implements Interface {}

Return to bug 14722