/*
* 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.apache.aries.subsystem.itests.defect;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.aries.subsystem.itests.SubsystemTest;
import org.apache.aries.subsystem.itests.util.TestCapability;
import org.apache.aries.subsystem.itests.util.TestRepository;
import org.apache.aries.subsystem.itests.util.TestRepositoryContent;
import org.eclipse.equinox.region.Region;
import org.eclipse.equinox.region.RegionDigraph;
import org.eclipse.equinox.region.RegionDigraph.FilteredRegion;
import org.eclipse.equinox.region.RegionFilter;
import org.junit.Before;
import org.junit.Test;
import org.ops4j.pax.tinybundles.core.InnerClassStrategy;
import org.ops4j.pax.tinybundles.core.TinyBundles;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.osgi.framework.hooks.weaving.WeavingHook;
import org.osgi.framework.hooks.weaving.WovenClass;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.framework.namespace.PackageNamespace;
import org.osgi.resource.Resource;
import org.osgi.service.repository.Repository;
import org.osgi.service.subsystem.Subsystem;
import org.osgi.service.subsystem.SubsystemConstants;
/*
* https://issues.apache.org/jira/browse/ARIES-1435
*
* Sharing policy updates for dynamic imports, if necessary, should proceed up
* the subsystem region tree.
*/
public class Aries1435Test extends SubsystemTest {
private static final String APPLICATION_A = "application.a.esa";
private static final String APPLICATION_B = "application.b.esa";
private static final String APPLICATION_C = "application.c.esa";
private static final String APPLICATION_D = "application.d.esa";
private static final String APPLICATION_E = "application.e.esa";
private static final String BUNDLE_A = "bundle.a.jar";
private static final String BUNDLE_B = "bundle.b.jar";
private static final String COMPOSITE_A = "composite.a.esa";
private static final String COMPOSITE_B = "composite.b.esa";
private static final String COMPOSITE_C = "composite.c.esa";
private static final String COMPOSITE_D = "composite.d.esa";
private static final String COMPOSITE_E = "composite.e.esa";
private static final String COMPOSITE_F = "composite.f.esa";
private static final String FEATURE_A = "feature.a.esa";
private static final String FEATURE_B = "feature.b.esa";
private static final String FEATURE_C = "feature.c.esa";
private static final String FEATURE_D = "feature.d.esa";
private static boolean createdTestFiles;
@Before
public void createTestFiles() throws Exception {
if (createdTestFiles)
return;
createApplicationB();
createApplicationA();
createCompositeA();
createCompositeB();
createApplicationC();
createFeatureA();
createFeatureB();
createApplicationD();
createCompositeC();
createFeatureC();
createCompositeD();
createFeatureD();
createApplicationE();
createCompositeE();
createCompositeF();
createdTestFiles = true;
}
private AtomicBoolean weavingHookCalled;
@Override
public void setUp() throws Exception {
super.setUp();
try {
serviceRegistrations.add(
bundleContext.registerService(
Repository.class,
createTestRepository(),
null));
}
catch (IOException e) {
throw new RuntimeException(e);
}
weavingHookCalled = new AtomicBoolean();
}
@Test
public void testApplicationWithParentApplication() throws Exception {
testDynamicImport(APPLICATION_B, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, APPLICATION_A);
}
@Test
public void testApplicationWithParentComposite() throws Exception {
testDynamicImport(APPLICATION_B, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, COMPOSITE_A);
}
@Test
public void testApplicationWithParentFeature() throws Exception {
testDynamicImport(APPLICATION_B, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, FEATURE_A);
}
@Test
public void testApplicationWithParentRoot() throws Exception {
testDynamicImport(APPLICATION_B, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, null);
}
@Test
public void testChildExportsPackage() throws Exception {
registerWeavingHook("b");
Subsystem applicationB = installSubsystemFromFile(APPLICATION_B);
try {
Subsystem compositeE = installSubsystemFromFile(applicationB, COMPOSITE_E);
try {
startSubsystem(compositeE);
try {
testSharingPolicy(applicationB, "b", true);
testDynamicImport(applicationB, "b.B");
testSharingPolicy(applicationB, "b", true);
testSharingPolicy(compositeE, "b", false);
testSharingPolicy(getRootSubsystem(), "b", false);
}
finally {
stopSubsystemSilently(compositeE);
}
}
finally {
uninstallSubsystemSilently(compositeE);
}
}
finally {
uninstallSubsystemSilently(applicationB);
}
}
@Test
public void testCompositeWithParentApplication() throws Exception {
testDynamicImport(COMPOSITE_B, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE, APPLICATION_C);
}
@Test
public void testCompositeWithParentComposite() throws Exception {
testDynamicImport(COMPOSITE_B, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE, COMPOSITE_C);
}
@Test
public void testCompositeWithParentFeature() throws Exception {
testDynamicImport(COMPOSITE_B, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE, FEATURE_C);
}
@Test
public void testDisconnectedEdgeWithParent() throws Exception {
registerWeavingHook("b");
Bundle bundleB = getRootSubsystem().getBundleContext().installBundle(
BUNDLE_B, new ByteArrayInputStream(createBundleBContent()));
try {
Subsystem applicationA = installSubsystemFromFile(APPLICATION_A);
try {
Subsystem applicationB = getChild(applicationA, APPLICATION_B);
uninstallSubsystem(applicationB);
removeConnectionWithParent(applicationA);
applicationB = installSubsystemFromFile(applicationA, APPLICATION_B);
try {
try {
testDynamicImport(applicationB, "b.B");
fail("Dynamic import should have failed");
}
catch (AssertionError e) {
// Okay.
}
testSharingPolicy(applicationB, "b", true);
testSharingPolicy(applicationA, "b", false);
testSharingPolicy(getRootSubsystem(), "b", false);
}
finally {
uninstallSubsystemSilently(applicationB);
}
}
finally {
uninstallSubsystemSilently(applicationA);
}
}
finally {
uninstallSilently(bundleB);
}
}
@Test
public void testFeatureWithParentApplication() throws Exception {
testDynamicImport(FEATURE_B, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE, APPLICATION_D);
}
@Test
public void testFeatureWithParentComposite() throws Exception {
testDynamicImport(FEATURE_B, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE, COMPOSITE_D);
}
@Test
public void testFeatureWithParentFeature() throws Exception {
testDynamicImport(FEATURE_B, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE, FEATURE_D);
}
@Test
public void testNoProviders() throws Exception {
registerWeavingHook("b");
Subsystem applicationB = installSubsystemFromFile(APPLICATION_B);
try {
Bundle bundleA = getConstituentAsBundle(applicationB, BUNDLE_A, null, null);
bundleA.loadClass("a.A");
try {
bundleA.loadClass("b.B");
fail("Class should not have loaded");
}
catch (ClassNotFoundException e) {
// Okay.
}
testSharingPolicy(applicationB, "b", false);
}
finally {
uninstallSubsystemSilently(applicationB);
}
}
@Test
public void testWildcardEverything() throws Exception {
registerWeavingHook("b", "*");
Subsystem compositeB = installSubsystemFromFile(COMPOSITE_B);
try {
Bundle bundleB = compositeB.getBundleContext().installBundle(
BUNDLE_B,
new ByteArrayInputStream(createBundleBContent()));
try {
Subsystem applicationB = installSubsystemFromFile(compositeB, APPLICATION_B);
Subsystem featureB = installSubsystemFromFile(applicationB, FEATURE_B);
Subsystem applicationE = installSubsystemFromFile(featureB, APPLICATION_E);
testSharingPolicy(applicationE, "b", false);
testSharingPolicy(applicationE, "org.osgi.framework.Constants", false);
testSharingPolicy(applicationB, "b", false);
testSharingPolicy(applicationB, "org.osgi.framework.Constants", false);
testSharingPolicy(compositeB, "b", false);
testSharingPolicy(compositeB, "org.osgi.framework.Constants", false);
testSharingPolicy(getRootSubsystem(), "b", false);
testSharingPolicy(getRootSubsystem(), "org.osgi.framework.Constants", false);
testDynamicImport(applicationE, "b.B");
testDynamicImport(applicationE, "org.osgi.framework.Constants");
testDynamicImport(featureB, "b.B");
testDynamicImport(featureB, "org.osgi.framework.Constants");
testDynamicImport(applicationB, "b.B");
testDynamicImport(applicationB, "org.osgi.framework.Constants");
testDynamicImport(compositeB, "b.B");
testDynamicImport(compositeB, "org.osgi.framework.Constants");
testSharingPolicy(applicationE, "b", true);
testSharingPolicy(applicationE, "org.osgi.framework.Constants", true);
testSharingPolicy(applicationB, "b", true);
testSharingPolicy(applicationB, "org.osgi.framework.Constants", true);
testSharingPolicy(compositeB, "b", true);
testSharingPolicy(compositeB, "org.osgi.framework.Constants", true);
testSharingPolicy(getRootSubsystem(), "b", false);
testSharingPolicy(getRootSubsystem(), "org.osgi.framework.Constants", false);
uninstallSubsystemSilently(applicationE);
uninstallSubsystemSilently(featureB);
uninstallSubsystemSilently(applicationB);
}
finally {
uninstallSilently(bundleB);
}
}
finally {
uninstallSubsystemSilently(compositeB);
}
}
@Test
public void testWildcardEverythingInPackage() throws Exception {
registerWeavingHook("b.*");
Subsystem applicationA = installSubsystemFromFile(APPLICATION_A);
try {
Bundle bundleB = applicationA.getBundleContext().installBundle(
BUNDLE_B,
new ByteArrayInputStream(createBundleBContent()));
try {
Subsystem applicationB = getChild(applicationA, APPLICATION_B);
testSharingPolicy(applicationB, "b", false);
testSharingPolicy(applicationB, "b.a", false);
testSharingPolicy(applicationA, "b", false);
testSharingPolicy(applicationA, "b.a", false);
testSharingPolicy(getRootSubsystem(), "b", false);
testSharingPolicy(getRootSubsystem(), "b.a", false);
testDynamicImport(applicationB, "b.a.A");
testSharingPolicy(applicationB, "b", false);
testSharingPolicy(applicationB, "b.a", true);
testSharingPolicy(applicationA, "b", false);
testSharingPolicy(applicationA, "b.a", true);
testSharingPolicy(getRootSubsystem(), "b", false);
testSharingPolicy(getRootSubsystem(), "b.a", false);
}
finally {
uninstallSilently(bundleB);
}
}
finally {
uninstallSubsystemSilently(applicationA);
}
}
@Test
public void testWovenSubsystemContainsProvider() throws Exception {
registerWeavingHook("b");
Subsystem applicationE = installSubsystemFromFile(APPLICATION_E);
try {
assertConstituent(applicationE, BUNDLE_B);
testDynamicImport(applicationE, "b.B");
testSharingPolicy(applicationE, "b", false);
}
finally {
uninstallSubsystemSilently(applicationE);
}
}
@Test
public void testWovenSubsystemParentContainsProvider() throws Exception {
registerWeavingHook("b");
Subsystem compositeE = installSubsystemFromFile(COMPOSITE_E);
try {
assertNotConstituent(getRootSubsystem(), BUNDLE_B);
assertConstituent(compositeE, BUNDLE_B);
Subsystem applicationB = getChild(compositeE, APPLICATION_B);
assertNotConstituent(applicationB, BUNDLE_B);
testDynamicImport(applicationB, "b.B");
testSharingPolicy(compositeE, "b", false);
testSharingPolicy(applicationB, "b", true);
}
finally {
uninstallSubsystemSilently(compositeE);
}
}
@Test
public void testWovenSubsystemParentPolicyAllowsProvider() throws Exception {
registerWeavingHook("b");
Subsystem root = getRootSubsystem();
BundleContext context = root.getBundleContext();
Bundle bundleB = context.installBundle(BUNDLE_B, new ByteArrayInputStream(createBundleBContent()));
try {
Subsystem applicationB1 = installSubsystemFromFile(root, new File(APPLICATION_B), APPLICATION_B + "1");
try {
Subsystem compositeF = installSubsystemFromFile(applicationB1, COMPOSITE_F);
try {
assertPackageFiltersInParentConnection(compositeF, applicationB1, 2, 1);
Subsystem applicationB2 = installSubsystemFromFile(compositeF, new File(APPLICATION_B), APPLICATION_B + "2");
try {
testDynamicImport(applicationB2, "b.B");
testSharingPolicy(applicationB2, "b", true);
testSharingPolicy(compositeF, "b", true);
assertPackageFiltersInParentConnection(compositeF, applicationB1, 2, 1);
testSharingPolicy(applicationB1, "b", true);
testSharingPolicy(root, "b", false);
}
finally {
uninstallSubsystemSilently(applicationB2);
}
}
finally {
uninstallSubsystemSilently(compositeF);
}
}
finally {
uninstallSubsystemSilently(applicationB1);
}
}
finally {
uninstallSilently(bundleB);
}
}
private void assertPackageFiltersInParentConnection(Subsystem subsystem, Subsystem parent, int expectedEdges, int expectedFilters) {
Region parentRegion = getRegion(parent);
Region region = getRegion(subsystem);
Set<FilteredRegion> edges = region.getEdges();
assertEquals("Wrong number of edges", expectedEdges, edges.size());
for (FilteredRegion edge : region.getEdges()) {
if (!edge.getRegion().equals(parentRegion)) {
continue;
}
RegionFilter filter = edge.getFilter();
Map<String, Collection<String>> policy = filter.getSharingPolicy();
Collection<String> packages = policy.get(PackageNamespace.PACKAGE_NAMESPACE);
assertNotNull("Wrong number of packages", packages);
assertEquals("Wrong number of packages", expectedFilters, packages.size());
return;
}
fail("No connection to parent found");
}
private void createApplicationA() throws IOException {
createApplicationAManifest();
createSubsystem(APPLICATION_A, APPLICATION_B);
}
private void createApplicationAManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_A);
createManifest(APPLICATION_A + ".mf", attributes);
}
private void createApplicationB() throws IOException {
createApplicationBManifest();
createSubsystem(APPLICATION_B);
}
private void createApplicationBManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_B);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A);
createManifest(APPLICATION_B + ".mf", attributes);
}
private void createApplicationC() throws IOException {
createApplicationCManifest();
createSubsystem(APPLICATION_C, COMPOSITE_B);
}
private void createApplicationCManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_C);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, COMPOSITE_B + ";type=osgi.subsystem.composite");
createManifest(APPLICATION_C + ".mf", attributes);
}
private void createApplicationD() throws IOException {
createApplicationDManifest();
createSubsystem(APPLICATION_D, FEATURE_B);
}
private void createApplicationDManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_D);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, FEATURE_B + ";type=osgi.subsystem.feature");
createManifest(APPLICATION_D + ".mf", attributes);
}
private void createApplicationE() throws IOException {
createApplicationEManifest();
createSubsystem(APPLICATION_E);
}
private void createApplicationEManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_E);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A + ',' + BUNDLE_B);
createManifest(APPLICATION_E + ".mf", attributes);
}
private byte[] createBundleAContent() throws Exception {
InputStream is = TinyBundles
.bundle()
.add(getClass().getClassLoader().loadClass("a.A"), InnerClassStrategy.NONE)
.set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_A)
.build(TinyBundles.withBnd());
return createBundleContent(is);
}
private Resource createBundleAResource() throws Exception {
return new TestRepositoryContent.Builder()
.capability(
new TestCapability.Builder()
.namespace(IdentityNamespace.IDENTITY_NAMESPACE)
.attribute(IdentityNamespace.IDENTITY_NAMESPACE, BUNDLE_A)
.attribute(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)
.attribute(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion))
.content(createBundleAContent())
.build();
}
private byte[] createBundleBContent() throws Exception {
InputStream is = TinyBundles
.bundle()
.add(getClass().getClassLoader().loadClass("b.B"), InnerClassStrategy.NONE)
.add(getClass().getClassLoader().loadClass("b.a.A"), InnerClassStrategy.NONE)
.set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_B)
.set(Constants.EXPORT_PACKAGE, "b,b.a")
.build(TinyBundles.withBnd());
return createBundleContent(is);
}
private byte[] createBundleContent(InputStream is) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int length;
while ((length = is.read(bytes)) != -1) {
baos.write(bytes, 0, length);
}
is.close();
baos.close();
return baos.toByteArray();
}
private Resource createBundleBResource() throws Exception {
return new TestRepositoryContent.Builder()
.capability(
new TestCapability.Builder()
.namespace(IdentityNamespace.IDENTITY_NAMESPACE)
.attribute(IdentityNamespace.IDENTITY_NAMESPACE, BUNDLE_B)
.attribute(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)
.attribute(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion))
.capability(
new TestCapability.Builder()
.namespace(PackageNamespace.PACKAGE_NAMESPACE)
.attribute(PackageNamespace.PACKAGE_NAMESPACE, "b")
.attribute(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion))
.capability(
new TestCapability.Builder()
.namespace(PackageNamespace.PACKAGE_NAMESPACE)
.attribute(PackageNamespace.PACKAGE_NAMESPACE, "b.a")
.attribute(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion))
.content(createBundleBContent())
.build();
}
private void createCompositeA() throws IOException {
createCompositeAManifest();
createSubsystem(COMPOSITE_A, APPLICATION_B);
}
private void createCompositeAManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, COMPOSITE_A);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, APPLICATION_B +
";type=osgi.subsystem.application;version=\"[0,0]\"");
createManifest(COMPOSITE_A + ".mf", attributes);
}
private void createCompositeB() throws IOException {
createCompositeBManifest();
createSubsystem(COMPOSITE_B);
}
private void createCompositeBManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, COMPOSITE_B);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A + ";version=\"[0,0]\"");
createManifest(COMPOSITE_B + ".mf", attributes);
}
private void createCompositeC() throws IOException {
createCompositeCManifest();
createSubsystem(COMPOSITE_C, COMPOSITE_B);
}
private void createCompositeCManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, COMPOSITE_C);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, COMPOSITE_B + ";type=osgi.subsystem.composite;version=\"[0,0]\"");
createManifest(COMPOSITE_C + ".mf", attributes);
}
private void createCompositeD() throws IOException {
createCompositeDManifest();
createSubsystem(COMPOSITE_D, FEATURE_B);
}
private void createCompositeDManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, COMPOSITE_D);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, FEATURE_B + ";type=osgi.subsystem.feature;version=\"[0,0]\"");
createManifest(COMPOSITE_D + ".mf", attributes);
}
private void createCompositeE() throws IOException {
createCompositeEManifest();
createSubsystem(COMPOSITE_E, APPLICATION_B);
}
private void createCompositeEManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, COMPOSITE_E);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, APPLICATION_B +
";type=osgi.subsystem.application;version=\"[0,0]\"," +
BUNDLE_B + ";version=\"[0,0]\"");
attributes.put(Constants.EXPORT_PACKAGE, "b");
createManifest(COMPOSITE_E + ".mf", attributes);
}
private void createCompositeF() throws IOException {
createCompositeFManifest();
createSubsystem(COMPOSITE_F);
}
private void createCompositeFManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, COMPOSITE_F);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE);
attributes.put(Constants.IMPORT_PACKAGE, "b;resolution:=optional");
createManifest(COMPOSITE_F + ".mf", attributes);
}
private void createFeatureA() throws IOException {
createFeatureAManifest();
createSubsystem(FEATURE_A, APPLICATION_B);
}
private void createFeatureAManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, FEATURE_A);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
createManifest(FEATURE_A + ".mf", attributes);
}
private void createFeatureB() throws IOException {
createFeatureBManifest();
createSubsystem(FEATURE_B);
}
private void createFeatureBManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, FEATURE_B);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A);
createManifest(FEATURE_B + ".mf", attributes);
}
private void createFeatureC() throws IOException {
createFeatureCManifest();
createSubsystem(FEATURE_C, COMPOSITE_B);
}
private void createFeatureCManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, FEATURE_C);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
createManifest(FEATURE_C + ".mf", attributes);
}
private void createFeatureD() throws IOException {
createFeatureDManifest();
createSubsystem(FEATURE_D, FEATURE_B);
}
private void createFeatureDManifest() throws IOException {
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, FEATURE_D);
attributes.put(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
createManifest(FEATURE_D + ".mf", attributes);
}
private Repository createTestRepository() throws Exception {
return new TestRepository.Builder()
.resource(createBundleAResource())
.resource(createBundleBResource())
.build();
}
private void registerWeavingHook(final String...dynamicImport) {
serviceRegistrations.add(bundleContext.registerService(
WeavingHook.class,
new WeavingHook() {
@Override
public void weave(WovenClass wovenClass) {
Bundle bundle = wovenClass.getBundleWiring().getBundle();
String symbolicName = bundle.getSymbolicName();
if (BUNDLE_A.equals(symbolicName)) {
weavingHookCalled.set(true);
List<String> dynamicImports = wovenClass.getDynamicImports();
dynamicImports.addAll(Arrays.asList(dynamicImport));
}
}
},
null));
}
private void testDynamicImport(String child, String type, String parent) throws Exception {
testDynamicImport(child, type, parent, "org.osgi.framework");
}
private void testDynamicImport(String child, String type, String parent, String dynamicImport) throws Exception {
registerWeavingHook(dynamicImport);
Subsystem p = installSubsystemFromFile(parent == null ? child : parent);
try {
if (parent != null) {
assertChild(p, child, null, type);
final Subsystem s = getConstituentAsSubsystem(p, child, null, type);
testDynamicImport(s);
}
else {
testDynamicImport(p);
}
}
finally {
uninstallSubsystemSilently(p);
}
}
private void testDynamicImport(Subsystem subsystem) throws Exception {
testDynamicImport(subsystem, "org.osgi.framework.Constants");
}
private void testDynamicImport(Subsystem subsystem, String clazz) throws Exception {
assertConstituent(subsystem, BUNDLE_A);
Bundle bundleA = getConstituentAsBundle(subsystem, BUNDLE_A, null, null);
bundleA.loadClass("a.A");
assertTrue("Weaving hook not called", weavingHookCalled.get());
try {
bundleA.loadClass(clazz);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
fail("Dynamic import not visible");
}
}
private void testSharingPolicy(Subsystem subsystem, String dynamicImport, boolean allowed) {
Region region = getRegion(subsystem);
Set<FilteredRegion> filteredRegions = region.getEdges();
Map<String, Object> map = new HashMap<String, Object>();
map.put(PackageNamespace.PACKAGE_NAMESPACE, dynamicImport);
map.put(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion);
boolean wasAllowed = false;
for (FilteredRegion filteredRegion : filteredRegions) {
RegionFilter filter = filteredRegion.getFilter();
if (allowed) {
if (filter.isAllowed(PackageNamespace.PACKAGE_NAMESPACE, map)) {
wasAllowed = true;
break;
}
}
else {
assertFalse("Sharing policy should not have been updated",
filter.isAllowed(PackageNamespace.PACKAGE_NAMESPACE, map));
}
}
if (allowed && !wasAllowed) {
fail("Sharing policy should have been updated");
}
}
@Test
public void testConnectedNonSubsystemRegions() throws Exception {
registerWeavingHook("b");
Bundle bundleB = getRootSubsystem().getBundleContext().installBundle(
BUNDLE_B, new ByteArrayInputStream(createBundleBContent()));
uninstallableBundles.add(bundleB);
Subsystem applicationA = installSubsystemFromFile(APPLICATION_A);
uninstallableSubsystems.add(applicationA);
Subsystem applicationB = getChild(applicationA, APPLICATION_B);
uninstallSubsystem(applicationB);
removeConnectionWithParent(applicationA);
Region region = getRegion(applicationA);
RegionDigraph digraph = region.getRegionDigraph();
Region r1 = digraph.createRegion("R1");
deletableRegions.add(r1);
region.connectRegion(r1, digraph.createRegionFilterBuilder().allow("y", "(y=x)").build());
Region r2a = digraph.createRegion("R2A");
deletableRegions.add(r2a);
Bundle bundleB1 = r2a.installBundleAtLocation(BUNDLE_B + '1', new ByteArrayInputStream(createBundleBContent()));
uninstallableBundles.add(bundleB1);
Region r2b = digraph.createRegion("R2B");
deletableRegions.add(r2b);
r2b.connectRegion(r2a, digraph.createRegionFilterBuilder().allow("osgi.wiring.package", "(&(osgi.wiring.package=b)(version=0))").build());
region.connectRegion(r2b, digraph.createRegionFilterBuilder().allow("osgi.wiring.package", "(&(osgi.wiring.package=b)(version=0))").build());
applicationB = installSubsystemFromFile(applicationA, APPLICATION_B);
uninstallableSubsystems.add(applicationB);
try {
testDynamicImport(applicationB, "b.B");
}
catch (AssertionError e) {
fail("Dynamic import should have succeeded");
}
testSharingPolicy(applicationB, "b", true);
testSharingPolicy(applicationA, "b", true);
testSharingPolicy(getRootSubsystem(), "b", false);
}
}