001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.core.lookup;
043:
044: import java.io.File;
045: import java.util.ArrayList;
046: import java.util.Collections;
047: import java.util.List;
048: import javax.print.PrintServiceLookup;
049: import org.netbeans.Module;
050: import org.netbeans.ModuleManager;
051: import org.netbeans.core.startup.ModuleHistory;
052: import org.netbeans.junit.NbTestCase;
053: import org.openide.util.Lookup;
054: import org.openide.util.LookupEvent;
055: import org.openide.util.LookupListener;
056: import org.openide.util.Mutex;
057: import org.openide.util.MutexException;
058:
059: /** Test whether modules can really register things in their META-INF/services/class.Name
060: * files, and whether this behaves correctly when the modules are disabled/enabled.
061: * Note that Plain loads its classpath modules as soon as you ask for it, so these
062: * tests do not check what happens on the NetBeans startup classpath.
063: * @author Jesse Glick
064: */
065: public class MetaInfServicesTest extends NbTestCase {
066:
067: public MetaInfServicesTest(String name) {
068: super (name);
069: }
070:
071: private ModuleManager mgr;
072: private Module m1, m2;
073:
074: protected void setUp() throws Exception {
075: //System.err.println("setUp");
076: //Thread.dumpStack();
077: clearWorkDir();
078: // Load Plain.
079: // Make a couple of modules.
080: mgr = org.netbeans.core.startup.Main.getModuleSystem()
081: .getManager();
082: try {
083: mgr.mutex().writeAccess(new Mutex.ExceptionAction() {
084: public Object run() throws Exception {
085: File jar1 = InstanceDataObjectModuleTestHid
086: .toFile(MetaInfServicesTest.class
087: .getResource("data/services-jar-1.jar"));
088: File jar2 = InstanceDataObjectModuleTestHid
089: .toFile(MetaInfServicesTest.class
090: .getResource("data/services-jar-2.jar"));
091: m1 = mgr.create(jar1, new ModuleHistory(jar1
092: .getAbsolutePath()), false, false, false);
093: m2 = mgr.create(jar2, new ModuleHistory(jar2
094: .getAbsolutePath()), false, false, false);
095: return null;
096: }
097: });
098: } catch (MutexException me) {
099: throw me.getException();
100: }
101: assertEquals(Collections.EMPTY_SET, m1.getProblems());
102: }
103:
104: protected void tearDown() throws Exception {
105: try {
106: mgr.mutex().writeAccess(new Mutex.ExceptionAction() {
107: public Object run() throws Exception {
108: if (m2.isEnabled())
109: mgr.disable(m2);
110: mgr.delete(m2);
111: if (m1.isEnabled())
112: mgr.disable(m1);
113: mgr.delete(m1);
114: return null;
115: }
116: });
117: } catch (MutexException me) {
118: throw me.getException();
119: }
120: m1 = null;
121: m2 = null;
122: mgr = null;
123: }
124:
125: protected static final int TWIDDLE_ENABLE = 0;
126: protected static final int TWIDDLE_DISABLE = 1;
127:
128: protected void twiddle(final Module m, final int action)
129: throws Exception {
130: try {
131: mgr.mutex().writeAccess(new Mutex.ExceptionAction() {
132: public Object run() throws Exception {
133: switch (action) {
134: case TWIDDLE_ENABLE:
135: mgr.enable(m);
136: break;
137: case TWIDDLE_DISABLE:
138: mgr.disable(m);
139: break;
140: default:
141: throw new IllegalArgumentException(
142: "bad action: " + action);
143: }
144: return null;
145: }
146: });
147: } catch (MutexException me) {
148: throw me.getException();
149: }
150: }
151:
152: /** Fails to work if you have >1 method per class, because setUp gets run more
153: * than once (XTest bug I suppose).
154: */
155: public void testEverything() throws Exception {
156: twiddle(m1, TWIDDLE_ENABLE);
157: ClassLoader systemClassLoader = Lookup.getDefault().lookup(
158: ClassLoader.class);
159: Class xface = systemClassLoader.loadClass("org.foo.Interface");
160: Lookup.Result r = Lookup.getDefault().lookupResult(xface);
161: List instances = new ArrayList(r.allInstances());
162: // Expect to get Impl1 from first JAR.
163: assertEquals(1, instances.size());
164: Object instance1 = instances.get(0);
165: assertTrue(xface.isInstance(instance1));
166: assertEquals("org.foo.impl.Implementation1", instance1
167: .getClass().getName());
168: // Expect to have (same) Impl1 + Impl2.
169: LookupL l = new LookupL();
170: r.addLookupListener(l);
171: twiddle(m2, TWIDDLE_ENABLE);
172: assertTrue(
173: "Turning on a second module with a manifest service fires a lookup change",
174: l.gotSomething());
175: instances = new ArrayList(r.allInstances());
176: assertEquals(2, instances.size());
177: assertEquals(instance1, instances.get(0));
178: assertEquals("org.bar.Implementation2", instances.get(1)
179: .getClass().getName());
180: // Expect to lose Impl2.
181: l.count = 0;
182: twiddle(m2, TWIDDLE_DISABLE);
183: assertTrue(l.gotSomething());
184: instances = new ArrayList(r.allInstances());
185: assertEquals(1, instances.size());
186: assertEquals(instance1, instances.get(0));
187: // Expect to lose Impl1 too.
188: l.count = 0;
189: twiddle(m1, TWIDDLE_DISABLE);
190: assertTrue(l.gotSomething());
191: instances = new ArrayList(r.allInstances());
192: assertEquals(0, instances.size());
193: // Expect to not get anything: wrong xface version
194: l.count = 0;
195: twiddle(m1, TWIDDLE_ENABLE);
196: // not really important: assertFalse(l.gotSomething());
197: instances = new ArrayList(r.allInstances());
198: assertEquals(0, instances.size());
199: systemClassLoader = Lookup.getDefault().lookup(
200: ClassLoader.class);
201: Class xface2 = systemClassLoader.loadClass("org.foo.Interface");
202: assertTrue(xface != xface2);
203: Lookup.Result r2 = Lookup.getDefault().lookupResult(xface2);
204: instances = new ArrayList(r2.allInstances());
205: assertEquals(1, instances.size());
206: // Let's also check up on some standard JDK services.
207: PrintServiceLookup psl = Lookup.getDefault().lookup(
208: PrintServiceLookup.class);
209: assertNotNull(
210: "Some META-INF/services/javax.print.PrintServiceLookup was found in "
211: + Lookup.getDefault(), psl);
212: }
213:
214: protected static final class LookupL implements LookupListener {
215: public int count = 0;
216:
217: public synchronized void resultChanged(LookupEvent ev) {
218: count++;
219: notifyAll();
220: }
221:
222: public synchronized boolean gotSomething()
223: throws InterruptedException {
224: if (count > 0)
225: return true;
226: wait(9999);
227: return count > 0;
228: }
229: }
230:
231: }
|