aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jwr...@apache.org
Subject svn commit: r1709471 - in /aries/trunk/subsystem: subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ subsystem-itests/src/test/classes/b/a/ subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/ subsystem-itests/src/test/...
Date Mon, 19 Oct 2015 19:40:20 GMT
Author: jwross
Date: Mon Oct 19 19:40:20 2015
New Revision: 1709471

URL: http://svn.apache.org/viewvc?rev=1709471&view=rev
Log:
ARIES-1435 Sharing policy updates for dynamic imports, if necessary, should proceed up the subsystem region tree.

Sharing policy updates will proceed up the region tree, starting with the region of the subsystem containing the woven bundle, until either a region is found in which the dynamic import
is completely satisfied or the root region is reached. To be "completely satisfied" means (1) the dynamic import does not contain a wildcard and (2) either (a) the region contains a
bundle providing a matching capability or (b) the region has an edge with a filter that allows a matching capability.

Add test.

Fix issue in RegionNameTest where content was being created after the containing subsystem causing intermittent failures.

Factor out common functionality of disconnecting a child region from its parent in the tests.

Added:
    aries/trunk/subsystem/subsystem-itests/src/test/classes/b/a/
    aries/trunk/subsystem/subsystem-itests/src/test/classes/b/a/A.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1435Test.java
Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/WovenClassListener.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AriesSubsystemTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RegionNameTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1429Test.java

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java?rev=1709471&r1=1709470&r2=1709471&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java Mon Oct 19 19:40:20 2015
@@ -37,10 +37,8 @@ public class RegionUpdater {
 	private final Region tail;
 	
 	public RegionUpdater(Region tail, Region head) {
-		if (tail == null)
-			throw new NullPointerException("Missing required parameter: tail");
 		if (head == null)
-			throw new NullPointerException("Missing required parameter: head");
+			throw new NullPointerException();
 		this.tail = tail;
 		this.head = head;
 		digraph = tail.getRegionDigraph();

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/WovenClassListener.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/WovenClassListener.java?rev=1709471&r1=1709470&r2=1709471&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/WovenClassListener.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/WovenClassListener.java Mon Oct 19 19:40:20 2015
@@ -19,26 +19,62 @@
 package org.apache.aries.subsystem.core.internal;
 
 import java.security.AccessController;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
 import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.aries.subsystem.core.archive.DynamicImportPackageHeader;
 import org.apache.aries.subsystem.core.archive.DynamicImportPackageRequirement;
 import org.apache.aries.subsystem.core.internal.BundleResourceInstaller.BundleConstituent;
 import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraphVisitor;
+import org.eclipse.equinox.region.RegionFilter;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.hooks.weaving.WovenClass;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWiring;
 import org.osgi.framework.wiring.FrameworkWiring;
-import org.osgi.resource.Requirement;
 import org.osgi.service.subsystem.Subsystem;
 import org.osgi.service.subsystem.SubsystemException;
 
 public class WovenClassListener implements org.osgi.framework.hooks.weaving.WovenClassListener {
+	private static class RegionUpdaterInfo {
+		private final Region head;
+		private final Collection<DynamicImportPackageRequirement> requirements;
+		private final Region tail;
+		
+		public RegionUpdaterInfo(Region tail, Region head) {
+			this.tail = tail;
+			this.head = head;
+			requirements = new ArrayList<DynamicImportPackageRequirement>();
+		}
+		
+		public Region head() {
+			return head;
+		}
+		
+		public void requirement(DynamicImportPackageRequirement requirement) {
+			requirements.add(requirement);
+		}
+		
+		public Collection<DynamicImportPackageRequirement> requirements() {
+			return requirements;
+		}
+		
+		public Region tail() {
+			return tail;
+		}
+	}
+	
 	private final BundleContext context;
 	private final Subsystems subsystems;
 	
@@ -47,10 +83,6 @@ public class WovenClassListener implemen
 		this.subsystems = subsystems;
 	}
 	
-	/*
-	 * This does not update sharing policies up the chain any further than the
-	 * parent. Does not account for providers in child subsystems.
-	 */
 	@Override
 	public void modified(WovenClass wovenClass) {
 		if (wovenClass.getState() != WovenClass.TRANSFORMED) {
@@ -64,71 +96,196 @@ public class WovenClassListener implemen
 			// Nothing to do if there are no dynamic imports.
 			return;
 		}
-		// Add the dynamic imports to the sharing policy of the scoped subsystem 
-		// that contains the bundle whose class was woven as a constituent.
-		Bundle wovenBundle = wovenClass.getBundleWiring().getBundle();
-		BundleRevision wovenRevision = wovenBundle.adapt(BundleRevision.class);
-		BasicSubsystem subsystem = subsystems.getSubsystemsByConstituent(new BundleConstituent(null, wovenRevision)).iterator().next();
+		BundleWiring wiring = wovenClass.getBundleWiring();
+		Bundle bundle = wiring.getBundle();
+		BundleRevision revision = bundle.adapt(BundleRevision.class);
+		BundleConstituent constituent = new BundleConstituent(null, revision);
+		Collection<BasicSubsystem> basicSubsystems = subsystems.getSubsystemsByConstituent(constituent);
+		BasicSubsystem subsystem = basicSubsystems.iterator().next();
+		// Find the scoped subsystem in the region.
+		subsystem = scopedSubsystem(subsystem);
 		if (subsystem.getSubsystemId() == 0) {
 			// The root subsystem needs no sharing policy.
 			return;
 		}
 		if (EnumSet.of(Subsystem.State.INSTALLING, Subsystem.State.INSTALLED).contains(subsystem.getState())) {
-			// The subsystem must be resolved before adding dynamic package
-			// imports to the sharing policy in order to minimize unpredictable
-			// wirings.
+			// The scoped subsystem must be resolved before adding dynamic 
+			// package imports to the sharing policy in order to minimize 
+			// unpredictable wirings. Resolving the scoped subsystem will also
+			// resolve all of the unscoped subsystems in the region.
 			AccessController.doPrivileged(new StartAction(subsystem, subsystem, subsystem, true));
 		}
-		// Determine the requirements that must be added to the sharing policy.
-		Collection<Requirement> requirements = new ArrayList<Requirement>();
+		Bundle systemBundle = context.getBundle(org.osgi.framework.Constants.SYSTEM_BUNDLE_LOCATION);
+		FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class);
+		// The following map tracks all of the necessary updates as each dynamic
+		// import is processed. The key is the tail region of the connection 
+		// whose filter needs updating.
+		Map<Region, RegionUpdaterInfo> updates = new HashMap<Region, RegionUpdaterInfo>();
 		for (String dynamicImport : dynamicImports) {
+			// For each dynamic import, collect the necessary update information.
 			DynamicImportPackageHeader header = new DynamicImportPackageHeader(dynamicImport);
-			for (DynamicImportPackageRequirement requirement : header.toRequirements(wovenRevision)) {
-				String pkg = requirement.getPackageName();
-				if (pkg.endsWith(".*")) {
-					// Dynamic imports with wildcards must always be added.
-					requirements.add(requirement);
-				}
-				else {
-					// Absolute dynamic imports are added to the sharing policy
-					// only if they are not satisfied within the subsystem.
-					FrameworkWiring fw = context.getBundle(org.osgi.framework.Constants.SYSTEM_BUNDLE_LOCATION).adapt(FrameworkWiring.class);
-					Collection<BundleCapability> providers = fw.findProviders(requirement);
-					boolean found = false;
-					for (BundleCapability provider : providers) {
-						BundleRevision br = provider.getResource();
-						if (subsystem.getConstituents().contains(new BundleConstituent(null, br))) {
-							// We found a provider that's a constituent of the subsystem.
-							found = true;
-							break;
-						}
-					}
-					if (!found) {
-						requirements.add(requirement);
+			List<DynamicImportPackageRequirement> requirements = header.toRequirements(revision);
+			for (DynamicImportPackageRequirement requirement : requirements) {
+				Collection<BundleCapability> providers = frameworkWiring.findProviders(requirement);
+				if (providers.isEmpty()) {
+					// If nothing provides a capability matching the dynamic
+					// import, no updates are made.
+					continue;
+				}
+				addSharingPolicyUpdates(requirement, subsystem, providers, updates);
+			}
+		}
+		// Now update each sharing policy only once.
+		for (RegionUpdaterInfo update : updates.values()) {
+			RegionUpdater updater = new RegionUpdater(update.tail(), update.head());
+			try {
+				updater.addRequirements(update.requirements());
+			}
+			catch (IllegalStateException e) {
+				// Something outside of the subsystems implementation has
+				// deleted the edge between the parent and child subsystems.
+				// Assume the dynamic import sharing policy is being handled
+				// elsewhere. See ARIES-1429.
+			} 
+			catch (Exception e) {
+				throw new SubsystemException(e);
+			} 
+		}
+	}
+	
+	private void addSharingPolicyUpdates(
+			final DynamicImportPackageRequirement requirement, 
+			final BasicSubsystem scopedSubsystem,
+			final Collection<BundleCapability> providers,
+			Map<Region, RegionUpdaterInfo> updates) {
+		
+		final List<BasicSubsystem> subsystems = new ArrayList<BasicSubsystem>();
+		final Map<Region, BasicSubsystem> regionToSubsystem = new HashMap<Region, BasicSubsystem>();
+		regionToSubsystem(scopedSubsystem, regionToSubsystem);
+		scopedSubsystem.getRegion().visitSubgraph(new RegionDigraphVisitor() {
+			private final AtomicBoolean abort = new AtomicBoolean();
+			private final Deque<BasicSubsystem> deque = new ArrayDeque<BasicSubsystem>();
+			
+			@Override
+			public void postEdgeTraverse(RegionFilter filter) {
+				if (	// The queue will be empty if the necessary sharing 
+						// policy updates have already been detected.
+						deque.isEmpty() || 
+						// This is an edge whose head region was owned by a
+						// subsystem that was not a parent of the last processed
+						// subsystem.
+						abort.getAndSet(false)) {
+					// Do nothing.
+					return;
+				}
+				// Add the subsystem to the list indicating a sharing policy
+				// update is required.
+				subsystems.add(deque.pop());
+			}
+
+			@Override
+			public boolean preEdgeTraverse(RegionFilter filter) {
+				if (deque.isEmpty()) {
+					// The queue will be empty if the necessary sharing policy
+					// updates have already been detected.
+					// Do not visit the head region of this filter connection.
+					return false;
+				}
+				String dynamicImport = requirement.getPackageName();
+				if (!"*".equals(dynamicImport) 
+						&& !dynamicImport.endsWith(".*") 
+						&& filter.isAllowed(providers.iterator().next())) {
+					// The dynamic import does not contain a wildcard and the
+					// sharing policy already allows the import.
+					// Do not visit the head region of this filter connection.
+					return false;
+				}
+				// Visit the head region of this filter connection
+				return true;
+			}
+
+			@Override
+			public boolean visit(Region region) {
+				BasicSubsystem subsystem = regionToSubsystem.get(region);
+				if (subsystem == null) {
+					// Neither the subsystem whose subgraph is being visited nor
+					// any ancestor in the subsystem tree owns this region.
+					return false;
+				}
+				if (	// The deque will be empty if this is first region visited.
+						!deque.isEmpty() && 
+						// This region is not owned by the scoped subsystem in
+						// the parent region of the last processed subsystem. 
+						// We want to traverse up the tree.
+						!scopedParent(deque.getFirst()).equals(subsystem)) {
+					// Indicate to postEdgeTraverse that it should not add a
+					// subsystem to the list.
+					abort.set(true);
+					// Do not traverse the edges of this region.
+					return false;
+				}
+				// Let postEdgeTraverse see the currently processing subsystem.
+				deque.push(subsystem);
+				for (BundleCapability provider : providers) {
+					BundleRevision br = provider.getResource();
+					if (region.contains(br.getBundle()) && !requirement.getPackageName().contains("*")) {
+						// The subsystem contains the provider so there is no
+						// need to update it's sharing policy. It must be added
+						// to the list, however, to serve as a head.
+						subsystems.add(deque.pop());
+						// Do not traverse the edges of this region.
+						return false;
 					}
 				}
+				if (region.getEdges().isEmpty()) {
+					// We want to traverse the edges but it has none. This means
+					// we will miss a call to postEdgeTraverse resulting in a
+					// needed subsystem not being added. Add it here.
+					subsystems.add(deque.pop());
+				}
+				// Traverse the edges of this region.
+				return true;
+			}
+		});
+		// The reversal is necessary because the postEdgeTraverse calls in the
+		// visitor act as a LIFO queue. We want the order to be tail, head/tail,
+		// head/tail, ..., head. In other words, index i is the tail and index
+		// i + 1 is the head.
+		Collections.reverse(subsystems);
+		for (int i = 0; i < subsystems.size()-1; i++) {
+			Region tail = subsystems.get(i).getRegion();
+			Region head = subsystems.get(i+1).getRegion();
+			RegionUpdaterInfo info = updates.get(tail);
+			if (info == null) {
+				info = new RegionUpdaterInfo(tail, head);
+				updates.put(tail, info);
 			}
+			info.requirement(requirement);
 		}
-		if (requirements.isEmpty()) {
-			// No wildcards and all dynamic imports were satisfied within the
-			// subsystem.
+	}
+	
+	private void regionToSubsystem(BasicSubsystem subsystem, Map<Region, BasicSubsystem> map) {
+		map.put(subsystem.getRegion(), subsystem);
+		subsystem = scopedParent(subsystem);
+		if (subsystem == null) {
 			return;
 		}
-		// Now update the sharing policy with the necessary requirements.
-		Region from = subsystem.getRegion();
-		Region to = ((BasicSubsystem)subsystem.getParents().iterator().next()).getRegion();
-		RegionUpdater updater = new RegionUpdater(from, to);
-		try {
-			updater.addRequirements(requirements);
-		}
-		catch (IllegalStateException e) {
-			// Something outside of the subsystems implementation has
-			// deleted the edge between the parent and child subsystems.
-			// Assume the dynamic import sharing policy is being handled
-			// elsewhere. See ARIES-1429.
+		regionToSubsystem(subsystem, map);
+	}
+	
+	private BasicSubsystem scopedParent(BasicSubsystem subsystem) {
+		Collection<Subsystem> parents = subsystem.getParents();
+		if (parents.isEmpty()) {
+			return null;
 		}
-		catch (Exception e) {
-			throw new SubsystemException(e);
+		subsystem = (BasicSubsystem)parents.iterator().next();
+		return scopedSubsystem(subsystem);
+	}
+	
+	private BasicSubsystem scopedSubsystem(BasicSubsystem subsystem) {
+		while (!subsystem.isScoped()) {
+			subsystem = (BasicSubsystem)subsystem.getParents().iterator().next();
 		}
+		return subsystem;
 	}
 }

Added: aries/trunk/subsystem/subsystem-itests/src/test/classes/b/a/A.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/classes/b/a/A.java?rev=1709471&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/classes/b/a/A.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/classes/b/a/A.java Mon Oct 19 19:40:20 2015
@@ -0,0 +1,5 @@
+package b.a;
+
+public class A {
+
+}

Modified: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AriesSubsystemTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AriesSubsystemTest.java?rev=1709471&r1=1709470&r2=1709471&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AriesSubsystemTest.java (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AriesSubsystemTest.java Mon Oct 19 19:40:20 2015
@@ -126,51 +126,56 @@ public class AriesSubsystemTest extends
 	@Test
 	public void testAddRequirementsKeepsEdgesOtherThanParentChild() throws Exception {
 		AriesSubsystem compositeA = (AriesSubsystem)installSubsystemFromFile(COMPOSITE_A);
-		AriesSubsystem applicationB = (AriesSubsystem)getConstituentAsSubsystem(compositeA, APPLICATION_B, null, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION);
-		Region bRegion = getRegion(applicationB);
-		// One edge to parent for import package. One edge to root for subsystem
-		// service.
-		assertEquals("Wrong number of edges", 2, bRegion.getEdges().size());
-		Requirement requirement = new BasicRequirement.Builder()
-				.namespace(PackageNamespace.PACKAGE_NAMESPACE)
-				.directive(
-						PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, 
-						"(osgi.wiring.package=org.osgi.framework)")
-				.resource(EasyMock.createMock(Resource.class))
-				.build();
-		applicationB.addRequirements(Collections.singleton(requirement));
-		bRegion = getRegion(applicationB);
-		// Still one edge to parent for import package. One edge to root for 
-		// subsystem service.
-		assertEquals("Wrong number of edges", 2, bRegion.getEdges().size());
-		Region rootRegion = getRegion(getRootSubsystem());
-		// The root region won't be the tail region for any connection unless
-		// manually added.
-		assertEquals("Wrong number of edges", 0, rootRegion.getEdges().size());
-		// Manually add a connection from root to application B.
-		rootRegion.connectRegion(
-				bRegion, 
-				rootRegion.getRegionDigraph().createRegionFilterBuilder().allow(
-						"com.foo", 
-						"(bar=b)").build());
-		// The root region should now have an edge.
-		assertEquals("Wrong number of edges", 1, rootRegion.getEdges().size());
-		// Add another requirement to force a copy.
-		requirement = new BasicRequirement.Builder()
-				.namespace(PackageNamespace.PACKAGE_NAMESPACE)
-				.directive(
-						PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, 
-						"(osgi.wiring.package=org.osgi.framework.wiring)")
-				.resource(EasyMock.createMock(Resource.class))
-				.build();
-		applicationB.addRequirements(Collections.singleton(requirement));
-		rootRegion = getRegion(getRootSubsystem());
-		// The root region should still have its edge.
-		assertEquals("Wrong number of edges", 1, rootRegion.getEdges().size());
-		bRegion = getRegion(applicationB);
-		// Still one edge to parent for import package. One edge to root for 
-		// subsystem service.
-		assertEquals("Wrong number of edges", 2, bRegion.getEdges().size());
+		try {
+			AriesSubsystem applicationB = (AriesSubsystem)getConstituentAsSubsystem(compositeA, APPLICATION_B, null, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION);
+			Region bRegion = getRegion(applicationB);
+			// One edge to parent for import package. One edge to root for subsystem
+			// service.
+			assertEquals("Wrong number of edges", 2, bRegion.getEdges().size());
+			Requirement requirement = new BasicRequirement.Builder()
+					.namespace(PackageNamespace.PACKAGE_NAMESPACE)
+					.directive(
+							PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, 
+							"(osgi.wiring.package=org.osgi.framework)")
+					.resource(EasyMock.createMock(Resource.class))
+					.build();
+			applicationB.addRequirements(Collections.singleton(requirement));
+			bRegion = getRegion(applicationB);
+			// Still one edge to parent for import package. One edge to root for 
+			// subsystem service.
+			assertEquals("Wrong number of edges", 2, bRegion.getEdges().size());
+			Region rootRegion = getRegion(getRootSubsystem());
+			// The root region won't be the tail region for any connection unless
+			// manually added.
+			assertEquals("Wrong number of edges", 0, rootRegion.getEdges().size());
+			// Manually add a connection from root to application B.
+			rootRegion.connectRegion(
+					bRegion, 
+					rootRegion.getRegionDigraph().createRegionFilterBuilder().allow(
+							"com.foo", 
+							"(bar=b)").build());
+			// The root region should now have an edge.
+			assertEquals("Wrong number of edges", 1, rootRegion.getEdges().size());
+			// Add another requirement to force a copy.
+			requirement = new BasicRequirement.Builder()
+					.namespace(PackageNamespace.PACKAGE_NAMESPACE)
+					.directive(
+							PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, 
+							"(osgi.wiring.package=org.osgi.framework.wiring)")
+					.resource(EasyMock.createMock(Resource.class))
+					.build();
+			applicationB.addRequirements(Collections.singleton(requirement));
+			rootRegion = getRegion(getRootSubsystem());
+			// The root region should still have its edge.
+			assertEquals("Wrong number of edges", 1, rootRegion.getEdges().size());
+			bRegion = getRegion(applicationB);
+			// Still one edge to parent for import package. One edge to root for 
+			// subsystem service.
+			assertEquals("Wrong number of edges", 2, bRegion.getEdges().size());
+		}
+		finally {
+			uninstallSubsystemSilently(compositeA);
+		}
 	}
 	
 	/*

Modified: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RegionNameTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RegionNameTest.java?rev=1709471&r1=1709470&r2=1709471&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RegionNameTest.java (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RegionNameTest.java Mon Oct 19 19:40:20 2015
@@ -76,9 +76,9 @@ public class RegionNameTest extends Subs
 	public void createTestFiles() throws Exception {
 		if (createdTestFiles)
 			return;
+		createFeatureA();
 		createApplicationA();
 		createCompositeA();
-		createFeatureA();
 		createdTestFiles = true;
 	}
 	

Modified: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java?rev=1709471&r1=1709470&r2=1709471&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java Mon Oct 19 19:40:20 2015
@@ -42,6 +42,7 @@ import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -848,6 +849,20 @@ public abstract class SubsystemTest exte
 		}
 		registerRepositoryService(resources);
 	}
+	
+	protected void removeConnectionWithParent(Subsystem subsystem) throws BundleException {
+		Region tail = getRegion(subsystem);
+		RegionDigraph digraph = tail.getRegionDigraph();
+		RegionDigraph copy = digraph.copy();
+		Region tailCopy = copy.getRegion(tail.getName());
+		Set<Long> ids = tail.getBundleIds();
+		copy.removeRegion(tailCopy);
+		tailCopy= copy.createRegion(tailCopy.getName());
+		for (long id : ids) {
+			tailCopy.addBundle(id);
+		}
+		digraph.replace(copy);
+	}
 
 	protected void restartSubsystemsImplBundle() throws BundleException {
 		Bundle b = getSubsystemCoreBundle();

Modified: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1429Test.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1429Test.java?rev=1709471&r1=1709470&r2=1709471&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1429Test.java (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1429Test.java Mon Oct 19 19:40:20 2015
@@ -28,26 +28,21 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.aries.subsystem.AriesSubsystem;
 import org.apache.aries.subsystem.itests.SubsystemTest;
 import org.apache.aries.subsystem.itests.util.TestRequirement;
-import org.eclipse.equinox.region.Region;
-import org.eclipse.equinox.region.RegionDigraph;
 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.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.FrameworkEvent;
 import org.osgi.framework.FrameworkListener;
-import org.osgi.framework.ServiceReference;
 import org.osgi.framework.hooks.weaving.WeavingHook;
 import org.osgi.framework.hooks.weaving.WovenClass;
 import org.osgi.framework.namespace.PackageNamespace;
@@ -143,19 +138,6 @@ public class Aries1429Test extends Subsy
     		uninstallSubsystemSilently(applicationA);
     	}
     }
-	
-	private void removeConnectionWithParent(Subsystem subsystem) throws BundleException {
-		Region tail = getRegion(subsystem);
-		RegionDigraph copy = digraph.copy();
-		Region tailCopy = copy.getRegion(tail.getName());
-		Set<Long> ids = tail.getBundleIds();
-		copy.removeRegion(tailCopy);
-		tailCopy= copy.createRegion(tailCopy.getName());
-		for (long id : ids) {
-			tailCopy.addBundle(id);
-		}
-		digraph.replace(copy);
-	}
     
     @Test
     public void testMissingParentChildEdgeNotTolerated() throws Exception {
@@ -181,19 +163,4 @@ public class Aries1429Test extends Subsy
     		uninstallSubsystemSilently(applicationA);
     	}
     }
-    
-    private RegionDigraph digraph;
-    private ServiceReference<RegionDigraph> reference;
-    
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        reference = bundleContext.getServiceReference(RegionDigraph.class);
-        digraph = bundleContext.getService(reference);
-    }
-    
-    @Override
-    public void tearDown() throws Exception {
-    	bundleContext.ungetService(reference);
-    }
 }

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1435Test.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1435Test.java?rev=1709471&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1435Test.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1435Test.java Mon Oct 19 19:40:20 2015
@@ -0,0 +1,711 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+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.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.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 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();
+		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 {
+			bundleB.uninstall();
+		}
+	}
+	
+	@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 {
+				bundleB.uninstall();
+			}
+		}
+		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 {
+				bundleB.uninstall();
+			}
+		}
+		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);
+		}
+	}
+	
+	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 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");
+		}
+	}
+}



Mime
View raw message