blob: 42b60ef879d4bec82ce42ae7ff98325583907b6a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.logging.Level;
import org.netbeans.junit.RandomlyFails;
import org.openide.modules.Dependency;
import org.openide.modules.ModuleInfo;
import org.openide.modules.Modules;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.Utilities;
import org.openide.util.test.TestFileUtils;
/** Test the module manager as well as the Module class.
* This means creating modules from JAR as well as from "classpath"
* (i.e. rigged-up classloader), and testing that it creates them with
* the correct stuff; testing that the various pieces of the manifest
* are correctly parsed and made accessible; that dependencies work
* when things are done in various orders etc.; that problems (such as
* missing dependencies) are accurately reported; that the classloaders
* are capable of getting everything listed; that module installer
* methods are called at the correct times and with modules in the correct
* state; that changes are fired correctly; etc.
* Note that since the design of the module manager makes no direct
* reference to general IDE classes other than standalone APIs and a couple
* of standalone core utilities, this entire test can (and ought to be)
* executed in standalone mode.
* @author Jesse Glick
*/
public class ModuleManagerTest extends SetupHid {
static {
// To match org.netbeans.Main.execute (cf. #44828):
new URLConnection(ModuleManagerTest.class.getResource("ModuleManagerTest.class")) {
public @Override void connect() throws IOException {}
}.setDefaultUseCaches(false);
ProxyURLStreamHandlerFactory.register();
}
public ModuleManagerTest(String name) {
super(name);
}
@Override
protected Level logLevel() {
return Level.FINE;
}
/** Load simple-module and depends-on-simple-module.
* Make sure they can be installed and in a sane order.
* Make sure a class from one can depend on a class from another.
* Try to disable them too.
*/
public void testSimpleInstallation() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
assertEquals("org.foo", m1.getCodeNameBase());
assertEquals("org.bar", m2.getCodeNameBase());
assertCnb(m1);
assertCnb(m2);
assertEquals(Collections.EMPTY_SET, m1.getDependencies());
assertEquals(Dependency.create(Dependency.TYPE_MODULE, "org.foo/1"), m2.getDependencies());
Map<String,Module> modulesByName = new HashMap<String,Module>();
modulesByName.put(m1.getCodeNameBase(), m1);
modulesByName.put(m2.getCodeNameBase(), m2);
List<Module> m1m2 = Arrays.asList(m1, m2);
List<Module> m2m1 = Arrays.asList(m2, m1);
Map<Module,List<Module>> deps = Util.moduleDependencies(m1m2, modulesByName, Collections.<String,Set<Module>>emptyMap());
assertNull(deps.get(m1));
assertEquals(Collections.singletonList(m1), deps.get(m2));
assertEquals(m2m1, Utilities.topologicalSort(m1m2, deps));
assertEquals(m2m1, Utilities.topologicalSort(m2m1, deps));
// Leave commented out since it has a (hopefully clean) mutation effect
// and could affect results:
/*
assertEquals(Collections.EMPTY_SET, m1.getProblems());
assertEquals(Collections.EMPTY_SET, m2.getProblems());
*/
Set<Module> m1PlusM2 = new HashSet<Module>();
m1PlusM2.add(m1);
m1PlusM2.add(m2);
List<Module> toEnable = mgr.simulateEnable(m1PlusM2);
assertEquals("correct result of simulateEnable", Arrays.asList(m1, m2), toEnable);
mgr.enable(m1PlusM2);
assertEquals(Arrays.asList(
"prepare",
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m1,
m2,
Arrays.asList(m1, m2)
), installer.args);
Class<?> somethingelse = Class.forName("org.bar.SomethingElse", true, m2.getClassLoader());
Method somemethod = somethingelse.getMethod("message");
assertEquals("hello", somemethod.invoke(somethingelse.newInstance()));
installer.clear();
List<Module> toDisable = mgr.simulateDisable(Collections.singleton(m1));
assertEquals("correct result of simulateDisable", Arrays.asList(m2, m1), toDisable);
toDisable = mgr.simulateDisable(m1PlusM2);
assertEquals("correct result of simulateDisable #2", Arrays.asList(m2, m1), toDisable);
mgr.disable(m1PlusM2);
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
assertEquals(Collections.EMPTY_SET, mgr.getEnabledModules());
assertEquals(m1PlusM2, mgr.getModules());
assertEquals(Arrays.asList(
"unload",
"dispose",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Arrays.asList(m2, m1),
m2,
m1
), installer.args);
installer.clear();
mgr.enable(m1);
mgr.shutDown();
assertEquals(Arrays.asList(
"prepare",
"load",
"closing",
"close"
), installer.actions);
assertEquals(Arrays.asList(
m1,
Collections.singletonList(m1),
Collections.singletonList(m1),
Collections.singletonList(m1)
), installer.args);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testInstallAutoload() throws Exception {
// Cf. #9779, I think.
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
// m1 will be an autoload.
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, true, false);
try {
mgr.simulateEnable(new HashSet<Module>(Arrays.asList(m1, m2)));
assertTrue("Should not permit you to simulate enablement of an autoload", false);
} catch (IllegalArgumentException iae) {
// Good. m1 should not have been passed to it.
}
assertEquals(Collections.EMPTY_SET, m1.getProblems());
assertEquals(Collections.EMPTY_SET, m2.getProblems());
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertEquals("correct result of simulateEnable", Arrays.asList(m1, m2), toEnable);
mgr.enable(Collections.singleton(m2));
assertEquals(Arrays.asList(
"prepare",
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m1,
m2,
Arrays.asList(m1, m2)
), installer.args);
Class<?> somethingelse = Class.forName("org.bar.SomethingElse", true, m2.getClassLoader());
Method somemethod = somethingelse.getMethod("message");
assertEquals("hello", somemethod.invoke(somethingelse.newInstance()));
// Now try turning off m2 and make sure m1 goes away as well.
assertEquals("correct result of simulateDisable", Arrays.asList(m2, m1), mgr.simulateDisable(Collections.singleton(m2)));
installer.clear();
mgr.disable(Collections.singleton(m2));
assertEquals(Arrays.asList(
"unload",
"dispose",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Arrays.asList(m2, m1),
m2,
m1
), installer.args);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testInstallEager() throws Exception {
// Cf. #17501.
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
// m2 will be eager.
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, true);
try {
mgr.simulateEnable(new HashSet<Module>(Arrays.asList(m1, m2)));
fail("Should not permit you to simulate enablement of an eager module");
} catch (IllegalArgumentException iae) {
// Good. m2 should not have been passed to it.
}
assertEquals(Collections.EMPTY_SET, m1.getProblems());
assertEquals(Collections.EMPTY_SET, m2.getProblems());
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m1));
assertEquals("correct result of simulateEnable", Arrays.asList(m1, m2), toEnable);
mgr.enable(Collections.singleton(m1));
assertEquals(Arrays.asList(
"prepare",
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m1,
m2,
Arrays.asList(m1, m2)
), installer.args);
Class<?> somethingelse = Class.forName("org.bar.SomethingElse", true, m2.getClassLoader());
Method somemethod = somethingelse.getMethod("message");
assertEquals("hello", somemethod.invoke(somethingelse.newInstance()));
// Now try turning off m1 and make sure m2 goes away quietly.
assertEquals("correct result of simulateDisable", Arrays.asList(m2, m1), mgr.simulateDisable(Collections.singleton(m1)));
installer.clear();
mgr.disable(Collections.singleton(m1));
assertEquals(Arrays.asList(
"unload",
"dispose",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Arrays.asList(m2, m1),
m2,
m1
), installer.args);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testEagerPlusAutoload() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
// m1 autoload, m2 normal, m3 eager
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, true, false);
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "dep-on-dep-on-simple.jar"), null, false, false, true);
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertEquals("correct result of simulateEnable", Arrays.asList(m1, m2, m3), toEnable);
mgr.enable(Collections.singleton(m2));
assertEquals(Arrays.asList(
"prepare",
"prepare",
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m1,
m2,
m3,
Arrays.asList(m1, m2, m3)
), installer.args);
Class<?> somethingelseagain = Class.forName("org.baz.SomethingElseAgain", true, m3.getClassLoader());
Method somemethod = somethingelseagain.getMethod("doit");
assertEquals("hello", somemethod.invoke(somethingelseagain.newInstance()));
assertEquals("correct result of simulateDisable", Arrays.asList(m3, m2, m1), mgr.simulateDisable(Collections.singleton(m2)));
installer.clear();
mgr.disable(Collections.singleton(m2));
assertEquals(Arrays.asList(
"unload",
"dispose",
"dispose",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Arrays.asList(m3, m2, m1),
m3,
m2,
m1
), installer.args);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
/** Test scenario from #22536: when a normal module and an eager module
* both depend on the autoload, the eager & autoload modules should
* always be on, regardless of the normal module.
*/
public void testEagerPlusAutoload2() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
// m1 autoload, m2 normal, m3 eager
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, true, false);
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "depends-on-simple-module-2.jar"), null, false, false, true);
mgr.enable(Collections.<Module>emptySet());
assertTrue(m1.isEnabled());
assertFalse(m2.isEnabled());
assertTrue(m3.isEnabled());
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertEquals("correct result of simulateEnable", Collections.singletonList(m2), toEnable);
mgr.enable(Collections.singleton(m2));
assertTrue(m1.isEnabled());
assertTrue(m2.isEnabled());
assertTrue(m3.isEnabled());
List<Module> toDisable = mgr.simulateDisable(Collections.singleton(m2));
assertEquals("correct result of simulateDisable", Collections.singletonList(m2), toDisable);
mgr.disable(Collections.singleton(m2));
assertTrue(m1.isEnabled());
assertFalse(m2.isEnabled());
assertTrue(m3.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testEagerEnabledImmediately() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, true);
mgr.enable(Collections.<Module>emptySet());
assertTrue(m1.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, true);
mgr.enable(Collections.<Module>emptySet());
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
mgr.enable(m1);
assertTrue(m1.isEnabled());
assertTrue(m2.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, true, false);
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, true);
mgr.enable(Collections.<Module>emptySet());
assertTrue(m1.isEnabled());
assertTrue(m2.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testEagerEnablementRobust() throws Exception { // #144005
File dir = getWorkDir();
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
File jar = new File(dir, "eager1.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: eager1\nOpenIDE-Module-Module-Dependencies: autoload\n\n");
Module eager1 = mgr.create(jar, null, false, false, true);
mgr.enable(Collections.<Module>emptySet());
assertEquals(Collections.emptySet(), mgr.getEnabledModules());
jar = new File(dir, "autoload.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: autoload\n\n");
Module autoload = mgr.create(jar, null, false, true, false);
mgr.enable(Collections.<Module>emptySet());
assertEquals(new HashSet<Module>(Arrays.asList(autoload, eager1)), mgr.getEnabledModules());
jar = new File(dir, "eager2.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: eager2\nOpenIDE-Module-Module-Dependencies: missing\n\n");
mgr.create(jar, null, false, false, true);
mgr.enable(Collections.<Module>emptySet());
assertEquals(new HashSet<Module>(Arrays.asList(autoload, eager1)), mgr.getEnabledModules());
jar = new File(dir, "eager3.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: eager3\nOpenIDE-Module-Module-Dependencies: autoload\n\n");
Module eager3 = mgr.create(jar, null, false, false, true);
mgr.enable(Collections.<Module>emptySet());
assertEquals(new HashSet<Module>(Arrays.asList(autoload, eager1, eager3)), mgr.getEnabledModules());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testCyclic() throws Exception {
// Cf. #12014.
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module cyc1 = mgr.create(new File(jars, "cyclic-1.jar"), null, false, false, false);
Module cyc2 = mgr.create(new File(jars, "cyclic-2.jar"), null, false, false, false);
Module cycd = mgr.create(new File(jars, "depends-on-cyclic-1.jar"), null, false, false, false);
Set<Module> circular = new HashSet<Module>(Arrays.asList(cyc1, cyc2, cycd));
assertEquals("correct result of simulateEnable", Collections.EMPTY_LIST, mgr.simulateEnable(circular));
assertEquals("cyc1 problems include cyc2", cyc1.getDependencies(), cyc1.getProblems());
assertEquals("cyc2 problems include cyc1", cyc2.getDependencies(), cyc2.getProblems());
assertEquals("cycd problems include cyc1", cycd.getDependencies(), cycd.getProblems());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testBuildVersionCanBeReadOrIsDelegated() throws Exception {
// Cf. #12014.
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module cyc1 = mgr.create(new File(jars, "cyclic-1.jar"), null, false, false, false);
Module cyc2 = mgr.create(new File(jars, "cyclic-2.jar"), null, false, false, false);
String impl1 = cyc1.getImplementationVersion ();
String impl2 = cyc2.getImplementationVersion ();
String bld1 = cyc1.getBuildVersion ();
String bld2 = cyc2.getBuildVersion ();
assertEquals (
"cyc1 does not define build version and thus it is same as impl",
impl1, bld1
);
assertEquals (
"cyc2 does define build version",
"this_line_is_here_due_to_yarda",
bld2
);
assertTrue ("Impl and build versions are not same",
!bld2.equals (impl2)
);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testLookup() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
Module m1, m2;
try {
m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
Lookup l = mgr.getModuleLookup();
assertNull(l.lookup(String.class));
Object random = l.lookup(ModuleInfo.class);
assertTrue(random == m1 || random == m2);
random = l.lookup(Module.class);
assertTrue(random == m1 || random == m2);
Lookup.Result<ModuleInfo> resultAll = l.lookupResult(ModuleInfo.class);
assertEquals("finding all instances works", new HashSet<Module>(Arrays.asList(m1, m2)), new HashSet<ModuleInfo>(resultAll.allInstances()));
Lookup.Result<Module> resultInstance2 = l.lookup(new Lookup.Template<Module>(null, null, m2));
assertEquals("finding one specific instance works", Collections.singleton(m2), new HashSet<Module>(resultInstance2.allInstances()));
Collection<? extends Lookup.Item<Module>> items = resultInstance2.allItems();
assertTrue(items.size() == 1);
Lookup.Item<Module> item = items.iterator().next();
assertEquals(m2, item.getInstance());
Util.err.log(Level.INFO, "Item ID: {0}", item.getId());
assertTrue("Item class is OK: " + item.getType(), item.getType().isAssignableFrom(Module.class));
assertEquals("finding by ID works", Collections.singleton(m2),
new HashSet<Module>(l.lookup(new Lookup.Template<Module>(null, item.getId(), null)).allInstances()));
final boolean[] waiter = new boolean[] {false};
resultAll.addLookupListener(new LookupListener() {
public @Override void resultChanged(LookupEvent lev) {
Util.err.log(Level.INFO, "Got event: {0}", lev);
synchronized (waiter) {
waiter[0] = true;
waiter.notify();
}
}
});
Module m3;
mgr.mutexPrivileged().enterWriteAccess();
try {
m3 = mgr.create(new File(jars, "cyclic-1.jar"), null, false, false, false);
mgr.delete(m2);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
assertEquals("results changed", new HashSet<ModuleInfo>(Arrays.asList(m1, m3)), new HashSet<ModuleInfo>(resultAll.allInstances()));
synchronized (waiter) {
if (! waiter[0]) {
waiter.wait(5000);
}
}
assertTrue("got lookup changes within 5 seconds", waiter[0]);
}
/** Test that after deletion of a module, problems cache is cleared. */
public void test14561() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
Set<Module> m1AndM2 = new HashSet<Module>(Arrays.asList(m1, m2));
mgr.enable(m1AndM2);
mgr.disable(m1AndM2);
assertEquals(Collections.EMPTY_SET, m2.getProblems());
mgr.delete(m1);
assertEquals(1, m2.getProblems().size());
assertEquals(Collections.EMPTY_LIST, mgr.simulateEnable(Collections.singleton(m2)));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
/** Test that PROP_PROBLEMS is fired reliably after unexpected problems. */
public void test14560() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
LoggedPCListener listener = new LoggedPCListener();
mgr.addPropertyChangeListener(listener);
mgr.mutexPrivileged().enterWriteAccess();
Module m1, m2;
try {
m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
m1.addPropertyChangeListener(listener);
m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
m2.addPropertyChangeListener(listener);
installer.delinquents.add(m1);
Set<Module> m1AndM2 = new HashSet<Module>(Arrays.asList(m1, m2));
try {
mgr.enable(m1AndM2);
} catch (InvalidException ie) {
assertEquals(m1, ie.getModule());
}
assertFalse(m1.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
assertTrue("Got PROP_PROBLEMS on m1", listener.waitForChange(m1, Module.PROP_PROBLEMS));
}
// #14705: make sure package loading is tested
public void testPackageLoading() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
// Make sure all of these can be turned on:
tryEnablingModule(mgr, "depends-on-lib-undecl.jar");
tryEnablingModule(mgr, "depends-on-lib-unvers.jar");
tryEnablingModule(mgr, "depends-on-lib-vers.jar");
tryEnablingModule(mgr, "depends-on-lib-vers-partial.jar");
// In fact it is OK to depend on pkg.somepkg[Something] even with
// library-undecl.jar, since the classloader will define a package for you.
//failToEnableModule(mgr, "fails-on-lib-undecl.jar");
// These should not work:
failToEnableModule(mgr, "fails-on-lib-unvers.jar");
failToEnableModule(mgr, "fails-on-lib-old.jar");
// Make sure that classloading is OK:
Module m = mgr.create(new File(jars, "depends-on-lib-undecl.jar"), null, false, false, false);
mgr.enable(m);
Class<?> c = m.getClassLoader().loadClass("org.dol.User");
Object o = c.newInstance();
Field f = c.getField("val");
assertEquals(42, f.getInt(o));
mgr.disable(m);
mgr.delete(m);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
private void tryEnablingModule(ModuleManager mgr, String name) throws Exception {
Module m = mgr.create(new File(jars, name), null, false, false, false);
try {
mgr.enable(m);
mgr.disable(m);
} finally {
mgr.delete(m);
}
}
private void failToEnableModule(ModuleManager mgr, String name) throws Exception {
try {
tryEnablingModule(mgr, name);
fail("Was able to turn on " + name + " without complaint");
} catch (InvalidException ie) {
// Fine, expected.
}
}
public void testPackageDependencyMayfail() throws Exception {
//see #63904:
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Manifest mani;
JarFile jf = new JarFile(new File(jars, "simple-module.jar"));
try {
mani = jf.getManifest();
} finally {
jf.close();
}
Module toFail = mgr.create(new File(jars, "fails-on-non-existing-package.jar"), null, false, false, false);
Module fixed = mgr.createFixed(mani, null, this.getClass().getClassLoader());
try {
mgr.enable(new HashSet<Module>(Arrays.asList(toFail, fixed)));
fail("Was able to turn on fails-on-non-existing-package.jar without complaint");
} catch (InvalidException e) {
assertTrue("fails-on-non-existing-package.jar was not enabled", e.getModule() == toFail);
}
assertTrue("simple-module.jar was enabled", fixed.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
// #12549: check that loading of localized manifest attributes works.
public void testLocalizedManifestAttributes() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
Locale starting = Locale.getDefault();
try {
Locale.setDefault(new Locale("en", "US"));
File locmanijar = new File(jars, "localized-manifest.jar");
assertTrue("test JAR exists: " + locmanijar, locmanijar.isFile()); // #50891
Module m = mgr.create(locmanijar, null, false, false, false);
// These are defined in the bundle:
assertEquals("en_US display name", "Localized Manifest Module", m.getDisplayName());
assertEquals("en_US bundle main attr", "value #1", m.getLocalizedAttribute("some-other-key"));
assertEquals("en_US bundle sub attr", "value #2", m.getLocalizedAttribute("locmani/something.txt/other-key"));
assertEquals("en_US bundle main attr untrans", "value #7", m.getLocalizedAttribute("other-untrans"));
assertEquals("en_US bundle sub attr untrans", "value #8", m.getLocalizedAttribute("locmani/something.txt/other-untrans"));
// These in the manifest itself:
assertEquals("en_US manifest main attr", "value #3", m.getLocalizedAttribute("some-key"));
assertEquals("en_US manifest sub attr", "value #4", m.getLocalizedAttribute("locmani/something.txt/key"));
assertEquals("en_US manifest main attr untrans", "value #5", m.getLocalizedAttribute("untrans"));
assertEquals("en_US manifest sub attr untrans", "value #6", m.getLocalizedAttribute("locmani/something.txt/untrans"));
mgr.delete(m);
// Now try it again, with a different locale this time:
Locale.setDefault(new Locale("cs", "CZ"));
m = mgr.create(new File(jars, "localized-manifest.jar"), null, false, false, false);
// Note Unicode values in the bundle.
assertEquals("cs_CZ display name", "Modul s lokalizovan\u00FDm manifestem", m.getDisplayName());
assertEquals("cs_CZ bundle main attr", "v\u00FDznam #1", m.getLocalizedAttribute("some-other-key"));
assertEquals("cs_CZ bundle sub attr", "v\u00FDznam #2", m.getLocalizedAttribute("locmani/something.txt/other-key"));
// These are not translated, see that they fall back to "default" locale:
assertEquals("cs_CZ bundle main attr untrans", "value #7", m.getLocalizedAttribute("other-untrans"));
assertEquals("cs_CZ bundle sub attr untrans", "value #8", m.getLocalizedAttribute("locmani/something.txt/other-untrans"));
// The manifest cannot hold non-ASCII characters.
assertEquals("cs_CZ manifest main attr", "vyznam #3", m.getLocalizedAttribute("some-key"));
assertEquals("cs_CZ manifest sub attr", "vyznam #4", m.getLocalizedAttribute("locmani/something.txt/key"));
// Also not translated:
assertEquals("cs_CZ manifest main attr untrans", "value #5", m.getLocalizedAttribute("untrans"));
assertEquals("cs_CZ manifest sub attr untrans", "value #6", m.getLocalizedAttribute("locmani/something.txt/untrans"));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
Locale.setDefault(starting);
}
}
// #19698: check that it also works when the module is enabled (above, module was disabled).
public void testLocalizedManifestAttributesWhileEnabled() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
Locale starting = Locale.getDefault();
try {
Locale.setDefault(new Locale("en", "US"));
Module m = mgr.create(new File(jars, "localized-manifest.jar"), null, false, false, false);
mgr.enable(m);
// These are defined in the bundle:
assertEquals("en_US display name", "Localized Manifest Module", m.getDisplayName());
assertEquals("en_US bundle main attr", "value #1", m.getLocalizedAttribute("some-other-key"));
assertEquals("en_US bundle sub attr", "value #2", m.getLocalizedAttribute("locmani/something.txt/other-key"));
assertEquals("en_US bundle main attr untrans", "value #7", m.getLocalizedAttribute("other-untrans"));
assertEquals("en_US bundle sub attr untrans", "value #8", m.getLocalizedAttribute("locmani/something.txt/other-untrans"));
// These in the manifest itself:
assertEquals("en_US manifest main attr", "value #3", m.getLocalizedAttribute("some-key"));
assertEquals("en_US manifest sub attr", "value #4", m.getLocalizedAttribute("locmani/something.txt/key"));
assertEquals("en_US manifest main attr untrans", "value #5", m.getLocalizedAttribute("untrans"));
assertEquals("en_US manifest sub attr untrans", "value #6", m.getLocalizedAttribute("locmani/something.txt/untrans"));
mgr.disable(m);
mgr.delete(m);
// Now try it again, with a different locale this time:
Locale.setDefault(new Locale("cs", "CZ"));
m = mgr.create(new File(jars, "localized-manifest.jar"), null, false, false, false);
mgr.enable(m);
// Note Unicode values in the bundle.
assertEquals("cs_CZ display name", "Modul s lokalizovan\u00FDm manifestem", m.getDisplayName());
assertEquals("cs_CZ bundle main attr", "v\u00FDznam #1", m.getLocalizedAttribute("some-other-key"));
assertEquals("cs_CZ bundle sub attr", "v\u00FDznam #2", m.getLocalizedAttribute("locmani/something.txt/other-key"));
// These are not translated, see that they fall back to "default" locale:
assertEquals("cs_CZ bundle main attr untrans", "value #7", m.getLocalizedAttribute("other-untrans"));
assertEquals("cs_CZ bundle sub attr untrans", "value #8", m.getLocalizedAttribute("locmani/something.txt/other-untrans"));
// The manifest cannot hold non-ASCII characters.
assertEquals("cs_CZ manifest main attr", "vyznam #3", m.getLocalizedAttribute("some-key"));
assertEquals("cs_CZ manifest sub attr", "vyznam #4", m.getLocalizedAttribute("locmani/something.txt/key"));
// Also not translated:
assertEquals("cs_CZ manifest main attr untrans", "value #5", m.getLocalizedAttribute("untrans"));
assertEquals("cs_CZ manifest sub attr untrans", "value #6", m.getLocalizedAttribute("locmani/something.txt/untrans"));
mgr.disable(m);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
Locale.setDefault(starting);
}
}
// There was also a bug that loc mani attrs were not recognized for classpath modules.
public void testLocalizedManifestAttributesClasspath() throws Exception {
File jar = new File(jars, "localized-manifest.jar");
File ljar = new File(new File(jars, "locale"), "localized-manifest_cs.jar");
Manifest mani;
JarFile jf = new JarFile(jar);
try {
mani = jf.getManifest();
} finally {
jf.close();
}
ClassLoader l = new URLClassLoader(new URL[] {
// Order should be irrelevant:
Utilities.toURI(jar).toURL(),
Utilities.toURI(ljar).toURL(),
});
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
Locale starting = Locale.getDefault();
try {
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Locale.setDefault(new Locale("en", "US"));
Module m = mgr.createFixed(mani, null, l);
// These are defined in the bundle:
assertEquals("en_US display name", "Localized Manifest Module", m.getDisplayName());
assertEquals("en_US bundle main attr", "value #1", m.getLocalizedAttribute("some-other-key"));
assertEquals("en_US bundle sub attr", "value #2", m.getLocalizedAttribute("locmani/something.txt/other-key"));
assertEquals("en_US bundle main attr untrans", "value #7", m.getLocalizedAttribute("other-untrans"));
assertEquals("en_US bundle sub attr untrans", "value #8", m.getLocalizedAttribute("locmani/something.txt/other-untrans"));
// These in the manifest itself:
assertEquals("en_US manifest main attr", "value #3", m.getLocalizedAttribute("some-key"));
assertEquals("en_US manifest sub attr", "value #4", m.getLocalizedAttribute("locmani/something.txt/key"));
assertEquals("en_US manifest main attr untrans", "value #5", m.getLocalizedAttribute("untrans"));
assertEquals("en_US manifest sub attr untrans", "value #6", m.getLocalizedAttribute("locmani/something.txt/untrans"));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
// Need to start with a new manager: cannot delete classpath modules, would be a dupe
// if we tried to make it again.
mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
// Now try it again, with a different locale this time:
Locale.setDefault(new Locale("cs", "CZ"));
Module m = mgr.createFixed(mani, null, l);
// Note Unicode values in the bundle.
assertEquals("cs_CZ display name", "Modul s lokalizovan\u00FDm manifestem", m.getDisplayName());
assertEquals("cs_CZ bundle main attr", "v\u00FDznam #1", m.getLocalizedAttribute("some-other-key"));
assertEquals("cs_CZ bundle sub attr", "v\u00FDznam #2", m.getLocalizedAttribute("locmani/something.txt/other-key"));
// These are not translated, see that they fall back to "default" locale:
assertEquals("cs_CZ bundle main attr untrans", "value #7", m.getLocalizedAttribute("other-untrans"));
assertEquals("cs_CZ bundle sub attr untrans", "value #8", m.getLocalizedAttribute("locmani/something.txt/other-untrans"));
// The manifest cannot hold non-ASCII characters.
assertEquals("cs_CZ manifest main attr", "vyznam #3", m.getLocalizedAttribute("some-key"));
assertEquals("cs_CZ manifest sub attr", "vyznam #4", m.getLocalizedAttribute("locmani/something.txt/key"));
// Also not translated:
assertEquals("cs_CZ manifest main attr untrans", "value #5", m.getLocalizedAttribute("untrans"));
assertEquals("cs_CZ manifest sub attr untrans", "value #6", m.getLocalizedAttribute("locmani/something.txt/untrans"));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
} finally {
Locale.setDefault(starting);
}
}
// #9273: test that modules/patches/<<code-name-dashes>>/*.jar function as patches
public void testModulePatches() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m = mgr.create(new File(jars, "patchable.jar"), null, false, false, false);
mgr.enable(m);
Class<?> c = m.getClassLoader().loadClass("pkg.subpkg.A");
Field f = c.getField("val");
Object o = c.newInstance();
assertEquals(25, f.getInt(o));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testSimpleProvReq() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "req-foo.jar"), null, false, false, false);
assertEquals(Collections.singletonList("foo"), assertCnb(m1));
assertEquals(Collections.EMPTY_LIST, assertCnb(m2));
assertEquals(Collections.EMPTY_SET, m1.getDependencies());
assertEquals(Dependency.create(Dependency.TYPE_REQUIRES, "foo"), m2.getDependencies());
Map<String,Module> modulesByName = new HashMap<String,Module>();
modulesByName.put(m1.getCodeNameBase(), m1);
modulesByName.put(m2.getCodeNameBase(), m2);
Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>();
providersOf.put("foo", Collections.singleton(m1));
List<Module> m1m2 = Arrays.asList(m1, m2);
List<Module> m2m1 = Arrays.asList(m2, m1);
Map<Module,List<Module>> deps = Util.moduleDependencies(m1m2, modulesByName, providersOf);
assertNull(deps.get(m1));
assertEquals(Collections.singletonList(m1), deps.get(m2));
assertEquals(m2m1, Utilities.topologicalSort(m1m2, deps));
assertEquals(m2m1, Utilities.topologicalSort(m2m1, deps));
Set<Module> m1PlusM2 = new HashSet<Module>();
m1PlusM2.add(m1);
m1PlusM2.add(m2);
List<Module> toEnable = mgr.simulateEnable(m1PlusM2);
assertEquals("correct result of simulateEnable", Arrays.asList(m1, m2), toEnable);
toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertEquals("correct result of simulateEnable #2", Arrays.asList(m1, m2), toEnable);
mgr.enable(m1PlusM2);
assertEquals(Arrays.asList(
"prepare",
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m1,
m2,
Arrays.asList(m1, m2)
), installer.args);
Class<?> testclazz = Class.forName("org.prov_foo.Clazz", true, m1.getClassLoader());
try {
Class.forName("org.prov_foo.Clazz", true, m2.getClassLoader());
fail("Should not be able to access classes due to prov-req deps only");
} catch (ClassNotFoundException cnfe) {
// OK, good.
}
installer.clear();
List<Module> toDisable = mgr.simulateDisable(Collections.singleton(m1));
assertEquals("correct result of simulateDisable", Arrays.asList(m2, m1), toDisable);
toDisable = mgr.simulateDisable(m1PlusM2);
assertEquals("correct result of simulateDisable #2", Arrays.asList(m2, m1), toDisable);
mgr.disable(m1PlusM2);
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
assertEquals(Arrays.asList(
"unload",
"dispose",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Arrays.asList(m2, m1),
m2,
m1
), installer.args);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testProvReqAllowsDisable() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "recommends-foo.jar"), null, false, false, false);
Set<Module> m1PlusM2 = new HashSet<Module>();
m1PlusM2.add(m1);
m1PlusM2.add(m2);
mgr.enable(m1PlusM2);
assertTrue("m1 enabled", m1.isEnabled());
assertTrue("m2 enabled", m2.isEnabled());
mgr.disable(m1);
assertFalse("m1 disabled", m1.isEnabled());
assertTrue("m2 remains enabled", m2.isEnabled());
mgr.disable(m2);
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testProvReqCycles() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo-req-bar.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "prov-bar-req-foo.jar"), null, false, false, false);
assertEquals("m1 cannot be installed because of m2",
Dependency.create(Dependency.TYPE_REQUIRES, "bar"),
m1.getProblems());
assertEquals("m2 cannot be installed because of m1",
Dependency.create(Dependency.TYPE_REQUIRES, "foo"),
m2.getProblems());
assertEquals("neither m1 nor m2 can be installed",
Collections.EMPTY_LIST,
mgr.simulateEnable(new HashSet<Module>(Arrays.asList(m1, m2))));
mgr.delete(m2);
Module m3 = mgr.create(new File(jars, "prov-bar-dep-cyclic.jar"), null, false, false, false);
assertEquals("m1 cannot be installed because of m3",
Dependency.create(Dependency.TYPE_REQUIRES, "bar"),
m1.getProblems());
assertEquals("m3 cannot be installed because of m1",
Dependency.create(Dependency.TYPE_MODULE, "prov_foo_req_bar"),
m3.getProblems());
assertEquals("neither m1 nor m3 can be installed",
Collections.EMPTY_LIST,
mgr.simulateEnable(new HashSet<Module>(Arrays.asList(m1, m3))));
m2 = mgr.create(new File(jars, "prov-bar-req-foo.jar"), null, false, false, false);
assertEquals("m2 cannot be installed because of m1",
Dependency.create(Dependency.TYPE_REQUIRES, "foo"),
m2.getProblems());
Module m4 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
assertEquals("m2 is OK with m4 here",
Collections.EMPTY_SET,
m2.getProblems());
mgr.delete(m1); // to prevent random failures; see comment in MM.sE
assertEquals("m2 and m4 can be enabled together",
Arrays.asList(m4, m2),
mgr.simulateEnable(Collections.singleton(m2)));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testMultipleProvs() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "prov-foo-bar.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "req-foo.jar"), null, false, false, false);
Set<Module> m123 = new HashSet<Module>(Arrays.asList(m1, m2, m3));
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m3));
// Note order of first two items in toEnable is indeterminate.
assertEquals("From start, turn on all providers", m123, new HashSet<Module>(toEnable));
assertEquals("m3 last", m3, toEnable.get(2));
assertEquals("Could request them all together too", m123, new HashSet<Module>(mgr.simulateEnable(m123)));
List<Module> m13 = Arrays.asList(m1, m3);
assertEquals("Or just m1 + m3", m13, mgr.simulateEnable(new HashSet<Module>(m13)));
List<Module> m23 = Arrays.asList(m2, m3);
assertEquals("Or just m2 + m3", m23, mgr.simulateEnable(new HashSet<Module>(m23)));
mgr.enable(m123);
assertTrue(m1.isEnabled());
assertTrue(m2.isEnabled());
assertTrue(m3.isEnabled());
assertEquals("Can turn off one provider",
Collections.singletonList(m1),
mgr.simulateDisable(Collections.singleton(m1)));
Set<Module> m12 = new HashSet<Module>(Arrays.asList(m1, m2));
assertEquals("Can't turn off both providers",
m123,
new HashSet<Module>(mgr.simulateDisable(m12)));
mgr.disable(m1);
assertFalse(m1.isEnabled());
assertTrue(m2.isEnabled());
assertTrue(m3.isEnabled());
List<Module> m32 = Arrays.asList(m3, m2);
assertEquals("Can't turn off last provider",
m32,
mgr.simulateDisable(Collections.singleton(m2)));
mgr.disable(new HashSet<Module>(m32));
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
assertFalse(m3.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testProvReqUnsatisfiable() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
Module m1 = createModule(mgr, "OpenIDE-Module: m1\nOpenIDE-Module-Needs: tok\n");
Module m2 = createModule(mgr, "OpenIDE-Module: m2\nOpenIDE-Module-Module-Dependencies: m1\n");
assertEquals(Collections.emptyList(), mgr.simulateEnable(Collections.singleton(m2)));
Module m3 = createModule(mgr, "OpenIDE-Module: m3\nOpenIDE-Module-Provides: tok\n");
assertEquals(new HashSet<Module>(Arrays.asList(m1, m2, m3)), new HashSet<Module>(mgr.simulateEnable(Collections.singleton(m2))));
mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
m1 = createModule(mgr, "OpenIDE-Module: m1\nOpenIDE-Module-Requires: tok\n");
m2 = createModule(mgr, "OpenIDE-Module: m2\nOpenIDE-Module-Module-Dependencies: m1\nOpenIDE-Module-Provides: tok\n");
assertEquals(Collections.emptyList(), mgr.simulateEnable(Collections.singleton(m2)));
}
public void testSimpleProvNeeds() throws Exception {
doSimpleProvNeeds(false, false);
}
public void testSimpleProvNeedsReversed() throws Exception {
doSimpleProvNeeds(true, false);
}
public void testSimpleSatisfiedProvRecommends() throws Exception {
doSimpleProvNeeds(false, true);
}
public void testSimpleSatisfiedProvRecommendsReversed() throws Exception {
doSimpleProvNeeds(true, true);
}
private void doSimpleProvNeeds(boolean reverseOrder, boolean recommends) throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo-depends-needs_foo.jar"), null, false, false, false);
Module m2;
if (recommends) {
m2 = mgr.create(new File(jars, "recommends-foo.jar"), null, false, false, false);
} else {
m2 = mgr.create(new File(jars, "needs-foo.jar"), null, false, false, false);
}
assertEquals(Collections.singletonList("foo"), assertCnb(m1));
assertEquals(Collections.EMPTY_LIST, assertCnb(m2));
assertEquals(1, m1.getDependencies().size());
int type = recommends ? Dependency.TYPE_RECOMMENDS : Dependency.TYPE_NEEDS;
assertEquals(Dependency.create(type, "foo"), m2.getDependencies());
Map<String,Module> modulesByName = new HashMap<String,Module>();
modulesByName.put(m1.getCodeNameBase(), m1);
modulesByName.put(m2.getCodeNameBase(), m2);
Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>();
providersOf.put("foo", Collections.singleton(m1));
List<Module> m1m2 = Arrays.asList(m1, m2);
List<Module> m2m1 = Arrays.asList(m2, m1);
Map<Module,List<Module>> deps = Util.moduleDependencies(m1m2, modulesByName, providersOf);
assertEquals(Collections.singletonList(m2), deps.get(m1));
/* assertEquals(Collections.singletonList(m1), deps.get(m2));
try {
Utilities.topologicalSort(m1m2, deps);
} catch (TopologicalSortException ex) {
Set[] arr = ex.unsortableSets();
assertEquals("One unsortable set", 1, arr.length);
assertEquals("It contains two elements", 2, arr[0].size());
assertTrue("m1 is there", arr[0].contains(m1));
assertTrue("m2 is there", arr[0].contains(m2));
}*/
Set<Module> m1PlusM2 = new LinkedHashSet<Module>();
if (reverseOrder) {
m1PlusM2.add(m2);
m1PlusM2.add(m1);
} else {
m1PlusM2.add(m1);
m1PlusM2.add(m2);
}
List<Module> toEnable = mgr.simulateEnable(m1PlusM2);
assertEquals("correct result of simulateEnable", Arrays.asList(m2, m1), toEnable);
toEnable = mgr.simulateEnable(Collections.singleton(m1));
assertEquals("correct result of simulateEnable #2", Arrays.asList(m2, m1), toEnable);
toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertEquals("correct result of simulateEnable #3", Arrays.asList(m2, m1), toEnable);
mgr.enable(m1PlusM2);
assertEquals(Arrays.asList(
"prepare",
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m2,
m1,
Arrays.asList(m2, m1)
), installer.args);
Class<?> testclazz = Class.forName("org.prov_foo.Clazz", true, m1.getClassLoader());
try {
Class.forName("org.prov_foo.Clazz", true, m2.getClassLoader());
fail("Should not be able to access classes due to prov-req deps only");
} catch (ClassNotFoundException cnfe) {
// OK, good.
}
installer.clear();
List<Module> toDisable = mgr.simulateDisable(Collections.singleton(m1));
if (!recommends) {
assertEquals("correct result of simulateDisable", Arrays.asList(m1, m2), toDisable);
toDisable = mgr.simulateDisable(m1PlusM2);
assertEquals("correct result of simulateDisable #2", Arrays.asList(m1, m2), toDisable);
mgr.disable(m1PlusM2);
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
assertEquals(Arrays.asList(
"unload",
"dispose",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Arrays.asList(m1, m2),
m1,
m2
), installer.args);
} else {
assertEquals("correct result of simulateDisable", Collections.singletonList(m1 ), toDisable);
toDisable = mgr.simulateDisable(m1PlusM2);
assertEquals("correct result of simulateDisable #2", Arrays.asList(m1, m2), toDisable);
mgr.disable(m1);
assertFalse(m1.isEnabled());
assertTrue(m2.isEnabled());
mgr.disable(m2);
assertFalse(m2.isEnabled());
assertEquals(Arrays.asList(
"unload",
"dispose",
"unload",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Collections.singletonList(m1),
m1,
Collections.singletonList(m2),
m2
), installer.args);
}
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testProvNeedsWithEager() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
// m1 is regular (disabled) module, providing foo
Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
// m2 is autoload module, which needs foo
Module m2 = mgr.create(new File(jars, "needs-foo.jar"), null, false, true, false);
// m3 is eager module, which depends on m2
Module m3 = mgr.create(new File(jars, "dep-on-needs_foo-simple.jar"), null, false, false, true);
mgr.enable(Collections.emptySet());
// since m1 is disabled, eager module m3 should be still disabled
assertFalse("Incorrectly enabled m1",m1.isEnabled());
assertFalse("Incorrectly enabled m2",m2.isEnabled());
assertFalse("Incorrectly enabled m3",m3.isEnabled());
} catch (IllegalArgumentException ex) {
fail(ex.getMessage());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testComplexProvNeeds() throws Exception {
doComplexProvNeeds(false, false, false);
}
public void testComplexProvNeedsReversed() throws Exception {
doComplexProvNeeds(true, false, false);
}
public void testComplexSatisfiedProvRecommends() throws Exception {
doComplexProvNeeds(false, true, false);
}
public void testComplexSatisfiedProvRecommendsReversed() throws Exception {
doComplexProvNeeds(true, true, true);
}
public void testComplexProvNeeds2() throws Exception {
doComplexProvNeeds(false, false, true);
}
public void testComplexProvNeedsReversed2() throws Exception {
doComplexProvNeeds(true, false, true);
}
public void testComplexSatisfiedProvRecommends2() throws Exception {
doComplexProvNeeds(false, true, true);
}
public void testComplexSatisfiedProvRecommendsReversed2() throws Exception {
doComplexProvNeeds(true, true, true);
}
private void doComplexProvNeeds(boolean reverseOrder, boolean recommends, boolean sndRec) throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo-depends-needs_foo.jar"), null, false, true, false);
Module m2;
if (recommends) {
m2 = mgr.create(new File(jars, "recommends-foo.jar"), null, false, false, false);
} else {
m2 = mgr.create(new File(jars, "needs-foo.jar"), null, false, false, false);
}
Module m3 = null;
if (sndRec) {
String manifest = "Manifest-Version: 1.0\n" +
"OpenIDE-Module: snd.needs_foo\n" +
"OpenIDE-Module-Name: 2nd Needs foo\n" +
"OpenIDE-Module-Needs: foo\n";
m3 = mgr.create(copyJar(m2.getJarFile(), manifest), null, false, false, false);
} else {
String manifest = "Manifest-Version: 1.0\n" +
"OpenIDE-Module: snd.needs_foo\n" +
"OpenIDE-Module-Name: 2nd Needs foo\n" +
"OpenIDE-Module-Recommends: foo\n";
m3 = mgr.create(copyJar(m2.getJarFile(), manifest), null, false, false, false);
}
assertEquals(Collections.singletonList("foo"), assertCnb(m1));
assertEquals(Collections.EMPTY_LIST, assertCnb(m2));
assertEquals(1, m1.getDependencies().size());
int type = recommends ? Dependency.TYPE_RECOMMENDS : Dependency.TYPE_NEEDS;
assertEquals(Dependency.create(type, "foo"), m2.getDependencies());
Map<String,Module> modulesByName = new HashMap<String,Module>();
modulesByName.put(m1.getCodeNameBase(), m1);
modulesByName.put(m2.getCodeNameBase(), m2);
Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>();
providersOf.put("foo", Collections.singleton(m1));
List<Module> m1m2 = Arrays.asList(m1, m2);
List<Module> m2m1 = Arrays.asList(m2, m1);
Map<Module,List<Module>> deps = Util.moduleDependencies(m1m2, modulesByName, providersOf);
assertEquals(Collections.singletonList(m2), deps.get(m1));
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertEquals("correct result of simulateEnable", Arrays.asList(m2, m1), toEnable);
mgr.enable(m2);
assertEquals(Arrays.asList(
"prepare",
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m2,
m1,
Arrays.asList(m2, m1)
), installer.args);
Class<?> testclazz = Class.forName("org.prov_foo.Clazz", true, m1.getClassLoader());
try {
Class.forName("org.prov_foo.Clazz", true, m2.getClassLoader());
fail("Should not be able to access classes due to prov-req deps only");
} catch (ClassNotFoundException cnfe) {
// OK, good.
}
mgr.enable(m3);
assertTrue("m3 enabled1", m3.isEnabled());
installer.clear();
List<Module> toDisable = mgr.simulateDisable(Collections.singleton(m3));
if (!recommends) {
mgr.disable(m3);
assertFalse("M3 enabled", m3.isEnabled());
assertTrue("Provider enabled", m1.isEnabled());
assertTrue(m2.isEnabled());
assertEquals(Arrays.asList(
"unload",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Collections.singletonList( m3 ),
m3
), installer.args);
} else {
mgr.disable(m3);
assertFalse(m3.isEnabled());
assertTrue(m2.isEnabled());
assertTrue(m1.isEnabled());
assertEquals(Arrays.asList(
"unload",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Collections.singletonList(m3),
m3
), installer.args);
}
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testRecommendsWithoutAProvider() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m2 = mgr.create(new File(jars, "recommends-foo.jar"), null, false, false, false);
assertEquals(Collections.EMPTY_LIST, assertCnb(m2));
assertEquals(Dependency.create(Dependency.TYPE_RECOMMENDS, "foo"), m2.getDependencies());
Map<String,Module> modulesByName = new HashMap<String,Module>();
modulesByName.put(m2.getCodeNameBase(), m2);
Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>();
List<Module> m2List = Collections.singletonList( m2 );
Map<Module,List<Module>> deps = Util.moduleDependencies(m2List, modulesByName, providersOf);
assertEquals(null, deps.get(m2));
List<Module> toEnable = mgr.simulateEnable(new HashSet<Module>(m2List));
assertEquals("correct result of simulateEnable", Collections.singletonList(m2), toEnable);
mgr.enable(new HashSet<Module>(m2List));
assertEquals(Arrays.asList(
"prepare",
"load"
), installer.actions);
assertEquals(Arrays.asList(
m2,
// m1,
Collections.singletonList(m2)
), installer.args);
installer.clear();
List<Module> toDisable = mgr.simulateDisable(Collections.singleton(m2));
assertEquals("correct result of simulateDisable", Collections.singletonList(m2), toDisable);
mgr.disable(m2);
assertFalse(m2.isEnabled());
assertEquals(Arrays.asList(
"unload",
"dispose"
), installer.actions);
assertEquals(Arrays.asList(
Collections.singletonList(m2),
// m1,
m2
), installer.args);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testNeedsWithAProviderWithoutAProvider() throws Exception {
doRecommendsWithAProviderWithoutAProvider(false);
}
public void testRecommendsWithAProviderWithoutAProvider() throws Exception {
doRecommendsWithAProviderWithoutAProvider(true);
}
private void doRecommendsWithAProviderWithoutAProvider(boolean recommends) throws Exception {
// ========= XXX recommends parameter is unused! ===========
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m2 = mgr.create(new File(jars, "recommends-foo.jar"), null, false, false, false);
assertEquals(Collections.EMPTY_LIST, assertCnb(m2));
Module m1;
{
String manifest = "Manifest-Version: 1.0\n" +
"OpenIDE-Module: snd.provides.foo\n" +
"OpenIDE-Module-Name: Provides foo\n" +
"OpenIDE-Module-Provides: foo\n" +
"OpenIDE-Module-Needs: bla\n";
m1 = mgr.create(copyJar(m2.getJarFile(), manifest), null, false, true, false);
}
assertEquals(Dependency.create(Dependency.TYPE_RECOMMENDS, "foo"), m2.getDependencies());
Map<String,Module> modulesByName = new HashMap<String,Module>();
modulesByName.put(m2.getCodeNameBase(), m2);
Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>();
List<Module> m2List = Collections.singletonList(m2);
Map<Module,List<Module>> deps = Util.moduleDependencies(m2List, modulesByName, providersOf);
assertEquals(null, deps.get(m2));
List<Module> toEnable = mgr.simulateEnable(new HashSet<Module>(m2List));
assertEquals("cannot enable while provider of bla is missing", Collections.singletonList(m2), toEnable);
// try {
// mgr.enable(new HashSet<Module>(m2List));
// fail("Shall not allow enablement as 'bar' is missing");
// } catch (IllegalArgumentException ex) {
// // this cannot be enabled
// }
Module m3;
{
String manifest = "Manifest-Version: 1.0\n" +
"OpenIDE-Module: snd.provides.bar\n" +
"OpenIDE-Module-Name: Provides bar\n" +
"OpenIDE-Module-Provides: bla\n";
m3 = mgr.create(copyJar(m2.getJarFile(), manifest), null, false, true, false);
}
Set<Module> allThreeModules = new HashSet<>(Arrays.asList(m1, m3, m2));
toEnable = mgr.simulateEnable(new HashSet<Module>(m2List));
assertEquals("all 3 need to be enabled", allThreeModules, new HashSet<Module>(toEnable));
mgr.enable(new HashSet<Module>(m2List));
assertEquals(Arrays.asList(
"prepare",
"prepare",
"prepare",
"load"
), installer.actions);
installer.clear();
List<Module> toDisable = mgr.simulateDisable(Collections.singleton(m2));
assertEquals("correct result of simulateDisable", allThreeModules, new HashSet<Module>(toDisable));
mgr.disable(m2);
assertFalse(m2.isEnabled());
assertEquals(Arrays.asList(
"unload",
"dispose",
"dispose",
"dispose"
), installer.actions);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testMultipleReqs() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "prov-baz.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "req-foo-baz.jar"), null, false, false, false);
Set<Module> m123 = new HashSet<Module>(Arrays.asList(m1, m2, m3));
assertEquals(m123, new HashSet<Module>(mgr.simulateEnable(Collections.singleton(m3))));
mgr.enable(m123);
assertEquals(Arrays.asList(m3, m1), mgr.simulateDisable(Collections.singleton(m1)));
assertEquals(Arrays.asList(m3, m2), mgr.simulateDisable(Collections.singleton(m2)));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testEagerReq() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "prov-baz.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "req-foo-baz.jar"), null, false, false, true);
assertEquals(Collections.singletonList(m1),
mgr.simulateEnable(Collections.singleton(m1)));
assertEquals(Collections.singletonList(m2),
mgr.simulateEnable(Collections.singleton(m2)));
Set<Module> m12 = new HashSet<Module>(Arrays.asList(m1, m2));
Set<Module> m123 = new HashSet<Module>(Arrays.asList(m1, m2, m3));
assertEquals(m123, new HashSet<Module>(mgr.simulateEnable(m12)));
mgr.enable(m12);
assertTrue(m3.isEnabled());
assertEquals(Arrays.asList(m3, m1),
mgr.simulateDisable(Collections.singleton(m1)));
assertEquals(Arrays.asList(m3, m2),
mgr.simulateDisable(Collections.singleton(m2)));
assertEquals(m123,
new HashSet<Module>(mgr.simulateDisable(m12)));
mgr.disable(m12);
assertFalse(m3.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testAutoloadProv() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, true, false);
Module m2 = mgr.create(new File(jars, "req-foo.jar"), null, false, false, false);
assertEquals(Arrays.asList(m1, m2),
mgr.simulateEnable(Collections.singleton(m2)));
mgr.enable(m2);
assertTrue(m1.isEnabled());
assertEquals(Arrays.asList(m2, m1),
mgr.simulateDisable(Collections.singleton(m2)));
mgr.disable(m2);
assertFalse(m1.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testWeirdRecursion() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
//Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "prov-bar-req-foo.jar"), null, false, true, false);
Module m3 = mgr.create(new File(jars, "prov-foo-bar.jar"), null, false, false, false);
Module m4 = mgr.create(new File(jars, "prov-foo-req-bar.jar"), null, false, false, true);
assertEquals("m2 should not be enabled - m4 might ask for it but m3 already has bar",
new HashSet<Module>(Arrays.asList(m3, m4)),
new HashSet<Module>(mgr.simulateEnable(Collections.singleton(m3))));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testLackOfOrderSensitivity() throws Exception {
String[] moduleNames = new String[] {
"simple-module.jar",
"depends-on-simple-module.jar",
"dep-on-dep-on-simple.jar",
"prov-foo.jar",
"prov-baz.jar",
"prov-foo-bar.jar",
"req-foo.jar",
"req-foo-baz.jar",
"prov-bar-req-foo.jar",
"prov-foo-req-bar.jar",
};
// Never make any of the following eager:
Set<String> noDepsNames = new HashSet<String>(Arrays.asList(
"simple-module.jar",
"prov-foo.jar",
"prov-baz.jar",
"prov-foo-bar.jar"
));
List<String> freeModules = new ArrayList<String>(Arrays.asList(moduleNames));
int count = 100; // # of things to do in order
Random r = new Random(count * 17 + 113);
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
int i = 0;
while (i < count) {
Util.err.log(Level.INFO, "testLackOfOrderSensitivity round #{0}", i);
switch (r.nextInt(11)) {
case 0:
case 1:
case 2:
Util.err.info("Add a regular module");
if (!freeModules.isEmpty()) {
String name = freeModules.remove(r.nextInt(freeModules.size()));
mgr.create(new File(jars, name), null, false, false, false);
i++;
}
break;
case 3:
Util.err.info("Add an autoload");
if (!freeModules.isEmpty()) {
String name = freeModules.remove(r.nextInt(freeModules.size()));
mgr.create(new File(jars, name), null, false, true, false);
i++;
}
break;
case 4:
Util.err.info("Add an eager module");
if (!freeModules.isEmpty()) {
String name = freeModules.remove(r.nextInt(freeModules.size()));
if (!noDepsNames.contains(name)) {
Module m = mgr.create(new File(jars, name), null, false, false, true);
i++;
}
}
break;
case 5:
case 6:
Util.err.info("Remove a disabled module");
List<Module> disabled = new ArrayList<Module>(moduleNames.length);
for (Module m : mgr.getModules()) {
if (!m.isEnabled()) {
disabled.add(m);
}
}
if (!disabled.isEmpty()) {
Module m = disabled.get(r.nextInt(disabled.size()));
mgr.delete(m);
freeModules.add(m.getJarFile().getName());
i++;
}
break;
case 7:
case 8:
Util.err.info("Enable some set of modules");
List<Module> candidates = new ArrayList<Module>(moduleNames.length);
for (Module m : mgr.getModules()) {
if (!m.isEnabled() && !m.isAutoload() && !m.isEager() && r.nextBoolean()) {
candidates.add(m);
}
}
if (!candidates.isEmpty()) {
Collections.shuffle(candidates, r);
Set<Module> candidatesSet = new LinkedHashSet<Module>(candidates);
assertEquals("OrderPreservingSet works", candidates, new ArrayList<Module>(candidatesSet));
//dumpState(mgr);
//System.err.println("will try to enable: " + candidates);
List<Module> toEnable1 = mgr.simulateEnable(candidatesSet);
//System.err.println("Enabling " + candidates + " ->\n " + toEnable1);
Collections.shuffle(candidates, r);
List<Module> toEnable2 = mgr.simulateEnable(new LinkedHashSet<Module>(candidates));
Set<Module> s1 = new HashSet<Module>(toEnable1);
Set<Module> s2 = new HashSet<Module>(toEnable2);
assertEquals("Order preserved", s1, s2);
Iterator<Module> it = s1.iterator();
while (it.hasNext()) {
Module m = it.next();
if (m.isAutoload() || m.isEager()) {
it.remove();
}
}
mgr.enable(s1);
i++;
}
break;
case 9:
case 10:
Util.err.info("Disable some set of modules");
candidates = new ArrayList<Module>(moduleNames.length);
for (Module m : mgr.getModules()) {
if (m.isEnabled() && !m.isAutoload() && !m.isEager() && r.nextBoolean()) {
candidates.add(m);
}
}
if (!candidates.isEmpty()) {
Collections.shuffle(candidates, r);
//dumpState(mgr);
List<Module> toDisable1 = mgr.simulateDisable(new LinkedHashSet<Module>(candidates));
//System.err.println("Disabling " + candidates + " ->\n " + toDisable1);
Collections.shuffle(candidates, r);
//System.err.println("candidates #2: " + candidates);
List<Module> toDisable2 = mgr.simulateDisable(new LinkedHashSet<Module>(candidates));
Set<Module> s1 = new HashSet<Module>(toDisable1);
Set<Module> s2 = new HashSet<Module>(toDisable2);
assertEquals("Order preserved", s1, s2);
Iterator<Module> it = s1.iterator();
while (it.hasNext()) {
Module m = it.next();
if (m.isAutoload() || m.isEager()) {
it.remove();
}
}
mgr.disable(s1);
i++;
}
break;
default:
throw new IllegalStateException();
}
}
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
/*
private static void dumpState(ModuleManager mgr) {
SortedSet modules = new TreeSet(Util.displayNameComparator());
modules.addAll(mgr.getModules());
System.err.print("State:");
Iterator it = modules.iterator();
while (it.hasNext()) {
Module m = (Module)it.next();
System.err.print(" " + m.getCodeNameBase());
if (m.isAutoload()) {
System.err.print(" (autoload, ");
} else if (m.isEager()) {
System.err.print(" (eager, ");
} else {
System.err.print(" (normal, ");
}
if (m.isEnabled()) {
System.err.print("on)");
} else {
System.err.print("off)");
}
}
System.err.println();
}
*/
public void testRelVersRanges() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module base = mgr.create(new File(jars, "rel-ver-2.jar"), null, false, false, false);
String[] depNames = new String[] {
"dep-on-relvertest-1.jar", // 0
"dep-on-relvertest-1-2.jar", // 1
"dep-on-relvertest-2.jar", // 2
"dep-on-relvertest-2-3.jar", // 3
"dep-on-relvertest-2-3-late.jar", // 4
"dep-on-relvertest-2-impl.jar", // 5
"dep-on-relvertest-2-impl-wrong.jar", // 6
"dep-on-relvertest-2-late.jar", // 7
"dep-on-relvertest-3-4.jar", // 8
"dep-on-relvertest-some.jar", // 9
};
Module[] deps = new Module[depNames.length];
for (int i = 0; i < deps.length; i++) {
deps[i] = mgr.create(new File(jars, depNames[i]), null, false, false, false);
}
Set<Module> all = new HashSet<Module>();
all.add(base);
all.addAll(Arrays.asList(deps));
Set<Module> ok = new HashSet<Module>();
ok.add(base);
// 0 - too early
ok.add(deps[1]);
ok.add(deps[2]);
ok.add(deps[3]);
// 4 - too late
ok.add(deps[5]);
// 6 - wrong impl version
// 7 - too late
// 8 - too late
// 9 - must give some rel vers, else ~ -1
assertEquals(ok, new HashSet<Module>(mgr.simulateEnable(all)));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testDisableAgainstRelVersRange() throws Exception {
// #41449: org.openidex.util/3 disabled improperly when disable module w/ dep on org.openide.util/2-3
// related to testDisableWithAutoloadMajorRange but this probably has the test backwards
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module base = mgr.create(new File(jars, "rel-ver-2.jar"), null, false, true, false);
Module dep1 = mgr.create(new File(jars, "dep-on-relvertest-2.jar"), null, false, false, false);
Module dep2 = mgr.create(new File(jars, "dep-on-relvertest-1-2-nospec.jar"), null, false, false, false);
Set<Module> all = new HashSet<Module>();
all.add(dep1);
all.add(dep2);
mgr.enable(all);
all.add(base);
assertEquals("turn on autoload w/ both deps OK", all, mgr.getEnabledModules());
Set<Module> dep2only = Collections.singleton(dep2);
assertEquals("intend to disable only dep2", dep2only, new HashSet<Module>(mgr.simulateDisable(dep2only)));
mgr.disable(dep2only);
all.remove(dep2);
assertEquals("removed just dep2, not autoload used by dep1", all, mgr.getEnabledModules());
mgr.disable(Collections.singleton(dep1));
assertEquals("now all gone", Collections.EMPTY_SET, mgr.getEnabledModules());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
/** Test #21114: after deleting a module, its JARs are released.
* Would probably always pass on Unix, but on Windows it matters.
*/
@RandomlyFails // NB-Core-Build #2081 in ModuleFactoryTest
public void testModuleDeletion() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
File jar = new File(getWorkDir(), "copy-of-simple-module.jar");
copy(new File(jars, "simple-module.jar"), jar);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m = mgr.create(jar, null, false, false, false);
mgr.enable(m);
Class<?> c = m.getClassLoader().loadClass("org.foo.Something");
URL u = m.getClassLoader().getResource("org/foo/Something.class");
URLConnection uc = u.openConnection();
assertNotNull("connetion", uc);
assertTrue("using JarURLConnection or JarClassLoader's one: " + uc, uc.getClass().getName().indexOf("JarClassLoader") >= 0);
uc.connect();
mgr.disable(m);
mgr.delete(m);
WeakReference<Class<?>> refC = new WeakReference<>(c);
WeakReference<URL> refU = new WeakReference<>(u);
WeakReference<URLConnection> refUC = new WeakReference<>(uc);
c = null;
u = null;
uc = null;
assertGC ("Module class can go away", refC);
assertGC ("Module url", refU);
assertGC ("Module connection ", refUC);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
assertTrue("could delete JAR file", jar.delete());
}
/** Test #20663: the context classloader is set on all threads
* according to the system classloader.
*/
public void testContextClassLoader() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
final ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
// Make sure created threads do not die.
final Object sleepForever = "sleepForever";
try {
final Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
ClassLoader l1 = mgr.getClassLoader();
assertEquals(l1, Thread.currentThread().getContextClassLoader());
mgr.enable(m1);
ClassLoader l2 = mgr.getClassLoader();
assertTrue(l1 == l2);
assertEquals(l2, Thread.currentThread().getContextClassLoader());
mgr.enable(m2);
ClassLoader l3 = mgr.getClassLoader();
assertTrue(l1 == l3);
assertEquals(l3, Thread.currentThread().getContextClassLoader());
mgr.disable(m2);
ClassLoader l4 = mgr.getClassLoader();
assertTrue(l1 != l4);
assertEquals(l4, Thread.currentThread().getContextClassLoader());
final Thread[] t23 = new Thread[2];
final ClassLoader[] lx = new ClassLoader[] {new URLClassLoader(new URL[0])};
// Make sure t1 runs to completion, though.
final Object finishT1 = "finishT1";
Thread t1 = new Thread("custom thread #1") {
public @Override void run() {
synchronized (finishT1) {
t23[0] = new Thread("custom thread #2") {
public @Override void run() {
synchronized (sleepForever) {
try {
sleepForever.wait();
} catch (InterruptedException ie) {
throw new Error(ie.toString());
}
}
}
};
t23[0].start();
Thread.currentThread().setContextClassLoader(lx[0]);
mgr.disable(m1);
t23[1] = new Thread("custom thread #3") {
public @Override void run() {
synchronized (sleepForever) {
try {
sleepForever.wait();
} catch (InterruptedException ie) {
throw new Error(ie.toString());
}
}
}
};
t23[1].start();
finishT1.notify();
}
synchronized (sleepForever) {
try {
sleepForever.wait();
} catch (InterruptedException ie) {
throw new Error(ie.toString());
}
}
}
};
t1.start();
synchronized (finishT1) {
if (t23[1] == null) {
finishT1.wait();
assertNotNull(t23[1]);
}
}
assertFalse(m1.isEnabled());
ClassLoader l5 = mgr.getClassLoader();
assertTrue(l1 != l5);
assertTrue(l4 != l5);
assertEquals(l5, Thread.currentThread().getContextClassLoader());
// It had a special classloader when we changed modules.
assertTrue(t1.isAlive());
assertEquals(lx[0], t1.getContextClassLoader());
// It was created before the special classloader.
assertTrue(t23[0].isAlive());
assertEquals(l5, t23[0].getContextClassLoader());
// It was created after and should have inherited the special classloader.
assertTrue(t23[1].isAlive());
assertEquals(lx[0], t23[1].getContextClassLoader());
mgr.enable(m1);
mgr.disable(m1);
ClassLoader l6 = mgr.getClassLoader();
assertTrue(l1 != l6);
assertTrue(l4 != l6);
assertTrue(l5 != l6);
assertEquals(l6, Thread.currentThread().getContextClassLoader());
assertEquals(lx[0], t1.getContextClassLoader());
assertEquals(l6, t23[0].getContextClassLoader());
assertEquals(lx[0], t23[1].getContextClassLoader());
} finally {
synchronized (sleepForever) {
sleepForever.notifyAll();
}
mgr.mutexPrivileged().exitWriteAccess();
}
}
/** Make sure classloaders do not overlap.
* @see "#24996"
*/
public void testDependOnTwoFixedModules() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
File j1 = new File(jars, "simple-module.jar");
File j2 = new File(jars, "depends-on-simple-module.jar");
File j3 = new File(jars, "dep-on-two-modules.jar");
URLClassLoader l = new URLClassLoader(new URL[] {Utilities.toURI(j1).toURL(), Utilities.toURI(j2).toURL()});
Manifest mani1, mani2;
JarFile j = new JarFile(j1);
try {
mani1 = j.getManifest();
} finally {
j.close();
}
j = new JarFile(j2);
try {
mani2 = j.getManifest();
} finally {
j.close();
}
Module m1 = mgr.createFixed(mani1, null, l);
Module m2 = mgr.createFixed(mani2, null, l);
Module m3 = mgr.create(j3, null, false, false, false);
mgr.enable(new HashSet<Module>(Arrays.asList(m1, m2, m3)));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
/** Test exporting selected packages to clients.
* @see "#19621"
*/
public void testPackageExports() throws Exception {
ModuleManager mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents());
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "api-mod-export-all.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "uses-api-simple-dep.jar"), null, false, false, false);
mgr.enable(m1);
mgr.enable(m2);
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
mgr.disable(m2);
mgr.disable(m1);
mgr.delete(m2);
mgr.delete(m1);
m1 = mgr.create(new File(jars, "api-mod-export-none.jar"), null, false, false, false);
m2 = mgr.create(new File(jars, "uses-api-simple-dep.jar"), null, false, false, false);
mgr.enable(m1);
mgr.enable(m2);
try {
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
fail();
} catch (NoClassDefFoundError e) {}
try {
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
fail();
} catch (NoClassDefFoundError e) {}
assertNotNull(mgr.getClassLoader().getResource("usesapi/UsesImplClass.class"));
assertNotNull(mgr.getClassLoader().getResource("org/netbeans/api/foo/PublicClass.class"));
assertNotNull(mgr.getClassLoader().getResource("org/netbeans/modules/foo/ImplClass.class"));
mgr.disable(m2);
mgr.disable(m1);
mgr.delete(m2);
mgr.delete(m1);
m1 = mgr.create(new File(jars, "api-mod-export-none.jar"), null, false, false, false);
m2 = mgr.create(new File(jars, "uses-api-spec-dep.jar"), null, false, false, false);
mgr.enable(m1);
mgr.enable(m2);
try {
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
fail();
} catch (NoClassDefFoundError e) {}
try {
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
fail();
} catch (NoClassDefFoundError e) {}
mgr.disable(m2);
mgr.disable(m1);
mgr.delete(m2);
mgr.delete(m1);
m1 = mgr.create(new File(jars, "api-mod-export-none.jar"), null, false, false, false);
m2 = mgr.create(new File(jars, "uses-api-impl-dep.jar"), null, false, false, false);
mgr.enable(m1);
mgr.enable(m2);
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
mgr.disable(m2);
mgr.disable(m1);
mgr.delete(m2);
mgr.delete(m1);
m1 = mgr.create(new File(jars, "api-mod-export-api.jar"), null, false, false, false);
m2 = mgr.create(new File(jars, "uses-api-simple-dep.jar"), null, false, false, false);
assertEquals("api-mod-export-api.jar can be enabled", Collections.EMPTY_SET, m1.getProblems());
mgr.enable(m1);
assertEquals("uses-api-simple-dep.jar can be enabled", Collections.EMPTY_SET, m2.getProblems());
mgr.enable(m2);
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
try {
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
fail();
} catch (NoClassDefFoundError e) {}
mgr.disable(m2);
mgr.disable(m1);
mgr.delete(m2);
mgr.delete(m1);
m1 = mgr.create(new File(jars, "api-mod-export-api.jar"), null, false, false, false);
m2 = mgr.create(new File(jars, "uses-api-spec-dep.jar"), null, false, false, false);
mgr.enable(m1);
mgr.enable(m2);
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
try {
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
fail();
} catch (NoClassDefFoundError e) {}
mgr.disable(m2);
mgr.disable(m1);
mgr.delete(m2);
mgr.delete(m1);
m1 = mgr.create(new File(jars, "api-mod-export-api.jar"), null, false, false, false);
m2 = mgr.create(new File(jars, "uses-api-impl-dep.jar"), null, false, false, false);
mgr.enable(m1);
mgr.enable(m2);
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
mgr.disable(m2);
mgr.disable(m1);
mgr.delete(m2);
mgr.delete(m1);
// XXX test use of .** to export packages recursively
// XXX test misparsing of malformed export lines
// XXX test exporting of >1 package from one module (comma-separated)
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
/** Test that package exports, and package/classloader use generally, is not
* transitively exported from modules - that you need to declare an explicit
* module dependency on every module from which you expect to load classes
* or resources, even if you are already declaring a dependency on an inter-
* mediate module which has such a dependency.
* @see "#27853"
*/
public void testIndirectPackageExports() throws Exception {
ModuleManager mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents());
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "api-mod-export-api.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "uses-and-exports-api.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "uses-api-transitively.jar"), null, false, false, false);
Module m4 = mgr.create(new File(jars, "uses-api-directly.jar"), null, false, false, false);
assertEquals("api-mod-export-api.jar had no problems", Collections.EMPTY_SET, m1.getProblems());
assertEquals("uses-and-exports-api.jar had no problems", Collections.EMPTY_SET, m2.getProblems());
assertEquals("uses-api-transitively.jar had no problems", Collections.EMPTY_SET, m3.getProblems());
assertEquals("uses-api-directly.jar had no problems", Collections.EMPTY_SET, m4.getProblems());
mgr.enable(new HashSet<Module>(Arrays.asList(m1, m2, m3, m4)));
m4.getClassLoader().loadClass("usesapitrans.UsesDirectAPI").newInstance();
m4.getClassLoader().loadClass("usesapitrans.UsesIndirectAPI").newInstance();
m3.getClassLoader().loadClass("usesapitrans.UsesDirectAPI").newInstance();
try {
m3.getClassLoader().loadClass("usesapitrans.UsesIndirectAPI").newInstance();
fail("Should not be able to use a transitive API class with no direct dependency");
} catch (NoClassDefFoundError e) {}
mgr.disable(new HashSet<Module>(Arrays.asList(m1, m2, m3, m4)));
mgr.delete(m4);
mgr.delete(m3);
mgr.delete(m2);
mgr.delete(m1);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testPublicPackagesCanBeExportedToSelectedFriendsOnlyIssue54123 () throws Exception {
ModuleManager mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents());
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "api-mod-export-friend.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "uses-api-friend.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "uses-and-exports-api.jar"), null, false, false, false);
Module m4 = mgr.create(new File(jars, "uses-api-directly.jar"), null, false, false, false);
Module m5 = mgr.create(new File(jars, "uses-api-impl-dep-for-friends.jar"), null, false, false, false);
assertEquals("api-mod-export-api.jar had no problems", Collections.EMPTY_SET, m1.getProblems());
assertEquals("uses-api-friend.jar had no problems", Collections.EMPTY_SET, m2.getProblems());
assertEquals("uses-and-exports-api.jar had no problems", Collections.EMPTY_SET, m3.getProblems());
assertEquals("uses-api-directly.jar had no problems", Collections.EMPTY_SET, m4.getProblems());
assertEquals("uses-api-impl-dep-for-friends.jar had no problems", Collections.EMPTY_SET, m5.getProblems());
mgr.enable(new HashSet<Module>(Arrays.asList(m1, m2, m3, m4, m5)));
m2.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
try {
m2.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
fail ("Even friends modules cannot access implementation classes");
} catch (NoClassDefFoundError ex) {
// ok
}
try {
m4.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
fail ("m4 is not friend and should not be allowed to load the class");
} catch (NoClassDefFoundError ex) {
// ok
}
try {
m4.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
fail ("m4 is not friend and should not be allowed to load the implementation either");
} catch (NoClassDefFoundError ex) {
// ok
}
try {
m5.getClassLoader().loadClass("usesapi.UsesPublicClass").newInstance();
} catch (NoClassDefFoundError e) {
fail("m5 has an implementation dependency and has not been allowed to load the public class");
}
try {
m5.getClassLoader().loadClass("usesapi.UsesImplClass").newInstance();
} catch (NoClassDefFoundError e) {
fail("m5 has an implementation dependency and has not been allowed to load the imlpementation class");
}
mgr.disable(new HashSet<Module>(Arrays.asList(m1, m2, m3, m4, m5)));
mgr.delete(m5);
mgr.delete(m4);
mgr.delete(m3);
mgr.delete(m2);
mgr.delete(m1);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testModuleInterdependencies() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false, false);
Module m3 = mgr.create(new File(jars, "dep-on-dep-on-simple.jar"), null, false, false, false);
Set<Module> m1m2 = new HashSet<>(Arrays.asList(m1, m2));
Set<Module> m2m3 = new HashSet<>(Arrays.asList(m2, m3));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m1, false, false, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m1, false, true, true));
assertEquals(Collections.singleton(m2), mgr.getModuleInterdependencies(m1, true, false, true));
assertEquals(m2m3, mgr.getModuleInterdependencies(m1, true, true, true));
assertEquals(Collections.singleton(m1), mgr.getModuleInterdependencies(m2, false, false, true));
assertEquals(Collections.singleton(m1), mgr.getModuleInterdependencies(m2, false, true, true));
assertEquals(Collections.singleton(m3), mgr.getModuleInterdependencies(m2, true, false, true));
assertEquals(Collections.singleton(m3), mgr.getModuleInterdependencies(m2, true, true, true));
assertEquals(Collections.singleton(m2), mgr.getModuleInterdependencies(m3, false, false, true));
assertEquals(m1m2, mgr.getModuleInterdependencies(m3, false, true, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m3, true, false, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m3, true, true, true));
m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false);
m2 = mgr.create(new File(jars, "prov-foo-bar.jar"), null, false, false, false);
m3 = mgr.create(new File(jars, "req-foo.jar"), null, false, false, false);
Module m4 = mgr.create(new File(jars, "prov-baz.jar"), null, false, false, false);
Module m5 = mgr.create(new File(jars, "req-foo-baz.jar"), null, false, false, false);
m1m2 = new HashSet<>(Arrays.asList(m1, m2));
assertEquals(m1m2, mgr.getModuleInterdependencies(m3, false, true, true));
Set<Module> m1m2m4 = new HashSet<>(Arrays.asList(m1, m2, m4));
assertEquals(m1m2m4, mgr.getModuleInterdependencies(m5, false, true, true));
Set<Module> m3m5 = new HashSet<>(Arrays.asList(m3, m5));
assertEquals(m3m5, mgr.getModuleInterdependencies(m1, true, true, true));
// XXX could do more...
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testModuleInterdependenciesOSGi() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
final File f1 = changeManifest(new File(jars, "simple-module.jar"),
"Bundle-SymbolicName: org.simple\n"
+ "\n"
+ "\n"
+ "\n"
);
final File f2 = changeManifest(new File(jars, "depends-on-simple-module.jar"),
"Bundle-SymbolicName: org.depsonsimple\n"
+ "Require-Bundle: org.simple\n"
+ "\n"
+ "\n"
);
final File f3 = changeManifest(new File(jars, "dep-on-dep-on-simple.jar"),
"Bundle-SymbolicName: org.deps.depsonsimple\n"
+ "Require-Bundle: org.depsonsimple\n"
+ "\n"
+ "\n"
);
Module m1 = mgr.create(f1, null, false, false, false);
Module m2 = mgr.create(f2, null, false, false, false);
Module m3 = mgr.create(f3, null, false, false, false);
Set<Module> m1m2 = new HashSet<>(Arrays.asList(m1, m2));
Set<Module> m2m3 = new HashSet<>(Arrays.asList(m2, m3));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m1, false, false, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m1, false, true, true));
assertEquals(Collections.singleton(m2), mgr.getModuleInterdependencies(m1, true, false, true));
assertEquals(m2m3, mgr.getModuleInterdependencies(m1, true, true, true));
assertEquals(Collections.singleton(m1), mgr.getModuleInterdependencies(m2, false, false, true));
assertEquals(Collections.singleton(m1), mgr.getModuleInterdependencies(m2, false, true, true));
assertEquals(Collections.singleton(m3), mgr.getModuleInterdependencies(m2, true, false, true));
assertEquals(Collections.singleton(m3), mgr.getModuleInterdependencies(m2, true, true, true));
assertEquals(Collections.singleton(m2), mgr.getModuleInterdependencies(m3, false, false, true));
assertEquals(m1m2, mgr.getModuleInterdependencies(m3, false, true, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m3, true, false, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m3, true, true, true));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testModuleImportOSGi() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
final File f1 = changeManifest(new File(jars, "simple-module.jar"),
"Bundle-SymbolicName: org.simple\n"
+ "Export-Package: org.simple.util\n"
+ "\n"
+ "\n"
);
final File f2 = changeManifest(new File(jars, "depends-on-simple-module.jar"),
"Bundle-SymbolicName: org.depsonsimple\n"
+ "Export-Package: org.depsonsimple.test\n"
+ "Import-Package: org.simple.util\n"
+ "\n"
+ "\n"
);
final File f3 = changeManifest(new File(jars, "dep-on-dep-on-simple.jar"),
"Bundle-SymbolicName: org.deps.depsonsimple\n"
+ "Import-Package: org.depsonsimple.test\n"
+ "\n"
+ "\n"
);
Module m1 = mgr.create(f1, null, false, false, false);
Module m2 = mgr.create(f2, null, false, false, false);
Module m3 = mgr.create(f3, null, false, false, false);
Set<Module> m1m2 = new HashSet<>(Arrays.asList(m1, m2));
Set<Module> m2m3 = new HashSet<>(Arrays.asList(m2, m3));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m1, false, false, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m1, false, true, true));
assertEquals(Collections.singleton(m2), mgr.getModuleInterdependencies(m1, true, false, true));
assertEquals(m2m3, mgr.getModuleInterdependencies(m1, true, true, true));
assertEquals(Collections.singleton(m1), mgr.getModuleInterdependencies(m2, false, false, true));
assertEquals(Collections.singleton(m1), mgr.getModuleInterdependencies(m2, false, true, true));
assertEquals(Collections.singleton(m3), mgr.getModuleInterdependencies(m2, true, false, true));
assertEquals(Collections.singleton(m3), mgr.getModuleInterdependencies(m2, true, true, true));
assertEquals(Collections.singleton(m2), mgr.getModuleInterdependencies(m3, false, false, true));
assertEquals(m1m2, mgr.getModuleInterdependencies(m3, false, true, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m3, true, false, true));
assertEquals(Collections.EMPTY_SET, mgr.getModuleInterdependencies(m3, true, true, true));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testModuleInterdependenciesNeeds() throws Exception { // #114896
File dir = getWorkDir();
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
File jar = new File(dir, "api.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: api\nOpenIDE-Module-Needs: provider\n\n");
Module api = mgr.create(jar, null, false, false, false);
jar = new File(dir, "impl.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: impl\nOpenIDE-Module-Provides: provider\n" +
"OpenIDE-Module-Module-Dependencies: api\n\n");
Module impl = mgr.create(jar, null, false, false, false);
jar = new File(dir, "client.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: client\nOpenIDE-Module-Module-Dependencies: api\n\n");
Module client = mgr.create(jar, null, false, false, false);
assertEquals(Collections.singleton(api), mgr.getModuleInterdependencies(impl, false, false, true));
assertEquals(Collections.singleton(api), mgr.getModuleInterdependencies(impl, false, true, true));
assertEquals(Collections.singleton(api), mgr.getModuleInterdependencies(impl, true, false, true));
assertEquals(new HashSet<Module>(Arrays.asList(api, client)), mgr.getModuleInterdependencies(impl, true, true, true));
assertEquals(Collections.singleton(api), mgr.getModuleInterdependencies(client, false, false, true));
assertEquals(new HashSet<Module>(Arrays.asList(api, impl)), mgr.getModuleInterdependencies(client, false, true, true));
assertEquals(Collections.emptySet(), mgr.getModuleInterdependencies(client, true, false, true));
assertEquals(Collections.emptySet(), mgr.getModuleInterdependencies(client, true, true, true));
assertEquals(Collections.singleton(impl), mgr.getModuleInterdependencies(api, false, false, true));
assertEquals(Collections.singleton(impl), mgr.getModuleInterdependencies(api, false, true, true));
assertEquals(new HashSet<Module>(Arrays.asList(impl, client)), mgr.getModuleInterdependencies(api, true, false, true));
assertEquals(new HashSet<Module>(Arrays.asList(impl, client)), mgr.getModuleInterdependencies(api, true, true, true));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testCyclicNeeds() throws Exception { // #161917
File dir = getWorkDir();
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
File jar = new File(dir, "a.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: a\nOpenIDE-Module-Needs: T1\nOpenIDE-Module-Provides: T2\n\n");
Module a = mgr.create(jar, null, false, false, false);
jar = new File(dir, "b.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: b\nOpenIDE-Module-Needs: T2\nOpenIDE-Module-Provides: T1\n\n");
Module b = mgr.create(jar, null, false, false, false);
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, false, false, true));
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, false, true, true));
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, true, false, true));
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, true, true, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, false, false, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, false, true, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, true, false, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, true, true, true));
Set<Module> both = new HashSet<>(Arrays.asList(a, b));
assertEquals(both, new HashSet<Module>(mgr.simulateEnable(Collections.singleton(a))));
assertEquals(both, new HashSet<Module>(mgr.simulateEnable(Collections.singleton(b))));
mgr.enable(both);
assertEquals(both, mgr.getEnabledModules());
mgr.disable(both);
assertEquals(Collections.emptySet(), mgr.getEnabledModules());
mgr.delete(a);
mgr.delete(b);
jar = new File(dir, "a.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: a\nOpenIDE-Module-Needs: T1\nOpenIDE-Module-Provides: T2\n" +
"OpenIDE-Module-Module-Dependencies: b\n");
a = mgr.create(jar, null, false, false, false);
jar = new File(dir, "b.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: b\nOpenIDE-Module-Needs: T2\nOpenIDE-Module-Provides: T1\n\n");
b = mgr.create(jar, null, false, false, false);
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, false, false, true));
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, false, true, true));
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, true, false, true));
assertEquals(Collections.singleton(a), mgr.getModuleInterdependencies(b, true, true, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, false, false, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, false, true, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, true, false, true));
assertEquals(Collections.singleton(b), mgr.getModuleInterdependencies(a, true, true, true));
both = new HashSet<>(Arrays.asList(a, b));
assertEquals(both, new HashSet<Module>(mgr.simulateEnable(Collections.singleton(a))));
assertEquals(both, new HashSet<Module>(mgr.simulateEnable(Collections.singleton(b))));
mgr.enable(both);
assertEquals(both, mgr.getEnabledModules());
mgr.disable(both);
assertEquals(Collections.emptySet(), mgr.getEnabledModules());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testModuleClassLoaderWasNotReadyWhenTheChangeWasFiredIssue() throws Exception {
doModuleClassLoaderWasNotReadyWhenTheChangeWasFiredIssue (1);
}
public void testGlobalClassLoaderWasNotReadyWhenTheChangeWasFiredIssue() throws Exception {
doModuleClassLoaderWasNotReadyWhenTheChangeWasFiredIssue (2);
}
public void testModuleManagerClassLoaderWasNotReadyWhenTheChangeWasFiredIssue() throws Exception {
doModuleClassLoaderWasNotReadyWhenTheChangeWasFiredIssue (3);
}
private void doModuleClassLoaderWasNotReadyWhenTheChangeWasFiredIssue (final int typeOfClassLoader) throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
final ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
final Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false);
class L implements java.beans.PropertyChangeListener {
ClassLoader l;
IllegalStateException ex;
public @Override void propertyChange(java.beans.PropertyChangeEvent event) {
if (Module.PROP_ENABLED.equals (event.getPropertyName ())) {
try {
l = get();
} catch (IllegalStateException x) {
ex = x;
}
}
}
public ClassLoader get () {
switch (typeOfClassLoader) {
case 1: return m1.getClassLoader ();
case 2: return Thread.currentThread ().getContextClassLoader ();
case 3: return mgr.getClassLoader ();
}
fail ("Wrong type: " + typeOfClassLoader);
return null;
}
}
L l = new L ();
m1.addPropertyChangeListener (l);
mgr.enable (m1);
assertTrue ("Successfully enabled", m1.isEnabled ());
assertEquals ("Classloader at the time of PROP_ENABLED is the same as now", l.get (), l.l);
assertNull ("No exception thrown", l.ex);
//System.out.println("L: " + l.l);
m1.removePropertyChangeListener (l);
mgr.disable (m1);
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
/** @see "#76917" */
public void testProblemsStillCorrectWithHardAndSoftMixture() throws Exception {
File m1j = new File(getWorkDir(), "m1.jar");
createJar(m1j, Collections.<String,String>emptyMap(), Collections.singletonMap("OpenIDE-Module", "m1"));
File m2j = new File(getWorkDir(), "m2.jar");
Map<String,String> mani = new HashMap<String,String>();
mani.put("OpenIDE-Module", "m2");
mani.put("OpenIDE-Module-Module-Dependencies", "m1");
mani.put("OpenIDE-Module-Java-Dependencies", "Java > 2046");
createJar(m2j, Collections.<String,String>emptyMap(), mani);
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m2 = mgr.create(m2j, null, false, false, false);
assertEquals("initially m2 has two problems: Java and m1", 2, m2.getProblems().size());
Module m1 = mgr.create(m1j, null, false, false, false);
assertEquals("m1 has no problems", Collections.emptySet(), m1.getProblems());
assertEquals("now m2 should have just one problem: Java", 1, m2.getProblems().size());
Dependency d = (Dependency) m2.getProblems().iterator().next();
assertEquals(Dependency.TYPE_JAVA, d.getType());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testShouldDelegateResource() throws Exception {
File m1j = new File(getWorkDir(), "m1.jar");
Map<String,String> contents = new HashMap<String,String>();
contents.put("javax/swing/JPanel.class", "overrides");
contents.put("javax/xml/parsers/DocumentBuilder.class", "ignored");
createJar(m1j, contents, Collections.singletonMap("OpenIDE-Module", "m1"));
File m2j = new File(getWorkDir(), "m2.jar");
Map<String,String> mani = new HashMap<String,String>();
mani.put("OpenIDE-Module", "m2");
mani.put("OpenIDE-Module-Module-Dependencies", "m1");
createJar(m2j, Collections.<String,String>emptyMap(), mani);
File m3j = new File(getWorkDir(), "m3.jar");
createJar(m3j, Collections.<String,String>emptyMap(), Collections.singletonMap("OpenIDE-Module", "m3"));
MockModuleInstaller installer = new MockModuleInstaller() {
public @Override boolean shouldDelegateResource(Module m, Module parent, String pkg) {
if (parent == null && pkg.equals("javax/swing/") && m.getCodeNameBase().matches("m[12]")) {
return false;
} else {
return true;
}
}
};
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(m1j, null, false, false, false);
Module m2 = mgr.create(m2j, null, false, false, false);
Module m3 = mgr.create(m3j, null, false, false, false);
mgr.enable(new HashSet<Module>(Arrays.asList(m1, m2, m3)));
assertOverrides(m1, "javax.swing.JPanel");
assertOverrides(m2, "javax.swing.JPanel");
assertDoesNotOverride(m3, "javax.swing.JPanel");
assertDoesNotOverride(m1, "javax.xml.parsers.DocumentBuilder");
assertDoesNotOverride(m2, "javax.xml.parsers.DocumentBuilder");
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public static void assertOverrides(ClassLoader l, String name, String clazz) throws Exception {
try {
assertFalse(name + " did not override " + clazz, Class.forName(clazz) == l.loadClass(clazz));
} catch (LinkageError e) {
// right: we don't provide legal class bodies here, so it would fail to even load
}
String rsrc = clazz.replace('.', '/') + ".class";
URL cpResource = ModuleManagerTest.class.getResource("/" + rsrc);
assertNotNull("found " + rsrc, cpResource);
URL modResource = l.getResource(rsrc);
assertNotNull("found " + rsrc, modResource);
assertFalse(name + " did not override " + rsrc, cpResource.equals(modResource));
}
public static void assertOverrides(Module m, String clazz) throws Exception {
assertOverrides(m.getClassLoader(), "module " + m.getCodeNameBase(), clazz);
}
public static void assertDoesNotOverride(ClassLoader l, String clazz) throws Exception {
assertEquals(Class.forName(clazz), l.loadClass(clazz));
String rsrc = clazz.replace('.', '/') + ".class";
URL cpResource = ModuleManagerTest.class.getResource("/" + rsrc);
assertNotNull("found " + rsrc, cpResource);
URL modResource = l.getResource(rsrc);
assertNotNull("found " + rsrc, modResource);
assertEquals(cpResource, modResource);
}
public static void assertDoesNotOverride(Module m, String clazz) throws Exception {
assertDoesNotOverride(m.getClassLoader(), clazz);
}
public void testDisableWithAutoloadMajorRange() throws Exception { // #127720; also see testDisableAgainstRelVersRange
File m1j = new File(getWorkDir(), "m1.jar");
createJar(m1j, Collections.<String,String>emptyMap(), Collections.singletonMap("OpenIDE-Module", "m1/0"));
File m2j = new File(getWorkDir(), "m2.jar");
Map<String,String> mani = new HashMap<String,String>();
mani.put("OpenIDE-Module", "m2");
mani.put("OpenIDE-Module-Module-Dependencies", "m1/0-1");
createJar(m2j, Collections.<String,String>emptyMap(), mani);
File m3j = new File(getWorkDir(), "m3.jar");
mani = new HashMap<String,String>();
mani.put("OpenIDE-Module", "m3");
mani.put("OpenIDE-Module-Module-Dependencies", "m1/0");
createJar(m3j, Collections.<String,String>emptyMap(), mani);
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(m1j, null, false, true, false);
Module m2 = mgr.create(m2j, null, false, false, false);
Module m3 = mgr.create(m3j, null, false, false, false);
mgr.enable(m2);
mgr.enable(m3);
assertTrue(m1.isEnabled());
assertTrue(m2.isEnabled());
assertTrue(m3.isEnabled());
assertEquals(Collections.singletonList(m3), mgr.simulateDisable(Collections.singleton(m3)));
mgr.disable(m3);
assertTrue(m1.isEnabled());
assertTrue(m2.isEnabled());
assertFalse(m3.isEnabled());
assertEquals(Arrays.asList(m2, m1), mgr.simulateDisable(Collections.singleton(m2)));
mgr.disable(m2);
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
assertFalse(m3.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testDisableWithRegularMajorRange() throws Exception { // #197718
File m1j = new File(getWorkDir(), "m1.jar");
createJar(m1j, Collections.<String,String>emptyMap(), Collections.singletonMap("OpenIDE-Module", "m1/0"));
File m2j = new File(getWorkDir(), "m2.jar");
Map<String,String> mani = new HashMap<String,String>();
mani.put("OpenIDE-Module", "m2");
mani.put("OpenIDE-Module-Module-Dependencies", "m1/0-1");
createJar(m2j, Collections.<String,String>emptyMap(), mani);
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module m1 = mgr.create(m1j, null, false, false, false);
Module m2 = mgr.create(m2j, null, false, false, false);
mgr.enable(new HashSet<Module>(Arrays.asList(m1, m2)));
assertTrue(m1.isEnabled());
assertTrue(m2.isEnabled());
assertEquals(Arrays.asList(m2, m1), mgr.simulateDisable(Collections.singleton(m1)));
mgr.disable(new HashSet<Module>(Arrays.asList(m1, m2)));
assertFalse(m1.isEnabled());
assertFalse(m2.isEnabled());
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
public void testModuleOwnsClass() throws Exception { // #157798
clearWorkDir();
data = new File(getWorkDir(), "data");
jars = new File(getWorkDir(), "jars");
TestFileUtils.writeFile(new File(data, "mod1.mf"), "OpenIDE-Module: mod1/1\n\n");
TestFileUtils.writeFile(new File(data, "mod1/pkg/C1.java"), "package pkg; class C1 {}");
TestFileUtils.writeFile(new File(data, "mod1/pkg/C2.java"), "package pkg; class C2 {}");
File mod1JAR = createTestJAR(data, jars, "mod1", null);
TestFileUtils.writeFile(new File(data, "mod2.mf"), "OpenIDE-Module: mod2/1\n\n");
TestFileUtils.writeFile(new File(data, "mod2/pkg/C3.java"), "package pkg; class C3 {}");
File mod2JAR = createTestJAR(data, jars, "mod2", null);
ModuleManager mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents());
Modules modules = mgr.getModuleLookup().lookup(Modules.class);
assertNotNull(modules);
mgr.mutexPrivileged().enterWriteAccess();
try {
Module mod1 = mgr.create(mod1JAR, null, false, false, false);
mgr.enable(mod1);
Module mod2 = mgr.create(mod2JAR, null, false, false, false);
mgr.enable(mod2);
Class<?> c1 = mod1.getClassLoader().loadClass("pkg.C1");
Class<?> c2 = mod1.getClassLoader().loadClass("pkg.C2");
Class<?> c3 = mod2.getClassLoader().loadClass("pkg.C3");
assertTrue(mod1.owns(c1));
assertTrue(mod1.owns(c2));
assertFalse(mod1.owns(c3));
assertFalse(mod2.owns(c1));
assertFalse(mod2.owns(c2));
assertTrue(mod2.owns(c3));
assertEquals(mod1, modules.ownerOf(c1));
assertEquals(mod1, modules.ownerOf(c2));
assertEquals(mod2, modules.ownerOf(c3));
assertNull(modules.ownerOf(String.class));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents());
modules = mgr.getModuleLookup().lookup(Modules.class);
assertNotNull(modules);
mgr.mutexPrivileged().enterWriteAccess();
try {
ClassLoader l = new URLClassLoader(new URL[] {Utilities.toURI(mod1JAR).toURL(), Utilities.toURI(mod2JAR).toURL()});
Module mod1 = mgr.createFixed(loadManifest(mod1JAR), null, l);
mgr.enable(mod1);
assertEquals(l, mod1.getClassLoader());
Module mod2 = mgr.createFixed(loadManifest(mod2JAR), null, l);
mgr.enable(mod2);
Class<?> c1 = l.loadClass("pkg.C1");
assertEquals(l, c1.getClassLoader());
Class<?> c2 = l.loadClass("pkg.C2");
Class<?> c3 = l.loadClass("pkg.C3");
assertTrue(mod1.owns(c1));
assertTrue(mod1.owns(c2));
assertFalse(mod1.owns(c3));
assertFalse(mod2.owns(c1));
assertFalse(mod2.owns(c2));
assertTrue(mod2.owns(c3));
assertEquals(mod1, modules.ownerOf(c1));
assertEquals(mod1, modules.ownerOf(c2));
assertEquals(mod2, modules.ownerOf(c3));
assertNull(modules.ownerOf(String.class));
} finally {
mgr.mutexPrivileged().exitWriteAccess();
}
}
private static Manifest loadManifest(File jar) throws IOException {
JarFile j = new JarFile(jar);
try {
return j.getManifest();
} finally {
j.close();
}
}
public void testMissingSpecVersion() throws Exception {
File dir = getWorkDir();
ModuleManager mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents());
mgr.mutexPrivileged().enterWriteAccess();
File jar = new File(dir, "api.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: api\n\n");
mgr.create(jar, null, false, false, false);
jar = new File(dir, "client.jar");
TestFileUtils.writeZipFile(jar, "META-INF/MANIFEST.MF:OpenIDE-Module: client\nOpenIDE-Module-Module-Dependencies: api > 1.0\n\n");
Module client = mgr.create(jar, null, false, false, false);
assertEquals(1, client.getProblems().size());
}
public void testEnableHostWithEagerFragment() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
Module host = mgr.create(new File(jars, "host-module.jar"), null, false, false, false);
Module fragment = mgr.create(new File(jars, "fragment-module.jar"), null, false, false, true);
assertTrue("Host is known", mgr.getModules().contains(host));
assertTrue("Fragment is known", mgr.getModules().contains(fragment));
mgr.enable(host);
assertTrue("Host must be enabled", mgr.getEnabledModules().contains(host));
assertTrue("Fragment must be enabled", mgr.getEnabledModules().contains(fragment));
}
public void testEnableHostWithEagerFragmentUnsatisfied() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
createTestJAR(data, jars, "fragment-module-missing-token", null);
Module host = mgr.create(new File(jars, "host-module.jar"), null, false, false, false);
Module fragment = mgr.create(new File(jars, "fragment-module-missing-token.jar"), null, false, false, true);
assertTrue("Host is known", mgr.getModules().contains(host));
assertTrue("Fragment is known", mgr.getModules().contains(fragment));
mgr.enable(host);
assertTrue("Host must be enabled", mgr.getEnabledModules().contains(host));
assertTrue("Fragment must not be enabled", !mgr.getEnabledModules().contains(fragment));
}
public void testEnableFragmentBeforeItsHost() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
// m1 autoload, m2 normal, m3 eager
Module m1 = mgr.create(new File(jars, "host-module.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "fragment-module.jar"), null, false, false, false);
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertTrue("Host will be enabled", toEnable.contains(m1));
assertTrue("Known fragment must be merged in", toEnable.contains(m2));
mgr.enable(new HashSet<>(toEnable));
}
public void testEnableHostWithoutFragment() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
// m1 autoload, m2 normal, m3 eager
Module m1 = mgr.create(new File(jars, "host-module.jar"), null, false, false, false);
Module m2 = mgr.create(new File(jars, "fragment-module.jar"), null, false, false, false);
List<Module> toEnable = mgr.simulateEnable(Collections.singleton(m2));
assertTrue("Host will be enabled", toEnable.contains(m1));
assertTrue("Known fragment must be merged in", toEnable.contains(m2));
mgr.enable(new HashSet<>(toEnable));
}
public void testInstallFragmentAfterHostEnabled() throws Exception {
MockModuleInstaller installer = new MockModuleInstaller();
MockEvents ev = new MockEvents();
ModuleManager mgr = new ModuleManager(installer, ev);
mgr.mutexPrivileged().enterWriteAccess();
// m1 autoload, m2 normal, m3 eager
Module m1 = mgr.create(new File(jars, "host-module.jar"), null, false, false, false);
mgr.enable(m1);
Module m2 = mgr.create(new File(jars, "fragment-module.jar"), null, false, false, false);
try {
mgr.simulateEnable(Collections.singleton(m2));
fail("Enabling fragment must fail if host is already live");
} catch (IllegalStateException ex) {
// ok
}
}
private File copyJar(File file, String manifest) throws IOException {
File ret = File.createTempFile(file.getName(), "2ndcopy", file.getParentFile());
JarFile jar = new JarFile(file);
JarOutputStream os = new JarOutputStream(new FileOutputStream(ret), new Manifest(
new ByteArrayInputStream(manifest.getBytes())
));
Enumeration<JarEntry> en = jar.entries();
while (en.hasMoreElements()) {
JarEntry elem = en.nextElement();
if (elem.getName().equals("META-INF/MANIFEST.MF")) {
continue;
}
os.putNextEntry(elem);
InputStream is = jar.getInputStream(elem);
copyStreams(is, os);
is.close();
}
os.close();
return ret;
}
private static Module createModule(ModuleManager mgr, String manifest) throws Exception {
return mgr.createFixed(new Manifest(new ByteArrayInputStream(manifest.getBytes())), null, ModuleManagerTest.class.getClassLoader());
}
private static Collection<String> assertCnb(Module m) {
String token = "cnb." + m.getCodeNameBase();
List<String> arr = new ArrayList<String>();
boolean ok = false;
for (String t : m.getProvides()) {
if (token.equals(t)) {
ok = true;
} else {
arr.add(t);
}
}
assertTrue(token + " is not among the list of provides of module " + m + " which is " + arr, ok);
return arr;
}
}