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 2012/02/18 00:17:51 UTC

svn commit: r1245802 - in /aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal: AriesSubsystem.java SubsystemGraph.java SubsystemServiceRegistrar.java

Author: jwross
Date: Fri Feb 17 23:17:51 2012
New Revision: 1245802

URL: http://svn.apache.org/viewvc?rev=1245802&view=rev
Log:
ARIES-825: Update subsystems to latest Subsystem, Resolver, and Repository APIs.

(1) now fails install if a cycle is detected in the subsystem graph
(2) added INSTALL_FAILED to list of uninstall states that simply return

Added:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemGraph.java
Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AriesSubsystem.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemServiceRegistrar.java

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AriesSubsystem.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AriesSubsystem.java?rev=1245802&r1=1245801&r2=1245802&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AriesSubsystem.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AriesSubsystem.java Fri Feb 17 23:17:51 2012
@@ -206,14 +206,13 @@ public class AriesSubsystem implements S
 	}
 	
 	private final SubsystemArchive archive;
-	private final Set<AriesSubsystem> children = Collections.synchronizedSet(new HashSet<AriesSubsystem>());
 	private final Set<Resource> constituents = Collections.synchronizedSet(new HashSet<Resource>());
 	private final File directory;
 	private final SubsystemEnvironment environment;
 	private final long id;
 	private final String location;
-	private final Set<AriesSubsystem> parents = Collections.synchronizedSet(new HashSet<AriesSubsystem>());
 	private final Region region;
+	private final SubsystemGraph subsystemGraph;
 	
 	private boolean autostart;
 	private Subsystem.State state = State.INSTALLING;
@@ -252,6 +251,8 @@ public class AriesSubsystem implements S
 			// on any persisted resources.
 			subsystemManifest = new SubsystemManifest(getSymbolicName(), getVersion(), archive.getResources());
 		environment = new SubsystemEnvironment(this);
+		// The root subsystem establishes the subsystem graph;
+		subsystemGraph = new SubsystemGraph(this);
 		archive.setDeploymentManifest(new DeploymentManifest(
 				deploymentManifest, 
 				subsystemManifest, 
@@ -295,7 +296,6 @@ public class AriesSubsystem implements S
 			
 		}
 		this.location = location;
-		this.parents.add(parent);
 		id = getNextId();
 		String directoryName = "subsystem" + id;
 		// TODO Add to constants.
@@ -327,6 +327,7 @@ public class AriesSubsystem implements S
 			deleteFile(zipFile);
 			throw new SubsystemException(e);
 		}
+		subsystemGraph = parent.subsystemGraph;
 	}
 	
 	public AriesSubsystem(SubsystemArchive archive, AriesSubsystem parent) throws Exception {
@@ -340,12 +341,12 @@ public class AriesSubsystem implements S
 		String directoryName = "subsystem" + id;
 		directory = new File(parent.directory, directoryName);
 		environment = new SubsystemEnvironment(this);
-		parents.add(parent);
 		// Unscoped subsystems don't get their own region. They share the region with their scoped parent.
 		if (isFeature())
 			region = parent.region;
 		else
 			region = createRegion(getSymbolicName() + ';' + getVersion() + ';' + getType() + ';' + getSubsystemId());
+		subsystemGraph = parent.subsystemGraph;
 	}
 	
 	public SubsystemArchive getArchive() {
@@ -380,9 +381,9 @@ public class AriesSubsystem implements S
 		return Collections.emptyList();
 	}
 
-	@SuppressWarnings({ "unchecked", "rawtypes" })
+	@Override
 	public Collection<Subsystem> getChildren() {
-		return (Collection<Subsystem>)(Collection)Collections.unmodifiableCollection(new ArrayList<Subsystem>(children));
+		return subsystemGraph.getChildren(this);
 	}
 
 	@Override
@@ -397,7 +398,7 @@ public class AriesSubsystem implements S
 
 	@Override
 	public Collection<Subsystem> getParents() {
-		return Collections.unmodifiableCollection(new ArrayList<Subsystem>(parents));
+		return subsystemGraph.getParents(this);
 	}
 
 	@Override
@@ -460,7 +461,7 @@ public class AriesSubsystem implements S
 						&& subsystem.getVersion().equals(ssr.getSubsystemVersion())
 						&& subsystem.getType().equals(ssr.getSubsystemType())))
 					throw new SubsystemException("Location already exists but symbolic name, version, and type are not the same: " + location);
-				children.add(subsystem);
+				subsystemGraph.add(this, subsystem);
 				constituents.add(subsystem);
 				return subsystem;
 			}
@@ -468,7 +469,7 @@ public class AriesSubsystem implements S
 			if (subsystem != null) {
 				if (!subsystem.getType().equals(ssr.getSubsystemType()))
 					throw new SubsystemException("Subsystem already exists in target region but has a different type: " + location);
-				children.add(subsystem);
+				subsystemGraph.add(this, subsystem);
 				constituents.add(subsystem);
 				return subsystem;
 			}
@@ -562,7 +563,6 @@ public class AriesSubsystem implements S
 				startResource(resource, coordination);
 			}
 			setState(State.ACTIVE);
-//			persist(State.ACTIVE);
 		} catch (Exception e) {
 			coordination.fail(e);
 			// TODO Need to reinstate complete isolation by disconnecting the
@@ -614,7 +614,7 @@ public class AriesSubsystem implements S
 		// The root subsystem may not be uninstalled.
 		checkRoot();
 		State state = getState();
-		if (state == State.UNINSTALLING || state == State.UNINSTALLED) {
+		if (state == State.UNINSTALLING || state == State.UNINSTALLED || state == State.INSTALL_FAILED) {
 			return;
 		}
 		else if (state == State.INSTALLING || state == State.RESOLVING || state == State.STARTING || state == State.STOPPING) {
@@ -649,10 +649,10 @@ public class AriesSubsystem implements S
 				// TODO Should FAILED go out for each failure?
 			}
 		}
-		for (AriesSubsystem parent : parents) {
-			parent.children.remove(this);
-			parent.constituents.remove(this);
+		for (Subsystem parent : getParents()) {
+			((AriesSubsystem)parent).constituents.remove(this);
 		}
+		subsystemGraph.remove(this);
 		locationToSubsystem.remove(location);
 		deleteFile(directory);
 		setState(State.UNINSTALLED);
@@ -780,9 +780,9 @@ public class AriesSubsystem implements S
 		}
 		setState(State.STOPPING);
 		// Stop child subsystems first.
-		for (AriesSubsystem subsystem : children) {
+		for (Subsystem subsystem : subsystemGraph.getChildren(this)) {
 			try {
-				stopSubsystemResource(subsystem);
+				stopSubsystemResource((AriesSubsystem)subsystem);
 			}
 			catch (Exception e) {
 				LOGGER.error("An error occurred while stopping resource "
@@ -898,8 +898,8 @@ public class AriesSubsystem implements S
 		if (transitive) {
 			// Transitive dependencies should be provisioned into the highest possible level.
 			// TODO Assumes root is always the appropriate level.
-			while (!provisionTo.parents.isEmpty())
-				provisionTo = provisionTo.parents.iterator().next();
+			while (!provisionTo.getParents().isEmpty())
+				provisionTo = (AriesSubsystem)provisionTo.getParents().iterator().next();
 		}
 		return provisionTo;
 	}
@@ -991,7 +991,7 @@ public class AriesSubsystem implements S
 		Set<AriesSubsystem> subsystems = new HashSet<AriesSubsystem>();
 		subsystems.add(this);
 		resourceToSubsystems.put(subsystem, subsystems);
-		children.add(subsystem);
+		subsystemGraph.add(this, subsystem);
 		constituents.add(subsystem);
 		subsystem.install();
 		coordination.addParticipant(new Participant() {
@@ -1002,7 +1002,6 @@ public class AriesSubsystem implements S
 			public void failed(Coordination coordination) throws Exception {
 				subsystem.uninstall();
 				constituents.remove(subsystem);
-				children.remove(subsystem);
 				Set<AriesSubsystem> subsystems = resourceToSubsystems.get(subsystem);
 				subsystems.remove(AriesSubsystem.this);
 				if (subsystems.isEmpty())
@@ -1063,7 +1062,7 @@ public class AriesSubsystem implements S
 			// Applications have an implicit import policy equating to "import everything that I require", which is not the same as features.
 			// This must be computed from the application requirements and will be done using the Wires returned by the Resolver, when one is available.
 			region.connectRegion(
-					parents.iterator().next().region, 
+					((AriesSubsystem)getParents().iterator().next()).region, 
 					region.getRegionDigraph().createRegionFilterBuilder().allowAll(RegionFilter.VISIBLE_ALL_NAMESPACE).build());
 		}
 		else if (isComposite()) {

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemGraph.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemGraph.java?rev=1245802&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemGraph.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemGraph.java Fri Feb 17 23:17:51 2012
@@ -0,0 +1,126 @@
+package org.apache.aries.subsystem.core.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemException;
+
+public class SubsystemGraph {
+	private static class SubsystemWrapper {
+		private final Subsystem s;
+		
+		public SubsystemWrapper(Subsystem subsystem) {
+			s = subsystem;
+		}
+		
+		@Override
+		public boolean equals(Object o) {
+			if (o == this)
+				return true;
+			if (!(o instanceof SubsystemWrapper))
+				return false;
+			SubsystemWrapper that = (SubsystemWrapper)o;
+			return s.getSymbolicName().equals(that.s.getSymbolicName())
+					&& s.getVersion().equals(that.s.getVersion())
+					&& s.getType().equals(that.s.getType());
+		}
+		
+		public Subsystem getSubsystem() {
+			return s;
+		}
+		
+		@Override
+		public int hashCode() {
+			int result = 17;
+			result = result + 31 * s.getSymbolicName().hashCode();
+			result = result + 31 * s.getVersion().hashCode();
+			result = result + 31 * s.getType().hashCode();
+			return result;
+		}
+		
+		@Override
+		public String toString() {
+			return new StringBuilder().append(s.getClass().getName())
+					.append(": symbolicName=").append(s.getSymbolicName())
+					.append(", version=").append(s.getVersion())
+					.append(", type=").append(s.getType()).toString();
+		}
+	}
+	private final Map<SubsystemWrapper, Collection<SubsystemWrapper>> adjacencyList = new HashMap<SubsystemWrapper, Collection<SubsystemWrapper>>();
+	
+	public SubsystemGraph(Subsystem root) {
+		adjacencyList.put(new SubsystemWrapper(root), new HashSet<SubsystemWrapper>());
+	}
+	
+	public synchronized void add(Subsystem parent, Subsystem child) {
+		SubsystemWrapper parentWrap = new SubsystemWrapper(parent);
+		SubsystemWrapper childWrap = new SubsystemWrapper(child);
+		if (containsAncestor(childWrap, parentWrap))
+			throw new SubsystemException("Cycle detected between '" + parentWrap + "' and '" + childWrap + "'");
+		Collection<SubsystemWrapper> subsystems = adjacencyList.get(childWrap);
+		if (subsystems == null) {
+			subsystems = new HashSet<SubsystemWrapper>();
+			adjacencyList.put(childWrap, subsystems);
+		}
+		subsystems = adjacencyList.get(parentWrap);
+		if (subsystems == null) {
+			subsystems = new HashSet<SubsystemWrapper>();
+			adjacencyList.put(parentWrap, subsystems);
+		}
+		subsystems.add(childWrap);
+	}
+	
+	public synchronized Collection<Subsystem> getChildren(Subsystem parent) {
+		Collection<SubsystemWrapper> children = adjacencyList.get(new SubsystemWrapper(parent));
+		if (children == null || children.isEmpty())
+			return Collections.emptySet();
+		Collection<Subsystem> result = new ArrayList<Subsystem>(children.size());
+		for (SubsystemWrapper child : children)
+			result.add(child.getSubsystem());
+ 		return Collections.unmodifiableCollection(result);
+	}
+	
+	public synchronized Collection<Subsystem> getParents(Subsystem child) {
+		Collection<SubsystemWrapper> parents = getParents(new SubsystemWrapper(child));
+		Collection<Subsystem> result = new ArrayList<Subsystem>(parents.size());
+		for (SubsystemWrapper parent : parents) {
+			result.add(parent.getSubsystem());
+		}
+		return Collections.unmodifiableCollection(result);
+	}
+	
+	public synchronized void remove(Subsystem subsystem) {
+		SubsystemWrapper subsystemWrap = new SubsystemWrapper(subsystem);
+		Collection<SubsystemWrapper> parents = getParents(subsystemWrap);
+		for (SubsystemWrapper parent : parents)
+			adjacencyList.get(parent).remove(subsystemWrap);
+		adjacencyList.remove(subsystemWrap);
+	}
+	
+	private boolean containsAncestor(SubsystemWrapper subsystem, SubsystemWrapper ancestor) {
+		Collection<SubsystemWrapper> subsystems = adjacencyList.get(subsystem);
+		if (subsystems == null)
+			return false;
+		if (subsystems.contains(ancestor))
+			return true;
+		for (SubsystemWrapper s : subsystems) {
+			return containsAncestor(s, ancestor);
+		}
+		return false;
+	}
+	
+	private Collection<SubsystemWrapper> getParents(SubsystemWrapper child) {
+		ArrayList<SubsystemWrapper> result = new ArrayList<SubsystemWrapper>();
+		for (Entry<SubsystemWrapper, Collection<SubsystemWrapper>> entry : adjacencyList.entrySet())
+			if (entry.getValue().contains(child))
+				result.add(entry.getKey());
+		result.trimToSize();
+		return result;
+	}
+}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemServiceRegistrar.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemServiceRegistrar.java?rev=1245802&r1=1245801&r2=1245802&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemServiceRegistrar.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemServiceRegistrar.java Fri Feb 17 23:17:51 2012
@@ -23,7 +23,7 @@ public class SubsystemServiceRegistrar {
 	
 	public synchronized void register(Subsystem subsystem) {
 		if (map.containsKey(subsystem))
-			throw new IllegalArgumentException("Subsystem '" + subsystem + "' already has service registration '" + map.get(subsystem) + "'");
+			throw new IllegalStateException("Subsystem '" + subsystem + "' already has service registration '" + map.get(subsystem) + "'");
 		Dictionary<String, Object> properties = properties(subsystem);
 		ServiceRegistration<Subsystem> registration = context.registerService(Subsystem.class, subsystem, properties);
 		map.put(subsystem, registration);