diff options
2 files changed, 218 insertions, 1 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/AllTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/AllTests.java index df5439bae..47c527cd4 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/AllTests.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/AllTests.java @@ -13,13 +13,16 @@ *******************************************************************************/ package org.eclipse.osgi.tests.container; -import junit.framework.*; +import junit.framework.JUnit4TestAdapter; +import junit.framework.Test; +import junit.framework.TestSuite; public class AllTests { public static Test suite() { TestSuite suite = new TestSuite(AllTests.class.getName()); suite.addTest(new JUnit4TestAdapter(TestModuleContainer.class)); suite.addTest(new JUnit4TestAdapter(ResolutionReportTest.class)); + suite.addTest(new JUnit4TestAdapter(ModuleContainerUsageTest.class)); return suite; } } diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/ModuleContainerUsageTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/ModuleContainerUsageTest.java new file mode 100644 index 000000000..112f5579f --- /dev/null +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/ModuleContainerUsageTest.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright (c) 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.tests.container; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.osgi.container.Module; +import org.eclipse.osgi.container.Module.State; +import org.eclipse.osgi.container.ModuleCapability; +import org.eclipse.osgi.container.ModuleContainer; +import org.eclipse.osgi.container.ModuleRevision; +import org.eclipse.osgi.container.ModuleRevisionBuilder; +import org.eclipse.osgi.container.builders.OSGiManifestBuilderFactory; +import org.eclipse.osgi.report.resolution.ResolutionReport; +import org.eclipse.osgi.tests.container.dummys.DummyContainerAdaptor; +import org.junit.Test; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.hooks.resolver.ResolverHook; +import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; +import org.osgi.framework.namespace.PackageNamespace; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.BundleRequirement; +import org.osgi.framework.wiring.BundleRevision; + +public class ModuleContainerUsageTest extends AbstractTest { + static final String EE_INDEX = "internal.ee.index"; + + @Test + public void testMultipleExecutionEnvironments() throws BundleException { + + final List<BundleCapability> executionEnvironments = Collections.synchronizedList(new ArrayList<>()); + + /** + * A resolver hook that filters packages based on the required EE of a module + */ + ResolverHook resolverHook = new ResolverHook() { + + @Override + public void filterSingletonCollisions(BundleCapability singleton, + Collection<BundleCapability> collisionCandidates) { + // don't care about possible collisions + collisionCandidates.clear(); + } + + @Override + public void filterResolvable(Collection<BundleRevision> candidates) { + // don't stop any revision from resolving + } + + @Override + public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) { + if (PackageNamespace.PACKAGE_NAMESPACE.equals(requirement.getNamespace())) { + // only filter based on EE for package requirements + filterBasedOnEE( + (AtomicReference<Long>) ((ModuleRevision) requirement.getRevision()).getRevisionInfo(), + candidates); + } + } + + private void filterBasedOnEE(AtomicReference<Long> revisionInfo, + Collection<BundleCapability> candidates) { + Long eeIndex = revisionInfo.get(); + // if the eeIndex is set for the revision then check if the package is + // available in the specified EE + if (eeIndex != null) { + Iterator<BundleCapability> iCandidates = candidates.iterator(); + while (iCandidates.hasNext()) { + ModuleCapability candidate = (ModuleCapability) iCandidates.next(); + // only check the ee index for the packages from the system module (id=0) + if (candidate.getRevision().getRevisions().getModule().getId() == 0) { + Object candidateEEIndex = candidate.getAttributes().get(EE_INDEX); + if (candidateEEIndex != null && !eeIndex.equals(candidateEEIndex)) { + iCandidates.remove(); + } + } + } + } + } + + @Override + public void end() { + // do nothing special at the end of resolution + } + }; + DummyContainerAdaptor adaptor = createDummyAdaptor(resolverHook); + ModuleContainer container = adaptor.getContainer(); + + // Notice that there are duplicate packages exported for each EE_INDEX + StringBuilder systemPackages = new StringBuilder(); + systemPackages.append("test.pkg1; " + EE_INDEX + ":Long=1"); + systemPackages.append(",test.pkg1; test.pkg2; " + EE_INDEX + ":Long=2"); + systemPackages.append(",test.pkg1; test.pkg2; test.pkg3; " + EE_INDEX + ":Long=3"); + systemPackages.append(",test.pkg1; test.pkg2; test.pkg3; test.pkg4; " + EE_INDEX + ":Long=4"); + systemPackages.append(",test.pkg1; test.pkg2; test.pkg3; test.pkg4; test.pkg5; " + EE_INDEX + ":Long=5"); + + // Notice that each defined EE capability has an EE_INDEX defined that matches + // the set of packages + // above for the specified EE_INDEX + StringBuilder systemEEs = new StringBuilder(); + systemEEs.append( + "osgi.ee; osgi.ee=\"JavaSE\"; version:List<Version>=\"1.0, 1.1, 1.2, 1.3, 1.4, 1.5\"; " + EE_INDEX + + ":Long=1"); + systemEEs.append( + ",osgi.ee; osgi.ee=\"JavaSE\"; version:List<Version>=\"1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6\"; " + EE_INDEX + + ":Long=2"); + systemEEs.append( + ",osgi.ee; osgi.ee=\"JavaSE\"; version:List<Version>=\"1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7\"; " + + EE_INDEX + ":Long=3"); + systemEEs.append( + ",osgi.ee; osgi.ee=\"JavaSE\"; version:List<Version>=\"1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8\"; " + + EE_INDEX + ":Long=4"); + systemEEs.append( + ",osgi.ee; osgi.ee=\"JavaSE\"; version:List<Version>=\"1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 9.0\"; " + + EE_INDEX + ":Long=5"); + + ModuleRevisionBuilder systemModuleBuilder = OSGiManifestBuilderFactory.createBuilder(getSystemManifest(), + Constants.SYSTEM_BUNDLE_SYMBOLICNAME, systemPackages.toString(), systemEEs.toString()); + Module systemBundle = container.install(null, Constants.SYSTEM_BUNDLE_LOCATION, systemModuleBuilder, + new AtomicReference<Long>()); + executionEnvironments.addAll(systemBundle.getCurrentRevision() + .getDeclaredCapabilities(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE)); + + Module m1 = installModule(container, "m1", "1.0", "test.pkg1", "JavaSE-1.5", + executionEnvironments); + Module m2 = installModule(container, "m2", "1.0", "test.pkg1,test.pkg2", "JavaSE-1.5", + executionEnvironments); + + Module m3 = installModule(container, "m3", "1.0", "test.pkg1,test.pkg2,test.pkg3", "JavaSE-1.7", + executionEnvironments); + Module m4 = installModule(container, "m4", "1.0", "test.pkg1,test.pkg2,test.pkg3,test.pkg4", "JavaSE-1.7", + executionEnvironments); + + ResolutionReport report = container.resolve(Arrays.asList(m1, m2, m3, m4), false); + assertEquals("Wrong state for m1.", State.RESOLVED, m1.getState()); + assertEquals("Wrong state for m2.", State.INSTALLED, m2.getState()); + assertEquals("Wrong state for m3.", State.RESOLVED, m3.getState()); + assertEquals("Wrong state for m4.", State.INSTALLED, m4.getState()); + + String resolutionErrorM2 = report.getResolutionReportMessage(m2.getCurrentRevision()); + assertNotNull("Expected resolution message", resolutionErrorM2); + assertTrue("Wrong resolution message.", resolutionErrorM2.contains("test.pkg2")); + + String resolutionErrorM4 = report.getResolutionReportMessage(m4.getCurrentRevision()); + assertNotNull("Expected resolution message", resolutionErrorM4); + assertTrue("Wrong resolution message.", resolutionErrorM4.contains("test.pkg4")); + } + + private Map<String, String> getSystemManifest() { + Map<String, String> result = new HashMap<>(); + result.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + result.put(Constants.BUNDLE_SYMBOLICNAME, "org.eclipse.osgi"); + result.put(Constants.BUNDLE_VERSION, "1.0"); + result.put(Constants.EXPORT_PACKAGE, "org.osgi.framework; version=1.10"); + return result; + } + + Module installModule(ModuleContainer container, String bsn, String version, String imports, String eeReqs, + List<BundleCapability> availableEEs) throws BundleException { + ModuleRevisionBuilder builder = createModuleRevisionBuilder(bsn, version, imports, eeReqs); + Module m = container.install(null, bsn, builder, new AtomicReference<Long>()); + // Use a revision info that holds the EE_INDEX of the bundle based + // on the EE capability that matches the modules EE requirement + Collection<BundleRequirement> eeBundleReqs = m.getCurrentRevision() + .getDeclaredRequirements(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE); + + eeBundleReqs.stream().findFirst().ifPresent((r) -> { + // notice that we depend on the available EEs + // to be ordered from least to greatest + for (BundleCapability ee : availableEEs) { + if (r.matches(ee)) { + ((AtomicReference<Long>) m.getCurrentRevision().getRevisionInfo()) + .set((Long) ee.getAttributes().get(EE_INDEX)); + return; + } + } + }); + return m; + } + + @SuppressWarnings("deprecation") + ModuleRevisionBuilder createModuleRevisionBuilder(String bsn, String version, String imports, String eeReq) + throws BundleException { + Map<String, String> manifest = new HashMap<>(); + manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + manifest.put(Constants.BUNDLE_SYMBOLICNAME, bsn); + manifest.put(Constants.BUNDLE_VERSION, version); + manifest.put(Constants.IMPORT_PACKAGE, imports); + manifest.put(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, eeReq); + return OSGiManifestBuilderFactory.createBuilder(manifest); + } +} |