blob: 169d91a72f08ed66d11b95d7c60c353ec8a2f255 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020, 2021 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);
}
}