You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by jw...@apache.org on 2013/03/07 20:28:17 UTC

svn commit: r1454035 - in /aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal: BasicSubsystem.java RegionUpdater.java

Author: jwross
Date: Thu Mar  7 19:28:17 2013
New Revision: 1454035

URL: http://svn.apache.org/r1454035
Log:
[ARIES-1021] Implementation of AriesSubsystem.addRequirements must not assume the region only has edges to the parent subsystem's region.

All possible edges are now retained.

Added:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java
Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java?rev=1454035&r1=1454034&r2=1454035&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java Thu Mar  7 19:28:17 2013
@@ -24,13 +24,11 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 
 import org.apache.aries.subsystem.AriesSubsystem;
 import org.apache.aries.subsystem.core.archive.AriesSubsystemParentsHeader;
@@ -42,17 +40,11 @@ import org.apache.aries.subsystem.core.a
 import org.apache.aries.util.filesystem.FileSystem;
 import org.apache.aries.util.filesystem.IDirectory;
 import org.apache.aries.util.io.IOUtils;
-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.eclipse.equinox.region.RegionFilterBuilder;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.Version;
 import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.namespace.service.ServiceNamespace;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
@@ -551,89 +543,15 @@ public class BasicSubsystem implements R
 		// The root subsystem has no requirements (there is no parent to import from).
 		if (isRoot())
 			throw new UnsupportedOperationException("The root subsystem does not accept additional requirements");
-		// Unscoped subsystems import everything.already.
+		// Unscoped subsystems import everything already.
 		if (!isScoped())
 			return;
-		for (int i = 0; i < 10; i++) {
-			try {
-				Region oldRegion = getRegion();
-				RegionDigraph currentDigraph = oldRegion.getRegionDigraph();
-				RegionDigraph copiedDigraph = currentDigraph.copy();
-				Region newRegion = copiedDigraph.getRegion(oldRegion.getName());
-				// Store the bundle ids for future reference.
-				Set<Long> bundleIds = newRegion.getBundleIds();
-				// Store the current connection info with parent for future reference.
-				RegionFilterBuilder parentFilter = copiedDigraph.createRegionFilterBuilder();
-				for (FilteredRegion filteredRegion : newRegion.getEdges()) {
-					Map<String, Collection<String>> sharingPolicy = filteredRegion.getFilter().getSharingPolicy();
-					for (Map.Entry<String, Collection<String>> entry : sharingPolicy.entrySet())
-						for (String filter : entry.getValue())
-							parentFilter.allow(entry.getKey(), filter);
-				}
-				// Add the additional requirements to the connection info with parent.
-				for (Requirement requirement : requirements) {
-					String namespace = requirement.getNamespace();
-					// The osgi.service namespace requires translation.
-					if (ServiceNamespace.SERVICE_NAMESPACE.equals(namespace))
-						namespace = RegionFilter.VISIBLE_SERVICE_NAMESPACE;
-					String filter = requirement.getDirectives().get(IdentityNamespace.REQUIREMENT_FILTER_DIRECTIVE);
-					// A null filter means import everything from that namespace.
-					if (filter == null)
-						parentFilter.allowAll(namespace);
-					else
-						parentFilter.allow(namespace, filter);
-				}
-				// Store the connection info with children for future reference.
-				Map<String, RegionFilterBuilder> childFilters = new HashMap<String, RegionFilterBuilder>();
-				for (Subsystem child : getChildren()) {
-					if (!((BasicSubsystem)child).isScoped())
-						continue;
-					Region childRegion = ((BasicSubsystem)child).getRegion();
-					RegionFilterBuilder childBuilder = copiedDigraph.createRegionFilterBuilder();
-					for (FilteredRegion filteredRegion : childRegion.getEdges()) {
-						Map<String, Collection<String>> sharingPolicy = filteredRegion.getFilter().getSharingPolicy();
-						for (Map.Entry<String, Collection<String>> entry : sharingPolicy.entrySet())
-							for (String filter : entry.getValue())
-								childBuilder.allow(entry.getKey(), filter);
-					}
-					childFilters.put(childRegion.getName(), childBuilder);
-				}
-				// Remove the region so the parent connection can be updated.
-				copiedDigraph.removeRegion(newRegion);
-				// Recreate the region.
-				newRegion = copiedDigraph.createRegion(newRegion.getName());
-				// Copy the bundle ids.
-				for (Long bundleId : bundleIds)
-					newRegion.addBundle(bundleId);
-				// Reconnect to the parent.
-				copiedDigraph.connect(newRegion, parentFilter.build(), copiedDigraph.getRegion(((BasicSubsystem)getParents().iterator().next()).getRegion().getName()));
-				// Reconnect the children.
-				for (Map.Entry<String, RegionFilterBuilder> entry : childFilters.entrySet())
-					copiedDigraph.connect(copiedDigraph.getRegion(entry.getKey()), entry.getValue().build(), newRegion);
-				// Replace the current digraph.
-				try {
-					currentDigraph.replace(copiedDigraph);
-				}
-				catch (BundleException e) {
-					// Something modified digraph since the copy was made.
-					if (i < 10)
-						// There are more attempts to make.
-						continue;
-					// Number of attempts has been exhausted.
-					throw e;
-				}
-				// Success! No need to continue looping.
-				break;
-			}
-			// If an exception occurs for any reason other than a replacement
-			// failure, or replacement failed with no more attempts left, break 
-			// out of the loop and throw it.
-			catch (SubsystemException e) {
-				throw e;
-			}
-			catch (Exception e) {
-				throw new SubsystemException(e);
-			}
+		RegionUpdater updater = new RegionUpdater(getRegion(), ((BasicSubsystem)getParents().iterator().next()).getRegion());
+		try {
+			updater.addRequirements(requirements);
+		}
+		catch (Exception e) {
+			throw new SubsystemException(e);
 		}
 	}
 

Added: 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=1454035&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java Thu Mar  7 19:28:17 2013
@@ -0,0 +1,139 @@
+package org.apache.aries.subsystem.core.internal;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+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.eclipse.equinox.region.RegionFilterBuilder;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.namespace.service.ServiceNamespace;
+import org.osgi.resource.Requirement;
+
+public class RegionUpdater {
+	public static final int MAX_ATTEMPTS_DEFAULT = 10;
+	
+	private final RegionDigraph digraph;
+	private final Region head;
+	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");
+		this.tail = tail;
+		this.head = head;
+		digraph = tail.getRegionDigraph();
+	}
+	
+	public void addRequirements(Collection<? extends Requirement> requirements) throws BundleException, InvalidSyntaxException {
+		for (int i = 0; i < MAX_ATTEMPTS_DEFAULT; i++) {
+			RegionDigraph copy = copyDigraph();
+			Region tail = copyTail(copy);
+			Region head = copyHead(copy);
+			Set<Long> bundleIds = copyBundleIds(tail);
+			Map<String, RegionFilterBuilder> heads = copyHeadRegions(tail, copy);
+			Map<String, RegionFilterBuilder> tails = copyTailRegions(tail, copy);
+			copy.removeRegion(tail);
+			tail = copy.createRegion(tail.getName());
+			addBundleIds(bundleIds, tail);
+			addRequirements(requirements, heads.get(head.getName()));
+			addHeadRegions(heads, tail, copy);
+			addTailRegions(tails, tail, copy);
+			// Replace the current digraph.
+			try {
+				digraph.replace(copy);
+			}
+			catch (BundleException e) {
+				// Something modified digraph since the copy was made.
+				if (i < MAX_ATTEMPTS_DEFAULT)
+					// There are more attempts to make.
+					continue;
+				// Number of attempts has been exhausted.
+				throw e;
+			}
+			// Success! No need to continue looping.
+			break;
+		}
+	}
+	
+	private void addBundleIds(Set<Long> ids, Region region) throws BundleException {
+		for (Long id : ids)
+			region.addBundle(id);
+	}
+	
+	private void addHeadRegions(Map<String, RegionFilterBuilder> heads, Region tail, RegionDigraph digraph) throws BundleException {
+		for (Map.Entry<String, RegionFilterBuilder> entry : heads.entrySet())
+			tail.connectRegion(digraph.getRegion(entry.getKey()), entry.getValue().build());
+	}
+	
+	private void addTailRegions(Map<String, RegionFilterBuilder> tails, Region head, RegionDigraph digraph) throws BundleException {
+		for (Map.Entry<String, RegionFilterBuilder> entry : tails.entrySet())
+			digraph.getRegion(entry.getKey()).connectRegion(head, entry.getValue().build());
+	}
+	
+	private void addRequirements(Collection<? extends Requirement> requirements, RegionFilterBuilder builder) throws InvalidSyntaxException {
+		for (Requirement requirement : requirements) {
+			String namespace = requirement.getNamespace();
+			// The osgi.service namespace requires translation.
+			if (ServiceNamespace.SERVICE_NAMESPACE.equals(namespace))
+				namespace = RegionFilter.VISIBLE_SERVICE_NAMESPACE;
+			String filter = requirement.getDirectives().get(IdentityNamespace.REQUIREMENT_FILTER_DIRECTIVE);
+			// A null filter means import everything from that namespace.
+			if (filter == null)
+				builder.allowAll(namespace);
+			else
+				builder.allow(namespace, filter);
+		}
+	}
+	
+	private Set<Long> copyBundleIds(Region region) {
+		return region.getBundleIds();
+	}
+	
+	private RegionDigraph copyDigraph() throws BundleException {
+		return digraph.copy();
+	}
+	
+	private Region copyHead(RegionDigraph digraph) {
+		return digraph.getRegion(head.getName());
+	}
+	
+	private Map<String, RegionFilterBuilder> copyHeadRegions(Region tail, RegionDigraph digraph) throws InvalidSyntaxException {
+		Map<String, RegionFilterBuilder> result = new HashMap<String, RegionFilterBuilder>();
+		for (FilteredRegion edge : tail.getEdges())
+			result.put(edge.getRegion().getName(), createRegionFilterBuilder(edge.getFilter().getSharingPolicy(), digraph));
+		return result;
+	}
+	
+	private Region copyTail(RegionDigraph digraph) {
+		return digraph.getRegion(tail.getName());
+	}
+	
+	private Map<String, RegionFilterBuilder> copyTailRegions(Region tail, RegionDigraph digraph) throws InvalidSyntaxException {
+		Map<String, RegionFilterBuilder> result = new HashMap<String, RegionFilterBuilder>();
+		for (Region head : digraph.getRegions()) {
+			if (head.equals(tail))
+				continue;
+			for (FilteredRegion edge : head.getEdges())
+				if (edge.getRegion().equals(tail))
+					result.put(head.getName(), createRegionFilterBuilder(edge.getFilter().getSharingPolicy(), digraph));
+		}
+		return result;
+	}
+	
+	private RegionFilterBuilder createRegionFilterBuilder(Map<String, Collection<String>> sharingPolicy, RegionDigraph digraph) throws InvalidSyntaxException {
+		RegionFilterBuilder result = digraph.createRegionFilterBuilder();
+		for (Map.Entry<String, Collection<String>> entry : sharingPolicy.entrySet())
+			for (String filter : entry.getValue())
+				result.allow(entry.getKey(), filter);
+		return result;
+	}
+}