| /* |
| * 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; |
| } |
| } |