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/08/20 22:58:28 UTC

svn commit: r1375215 - in /aries/trunk/subsystem: subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ subsystem-itests/src/test/java/org/apache/aries/subsystem/ite...

Author: jwross
Date: Mon Aug 20 20:58:27 2012
New Revision: 1375215

URL: http://svn.apache.org/viewvc?rev=1375215&view=rev
Log:
ARIES-907: As part of this work, the event emitting structure was changed to match those of bundles. On a restart, a persisted subsystem will generate an initial registration event containing its last state (i.e. RESOLVED or INSTALLED). If autostart is set to started, STARTING and ACTIVE events will follow. The root subsystem follows the same pattern. This required some changes to the tests.

A new test for autostarting under various conditions was also added.

Added:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ReferenceDirective.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AutostartTest.java
Removed:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ReferenceCountDirective.java
Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesSubsystemParentsHeader.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeployedContentHeader.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeploymentManifest.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AbstractAction.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
    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/BundleResourceInstaller.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceInstaller.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceUninstaller.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StartAction.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StopAction.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Subsystems.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RootSubsystemTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesSubsystemParentsHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesSubsystemParentsHeader.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesSubsystemParentsHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesSubsystemParentsHeader.java Mon Aug 20 20:58:27 2012
@@ -37,7 +37,6 @@ public class AriesSubsystemParentsHeader
 		public static final String ATTRIBUTE_VERSION = VersionRangeAttribute.NAME;
 		public static final String ATTRIBUTE_RESOURCEID = "resourceId";
 		public static final String ATTRIBUTE_TYPE = TypeAttribute.NAME;
-		public static final String DIRECTIVE_REFERENCECOUNT = ReferenceCountDirective.NAME;
 		
 		private static final Pattern PATTERN_SYMBOLICNAME = Pattern.compile('(' + Grammar.SYMBOLICNAME + ")(?=;|\\z)");
 		private static final Pattern PATTERN_PARAMETER = Pattern.compile('(' + Grammar.PARAMETER + ")(?=;|\\z)");
@@ -152,10 +151,6 @@ public class AriesSubsystemParentsHeader
 			return ((VersionAttribute)getAttribute(ATTRIBUTE_VERSION)).getVersion();
 		}
 		
-		public boolean isIncrementReferenceCount() {
-			return ((ReferenceCountDirective)getDirective(DIRECTIVE_REFERENCECOUNT)).isIncrement();
-		}
-		
 		public OsgiIdentityRequirement toRequirement(Resource resource) {
 			return new OsgiIdentityRequirement(getSymbolicName(), getVersion(), getType(), false);
 		}
@@ -189,11 +184,7 @@ public class AriesSubsystemParentsHeader
 			.append(';')
 			.append(Clause.ATTRIBUTE_RESOURCEID)
 			.append('=')
-			.append(subsystem.getSubsystemId())
-			.append(';')
-			.append(Clause.DIRECTIVE_REFERENCECOUNT)
-			.append(":=")
-			.append(referenceCount);
+			.append(subsystem.getSubsystemId());
 		return builder;
 	}
 	
@@ -238,13 +229,6 @@ public class AriesSubsystemParentsHeader
 	public Collection<AriesSubsystemParentsHeader.Clause> getClauses() {
 		return Collections.unmodifiableSet(clauses);
 	}
-	
-	public boolean isIncrementReferenceCount(AriesSubsystem subsystem) {
-		Clause clause = getClause(subsystem);
-		if (clause == null)
-			return false;
-		return clause.isIncrementReferenceCount();
-	}
 
 	@Override
 	public String getName() {

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeployedContentHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeployedContentHeader.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeployedContentHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeployedContentHeader.java Mon Aug 20 20:58:27 2012
@@ -36,6 +36,7 @@ public class DeployedContentHeader imple
 		public static final String ATTRIBUTE_DEPLOYEDVERSION = DeployedVersionAttribute.NAME;
 		public static final String ATTRIBUTE_RESOURCEID = "resourceId";
 		public static final String ATTRIBUTE_TYPE = TypeAttribute.NAME;
+		public static final String DIRECTIVE_REFERENCE = ReferenceDirective.NAME;
 		public static final String DIRECTIVE_STARTORDER = StartOrderDirective.NAME;
 		
 		private static final Pattern PATTERN_SYMBOLICNAME = Pattern.compile('(' + Grammar.SYMBOLICNAME + ")(?=;|\\z)");
@@ -45,6 +46,9 @@ public class DeployedContentHeader imple
 			Parameter parameter = parameters.get(ATTRIBUTE_TYPE);
 			if (parameter == null)
 				parameters.put(ATTRIBUTE_TYPE, TypeAttribute.DEFAULT);
+			parameter = parameters.get(DIRECTIVE_REFERENCE);
+			if (parameter == null)
+				parameters.put(DIRECTIVE_REFERENCE, ReferenceDirective.TRUE);
 		}
 		
 		private final String path;
@@ -64,7 +68,11 @@ public class DeployedContentHeader imple
 		}
 		
 		public Clause(Resource resource) {
-			this(appendResource(resource, new StringBuilder()).toString());
+			this(resource, true);
+		}
+		
+		public Clause(Resource resource, boolean referenced) {
+			this(appendResource(resource, new StringBuilder(), referenced).toString());
 		}
 		
 		public boolean contains(Resource resource) {
@@ -143,6 +151,10 @@ public class DeployedContentHeader imple
 			return ((TypeAttribute)getAttribute(ATTRIBUTE_TYPE)).getType();
 		}
 		
+		public boolean isReferenced() {
+			return ((ReferenceDirective)getDirective(DIRECTIVE_REFERENCE)).isReferenced();
+		}
+		
 		public DeployedContentRequirement toRequirement(Resource resource) {
 			return new DeployedContentRequirement(this, resource);
 		}
@@ -163,7 +175,7 @@ public class DeployedContentHeader imple
 	public static DeployedContentHeader newInstance(Collection<Resource> resources) {
 		StringBuilder builder = new StringBuilder();
 		for (Resource resource : resources) {
-			appendResource(resource, builder);
+			appendResource(resource, builder, true);
 			builder.append(',');
 		}
 		// Remove the trailing comma.
@@ -172,7 +184,7 @@ public class DeployedContentHeader imple
 		return new DeployedContentHeader(builder.toString());
 	}
 	
-	private static StringBuilder appendResource(Resource resource, StringBuilder builder) {
+	private static StringBuilder appendResource(Resource resource, StringBuilder builder, boolean referenced) {
 		String symbolicName = ResourceHelper.getSymbolicNameAttribute(resource);
 		Version version = ResourceHelper.getVersionAttribute(resource);
 		String type = ResourceHelper.getTypeAttribute(resource);
@@ -188,7 +200,11 @@ public class DeployedContentHeader imple
 			.append(';')
 			.append(Clause.ATTRIBUTE_RESOURCEID)
 			.append('=')
-			.append(Utils.getId(resource));
+			.append(Utils.getId(resource))
+			.append(';')
+			.append(Clause.DIRECTIVE_REFERENCE)
+			.append(":=")
+			.append(referenced);
 		return builder;
 	}
 	
@@ -247,6 +263,13 @@ public class DeployedContentHeader imple
 		return toString();
 	}
 	
+	public boolean isReferenced(Resource resource) {
+		DeployedContentHeader.Clause clause = getClause(resource);
+		if (clause == null)
+			return false;
+		return clause.isReferenced();
+	}
+	
 	@Override
 	public List<Requirement> toRequirements(Resource resource) {
 		List<Requirement> requirements = new ArrayList<Requirement>(clauses.size());

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeploymentManifest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeploymentManifest.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeploymentManifest.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeploymentManifest.java Mon Aug 20 20:58:27 2012
@@ -51,15 +51,20 @@ public class DeploymentManifest {
 			return this;
 		}
 		
-		public Builder content(Resource resource) {
+//		public Builder content(Resource resource) {
+//			return content(resource, true);
+//		}
+		
+		public Builder content(Resource resource, boolean referenced) {
 			DeployedContentHeader header = (DeployedContentHeader)headers.get(DeploymentManifest.DEPLOYED_CONTENT);
 			if (header == null) {
-				header(DeployedContentHeader.newInstance(Collections.singletonList(resource)));
+				DeployedContentHeader.Clause clause = new DeployedContentHeader.Clause(resource, referenced);
+				header(new DeployedContentHeader(Collections.singleton(clause)));
 				return this;
 			}
 			DeployedContentHeader.Clause clause = header.getClause(resource);
 			if (clause == null) {
-				clause = new DeployedContentHeader.Clause(resource);
+				clause = new DeployedContentHeader.Clause(resource, referenced);
 				List<DeployedContentHeader.Clause> clauses = new ArrayList<DeployedContentHeader.Clause>(header.getClauses().size() + 1);
 				clauses.addAll(header.getClauses());
 				clauses.add(clause);
@@ -73,7 +78,7 @@ public class DeploymentManifest {
 					i.remove();
 					break;
 				}
-			clauses.add(new DeployedContentHeader.Clause(resource));
+			clauses.add(new DeployedContentHeader.Clause(resource, referenced));
 			header(new DeployedContentHeader(clauses));
 			return this;
 		}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java Mon Aug 20 20:58:27 2012
@@ -27,6 +27,8 @@ public class DirectiveFactory {
 			return VisibilityDirective.getInstance(value);
 		if (ProvisionPolicyDirective.NAME.equals(name))
 			return ProvisionPolicyDirective.getInstance(value);
+		if (ReferenceDirective.NAME.equals(name))
+			return ReferenceDirective.getInstance(value);
 		return new GenericDirective(name, value);
 	}
 }

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ReferenceDirective.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ReferenceDirective.java?rev=1375215&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ReferenceDirective.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ReferenceDirective.java Mon Aug 20 20:58:27 2012
@@ -0,0 +1,45 @@
+/*
+ * Licensed 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.core.archive;
+
+public class ReferenceDirective extends AbstractDirective {
+	public static final String NAME = "reference";
+	public static final String VALUE_FALSE = Boolean.FALSE.toString();
+	public static final String VALUE_TRUE = Boolean.TRUE.toString();
+	
+	public static final ReferenceDirective FALSE = new ReferenceDirective(VALUE_FALSE);
+	public static final ReferenceDirective TRUE = new ReferenceDirective(VALUE_TRUE);
+	
+	
+	public ReferenceDirective() {
+		this(VALUE_TRUE);
+	}
+	
+	public static ReferenceDirective getInstance(String value) {
+		if (VALUE_TRUE.equals(value))
+			return TRUE;
+		if (VALUE_FALSE.equals(value))
+			return FALSE;
+		else
+			throw new IllegalArgumentException("Invalid " + NAME + " directive: " + value);
+	}
+	
+	private ReferenceDirective(String value) {
+		super(NAME, value);
+	}
+
+	public boolean isReferenced() {
+		return TRUE == this || VALUE_TRUE.equals(getValue());
+	}
+}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AbstractAction.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AbstractAction.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AbstractAction.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/AbstractAction.java Mon Aug 20 20:58:27 2012
@@ -19,30 +19,30 @@ import org.osgi.service.subsystem.Subsys
 
 public abstract class AbstractAction implements PrivilegedAction<Object> {
 	protected final boolean disableRootCheck;
-	protected final boolean explicit;
-	protected final AriesSubsystem subsystem;
+	protected final AriesSubsystem requestor;
+	protected final AriesSubsystem target;
 	
-	public AbstractAction(AriesSubsystem subsystem, boolean disableRootCheck, boolean explicit) {
-		this.subsystem = subsystem;
+	public AbstractAction(AriesSubsystem requestor, AriesSubsystem target, boolean disableRootCheck) {
+		this.requestor = requestor;
+		this.target = target;
 		this.disableRootCheck = disableRootCheck;
-		this.explicit = explicit;
 	}
 	
 	protected void checkRoot() {
-		if (!disableRootCheck && subsystem.isRoot())
+		if (!disableRootCheck && target.isRoot())
 			throw new SubsystemException("This operation may not be performed on the root subsystem");
 	}
 	
 	protected void checkValid() {
-		AriesSubsystem s = (AriesSubsystem)Activator.getInstance().getSubsystemServiceRegistrar().getSubsystemService(subsystem);
-		if (s != subsystem)
+		AriesSubsystem s = (AriesSubsystem)Activator.getInstance().getSubsystemServiceRegistrar().getSubsystemService(target);
+		if (s != target)
 			throw new IllegalStateException("Detected stale subsystem instance: " + s);
 	}
 	
 	protected void waitForStateChange() {
-		synchronized (subsystem) {
+		synchronized (target) {
 			try {
-				subsystem.wait();
+				target.wait();
 			}
 			catch (InterruptedException e) {
 				throw new SubsystemException(e);

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java Mon Aug 20 20:58:27 2012
@@ -153,7 +153,7 @@ public class Activator implements Bundle
 	private void deactivate() {
 		if (!isActive())
 			return;
-		new StopAction(subsystems.getRootSubsystem(), true, false).run();
+		new StopAction(subsystems.getRootSubsystem(), subsystems.getRootSubsystem(), true).run();
 		for (ServiceRegistration<?> registration : registrations) {
 			try {
 				registration.unregister();

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=1375215&r1=1375214&r2=1375215&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 Mon Aug 20 20:58:27 2012
@@ -22,6 +22,7 @@ import java.security.AccessController;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
@@ -106,7 +107,7 @@ public class AriesSubsystem implements R
 	
 	public AriesSubsystem(IDirectory directory) throws IOException, URISyntaxException, ResolutionException {
 		this.directory = directory;
-		setDeploymentManifest(new DeploymentManifest.Builder().manifest(getDeploymentManifest()).state(State.INSTALLING).build());
+		setDeploymentManifest(new DeploymentManifest.Builder().manifest(getDeploymentManifest()).build());
 	}
 	
 	/* BEGIN Resource interface methods. */
@@ -258,27 +259,29 @@ public class AriesSubsystem implements R
 	@Override
 	public void start() {
 		SecurityManager.checkExecutePermission(this);
-		AccessController.doPrivileged(new StartAction(this, true));
+		setAutostart(true);
+		AccessController.doPrivileged(new StartAction(this, this, this));
 	}
 
 	@Override
 	public void stop() {
 		SecurityManager.checkExecutePermission(this);
-		AccessController.doPrivileged(new StopAction(this, !isRoot(), true));
+		setAutostart(false);
+		AccessController.doPrivileged(new StopAction(this, this, !isRoot()));
 	}
 
 	@Override
 	public void uninstall() {
 		SecurityManager.checkLifecyclePermission(this);
-		AccessController.doPrivileged(new UninstallAction(this, false, true));
+		AccessController.doPrivileged(new UninstallAction(this, this, false));
 	}
 	
 	/* END Subsystem interface methods. */
 	
-	void addedContent(Resource resource) {
+	void addedConstituent(Resource resource, boolean referenced) {
 		try {
 			setDeploymentManifest(new DeploymentManifest.Builder()
-					.manifest(getDeploymentManifest()).content(resource).build());
+					.manifest(getDeploymentManifest()).content(resource, referenced).build());
 		} catch (Exception e) {
 			throw new SubsystemException(e);
 		}
@@ -368,6 +371,25 @@ public class AriesSubsystem implements R
 		return getSubsystemManifest().getSubsystemTypeHeader().isFeature();
 	}
 	
+	boolean isReadyToStart() {
+		if (isRoot())
+			return true;
+		for (Subsystem parent : getParents())
+			if (EnumSet.of(State.STARTING, State.ACTIVE).contains(parent.getState()) && isAutostart())
+				return true;
+		return false;
+	}
+	
+	boolean isReferenced(Resource resource) {
+		// Everything is referenced for the root subsystem during initialization.
+		if (isRoot() && EnumSet.of(State.INSTALLING, State.INSTALLED).contains(getState()))
+			return true;
+		DeployedContentHeader header = getDeploymentManifest().getDeployedContentHeader();
+		if (header == null)
+			return false;
+		return header.isReferenced(resource);
+	}
+	
 	boolean isRoot() {
 		return ROOT_LOCATION.equals(getLocation());
 	}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceInstaller.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceInstaller.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceInstaller.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceInstaller.java Mon Aug 20 20:58:27 2012
@@ -35,8 +35,8 @@ public class BundleResourceInstaller ext
 			ThreadLocalSubsystem.set(provisionTo);
 			revision = installBundle();
 		}
-		addConstituent(revision);
 		addReference(revision);
+		addConstituent(revision);
 		return revision;
 	}
 	

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceInstaller.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceInstaller.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceInstaller.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceInstaller.java Mon Aug 20 20:58:27 2012
@@ -15,7 +15,6 @@ package org.apache.aries.subsystem.core.
 
 import org.apache.aries.subsystem.core.archive.DeployedContentHeader;
 import org.apache.aries.subsystem.core.archive.DeploymentManifest;
-import org.apache.aries.subsystem.core.archive.ProvisionResourceHeader;
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.resource.Resource;
 import org.osgi.service.coordinator.Coordination;
@@ -59,9 +58,9 @@ public abstract class ResourceInstaller 
 	
 	protected void addConstituent(final Resource resource) {
 		// Don't let a resource become a constituent of itself.
-		if (resource.equals(provisionTo))
+		if (provisionTo == null || resource.equals(provisionTo))
 			return;
-		Activator.getInstance().getSubsystems().addConstituent(provisionTo, resource, isContent());
+		Activator.getInstance().getSubsystems().addConstituent(provisionTo, resource, isReferencedProvisionTo());
 		coordination.addParticipant(new Participant() {
 			@Override
 			public void ended(Coordination arg0) throws Exception {
@@ -79,7 +78,13 @@ public abstract class ResourceInstaller 
 		// Don't let a resource reference itself.
 		if (resource.equals(subsystem))
 			return;
-		Activator.getInstance().getSubsystems().addReference(subsystem, resource);
+		// The following check protects against resources posing as content
+		// during a restart since the Deployed-Content header is currently used
+		// to track all constituents for persistence purposes, which includes
+		// resources that were provisioned to the subsystem as dependencies of
+		// other resources.
+		if (isReferencedSubsystem())
+			Activator.getInstance().getSubsystems().addReference(subsystem, resource);
 		coordination.addParticipant(new Participant() {
 			@Override
 			public void ended(Coordination arg0) throws Exception {
@@ -98,20 +103,32 @@ public abstract class ResourceInstaller 
 	}
 	
 	protected boolean isContent() {
-		DeploymentManifest manifest = subsystem.getDeploymentManifest();
-		DeployedContentHeader header = manifest.getDeployedContentHeader();
-		if (header == null)
-			return !isDependency();
-		return header.contains(resource) || !isDependency();
+		return Utils.isContent(subsystem, resource);
 	}
 	
 	protected boolean isDependency() {
+		return Utils.isDependency(subsystem, resource);
+	}
+	
+	protected boolean isReferencedProvisionTo() {
+		DeploymentManifest manifest = subsystem.getDeploymentManifest();
+		if (manifest != null) {
+			DeployedContentHeader header = manifest.getDeployedContentHeader();
+			if (header != null && header.contains(resource))
+				return subsystem.isReferenced(resource);
+		}
+		if (subsystem.equals(provisionTo))
+			return isReferencedSubsystem();
+		return false;
+	}
+	
+	protected boolean isReferencedSubsystem() {
 		DeploymentManifest manifest = subsystem.getDeploymentManifest();
-		if (manifest == null)
-			return false;
-		ProvisionResourceHeader header = manifest.getProvisionResourceHeader();
-		if (header == null)
-			return false;
-		return header.contains(resource);
+		if (manifest != null) {
+			DeployedContentHeader header = manifest.getDeployedContentHeader();
+			if (header != null && header.contains(resource))
+				return subsystem.isReferenced(resource);
+		}
+		return true;
 	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceUninstaller.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceUninstaller.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceUninstaller.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceUninstaller.java Mon Aug 20 20:58:27 2012
@@ -100,7 +100,7 @@ public abstract class ResourceUninstalle
 	}
 	
 	protected void removeConstituent() {
-		removeConstituent(provisionTo, resource);
+		removeConstituent(subsystem, resource);
 	}
 	
 	protected void removeReference() {

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StartAction.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StartAction.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StartAction.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StartAction.java Mon Aug 20 20:58:27 2012
@@ -18,6 +18,7 @@ import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Map.Entry;
 
@@ -52,41 +53,58 @@ import org.slf4j.LoggerFactory;
 public class StartAction extends AbstractAction {
 	private static final Logger logger = LoggerFactory.getLogger(AriesSubsystem.class);
 	
-	public StartAction(AriesSubsystem subsystem, boolean explicit) {
-		super(subsystem, false, explicit);
+	private final AriesSubsystem instigator;
+	
+	public StartAction(AriesSubsystem instigator, AriesSubsystem requestor, AriesSubsystem target) {
+		super(requestor, target, false);
+		this.instigator = instigator;
 	}
 	
 	@Override
 	public Object run() {
-		State state = subsystem.getState();
-		if (state == State.UNINSTALLING || state == State.UNINSTALLED)
+		State state = target.getState();
+		// The following states are illegal.
+		if (EnumSet.of(State.INSTALL_FAILED, State.UNINSTALLED, State.UNINSTALLING).contains(state))
 			throw new SubsystemException("Cannot stop from state " + state);
-		if (state == State.INSTALLING || state == State.RESOLVING || state == State.STOPPING) {
+		// The following states must wait.
+		if (EnumSet.of(State.INSTALLING, State.RESOLVING, State.STARTING, State.STOPPING).contains(state)) {
 			waitForStateChange();
-			return new StartAction(subsystem, explicit).run();
+			return new StartAction(instigator, requestor, target).run();
 		}
-		// TODO Should we wait on STARTING to see if the outcome is ACTIVE?
-		if (state == State.STARTING || state == State.ACTIVE)
+		// The following states mean the requested state has already been attained.
+		if (State.ACTIVE.equals(state))
 			return null;
-		resolve(subsystem);
-		if (explicit)
-			subsystem.setAutostart(true);
-		subsystem.setState(State.STARTING);
+		// Always start if target is content of requestor.
+		if (!Utils.isContent(requestor, target)) {
+			// Aways start if target is a dependency of requestor.
+			if (!Utils.isDependency(requestor, target)) {
+				// Always start if instigator equals target (explicit start).
+				if (!instigator.equals(target)) {
+					// Don't start if instigator is root (restart) and target is not ready.
+					if (instigator.isRoot() && !target.isReadyToStart()) {
+						return null;
+					}
+				}
+			}
+		}
+		// Resolve if necessary.
+		if (State.INSTALLED.equals(state))
+			resolve(target);
+		target.setState(State.STARTING);
 		// TODO Need to hold a lock here to guarantee that another start
 		// operation can't occur when the state goes to RESOLVED.
 		// Start the subsystem.
 		Coordination coordination = Activator.getInstance()
 				.getCoordinator()
-				.create(subsystem.getSymbolicName() + '-' + subsystem.getSubsystemId(), 0);
+				.create(target.getSymbolicName() + '-' + target.getSubsystemId(), 0);
 		try {
-			List<Resource> resources = new ArrayList<Resource>(Activator.getInstance().getSubsystems().getResourcesReferencedBy(subsystem));
-			SubsystemContentHeader header = subsystem.getSubsystemManifest().getSubsystemContentHeader();
+			List<Resource> resources = new ArrayList<Resource>(Activator.getInstance().getSubsystems().getResourcesReferencedBy(target));
+			SubsystemContentHeader header = target.getSubsystemManifest().getSubsystemContentHeader();
 			if (header != null)
 				Collections.sort(resources, new StartResourceComparator(header));
-			if (!subsystem.isRoot())
-				for (Resource resource : resources)
-					startResource(resource, coordination);
-			subsystem.setState(State.ACTIVE);
+			for (Resource resource : resources)
+				startResource(resource, coordination);
+			target.setState(State.ACTIVE);
 		} catch (Throwable t) {
 			coordination.fail(t);
 			// TODO Need to reinstate complete isolation by disconnecting the
@@ -95,7 +113,7 @@ public class StartAction extends Abstrac
 			try {
 				coordination.end();
 			} catch (CoordinationException e) {
-				subsystem.setState(State.RESOLVED);
+				target.setState(State.RESOLVED);
 				Throwable t = e.getCause();
 				if (t instanceof SubsystemException)
 					throw (SubsystemException)t;
@@ -105,7 +123,7 @@ public class StartAction extends Abstrac
 		return null;
 	}
 	
-	private Collection<Bundle> getBundles(AriesSubsystem subsystem) {
+	private static Collection<Bundle> getBundles(AriesSubsystem subsystem) {
 		Collection<Resource> constituents = Activator.getInstance().getSubsystems().getConstituents(subsystem);
 		ArrayList<Bundle> result = new ArrayList<Bundle>(constituents.size());
 		for (Resource resource : constituents) {
@@ -116,10 +134,11 @@ public class StartAction extends Abstrac
 		return result;
 	}
 	
-	private void resolve(AriesSubsystem subsystem) {
-		if (subsystem.getState() != State.INSTALLED)
-			return;
-		subsystem.setState(State.RESOLVING);
+	private static void resolve(AriesSubsystem subsystem) {
+		// Don't propagate a RESOLVING event if this is a persisted subsystem
+		// that is already RESOLVED.
+		if (State.INSTALLED.equals(subsystem.getState()))
+			subsystem.setState(State.RESOLVING);
 		try {
 			// The root subsystem should follow the same event pattern for
 			// state transitions as other subsystems. However, an unresolvable
@@ -141,9 +160,10 @@ public class StartAction extends Abstrac
 				}
 				setExportIsolationPolicy(subsystem);
 			}
-			// TODO Could avoid calling setState (and notifyAll) here and
-			// avoid the need for a lock.
-			subsystem.setState(State.RESOLVED);
+			// No need to propagate a RESOLVED event if this is a persisted
+			// subsystem already in the RESOLVED state.
+			if (State.RESOLVING.equals(subsystem.getState()))
+				subsystem.setState(State.RESOLVED);
 		}
 		catch (Throwable t) {
 			subsystem.setState(State.INSTALLED);
@@ -153,7 +173,7 @@ public class StartAction extends Abstrac
 		}
 	}
 	
-	private void setExportIsolationPolicy(AriesSubsystem subsystem) throws InvalidSyntaxException, IOException, BundleException, URISyntaxException, ResolutionException {
+	private static void setExportIsolationPolicy(AriesSubsystem subsystem) throws InvalidSyntaxException, IOException, BundleException, URISyntaxException, ResolutionException {
 		if (!subsystem.isComposite())
 			return;
 		Region from = ((AriesSubsystem)subsystem.getParents().iterator().next()).getRegion();
@@ -171,7 +191,7 @@ public class StartAction extends Abstrac
 		from.connectRegion(to, regionFilter);
 	}
 	
-	private void setExportIsolationPolicy(RegionFilterBuilder builder, ExportPackageHeader header, AriesSubsystem subsystem) throws InvalidSyntaxException {
+	private static void setExportIsolationPolicy(RegionFilterBuilder builder, ExportPackageHeader header, AriesSubsystem subsystem) throws InvalidSyntaxException {
 		if (header == null)
 			return;
 		String policy = RegionFilter.VISIBLE_PACKAGE_NAMESPACE;
@@ -186,7 +206,7 @@ public class StartAction extends Abstrac
 		}
 	}
 	
-	private void setExportIsolationPolicy(RegionFilterBuilder builder, ProvideCapabilityHeader header, AriesSubsystem subsystem) throws InvalidSyntaxException {
+	private static void setExportIsolationPolicy(RegionFilterBuilder builder, ProvideCapabilityHeader header, AriesSubsystem subsystem) throws InvalidSyntaxException {
 		if (header == null)
 			return;
 		for (ProvideCapabilityHeader.Clause clause : header.getClauses()) {
@@ -202,7 +222,7 @@ public class StartAction extends Abstrac
 		}
 	}
 	
-	private void setExportIsolationPolicy(RegionFilterBuilder builder, SubsystemExportServiceHeader header, AriesSubsystem subsystem) throws InvalidSyntaxException {
+	private static void setExportIsolationPolicy(RegionFilterBuilder builder, SubsystemExportServiceHeader header, AriesSubsystem subsystem) throws InvalidSyntaxException {
 		if (header == null)
 			return;
 		String policy = RegionFilter.VISIBLE_SERVICE_NAMESPACE;
@@ -250,7 +270,11 @@ public class StartAction extends Abstrac
 
 	private void startSubsystemResource(Resource resource, Coordination coordination) throws IOException {
 		final AriesSubsystem subsystem = (AriesSubsystem)resource;
-		new StartAction(subsystem, false).run();
+		// Subsystems that are content resources of another subsystem must have
+		// their autostart setting set to started.
+		if (Utils.isContent(this.target, subsystem))
+			subsystem.setAutostart(true);
+		new StartAction(instigator, target, subsystem).run();
 		if (coordination == null)
 			return;
 		coordination.addParticipant(new Participant() {
@@ -259,7 +283,7 @@ public class StartAction extends Abstrac
 			}
 	
 			public void failed(Coordination coordination) throws Exception {
-				new StopAction(subsystem, !subsystem.isRoot(), false).run();
+				new StopAction(target, subsystem, !subsystem.isRoot()).run();
 			}
 		});
 	}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StopAction.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StopAction.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StopAction.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/StopAction.java Mon Aug 20 20:58:27 2012
@@ -34,29 +34,27 @@ import org.slf4j.LoggerFactory;
 public class StopAction extends AbstractAction {
 	private static final Logger logger = LoggerFactory.getLogger(StopAction.class);
 	
-	public StopAction(AriesSubsystem subsystem, boolean disableRootCheck, boolean explicit) {
-		super(subsystem, disableRootCheck, explicit);
+	public StopAction(AriesSubsystem requestor, AriesSubsystem target, boolean disableRootCheck) {
+		super(requestor, target, disableRootCheck);
 	}
 	
 	@Override
 	public Object run() {
 		checkRoot();
-		if (explicit)
-			subsystem.setAutostart(false);
-		State state = subsystem.getState();
+		State state = target.getState();
 		if (EnumSet.of(State.INSTALLED, State.RESOLVED).contains(state))
 			return null;
 		else if (EnumSet.of(State.INSTALL_FAILED, State.UNINSTALLING, State.UNINSTALLED).contains(state))
 			throw new IllegalStateException("Cannot stop from state " + state);
 		else if (EnumSet.of(State.INSTALLING, State.RESOLVING, State.STARTING, State.STOPPING).contains(state)) {
 			waitForStateChange();
-			return new StopAction(subsystem, disableRootCheck, explicit).run();
+			return new StopAction(requestor, target, disableRootCheck).run();
 		}
-		subsystem.setState(State.STOPPING);
-		List<Resource> resources = new ArrayList<Resource>(Activator.getInstance().getSubsystems().getResourcesReferencedBy(subsystem));
-		SubsystemContentHeader header = subsystem.getSubsystemManifest().getSubsystemContentHeader();
+		target.setState(State.STOPPING);
+		List<Resource> resources = new ArrayList<Resource>(Activator.getInstance().getSubsystems().getResourcesReferencedBy(target));
+		SubsystemContentHeader header = target.getSubsystemManifest().getSubsystemContentHeader();
 		if (header != null) {
-			Collections.sort(resources, new StartResourceComparator(subsystem.getSubsystemManifest().getSubsystemContentHeader()));
+			Collections.sort(resources, new StartResourceComparator(target.getSubsystemManifest().getSubsystemContentHeader()));
 			Collections.reverse(resources);
 		}
 		for (Resource resource : resources) {
@@ -67,19 +65,19 @@ public class StopAction extends Abstract
 				stopResource(resource);
 			} 
 			catch (Exception e) {
-				logger.error("An error occurred while stopping resource " + resource + " of subsystem " + subsystem, e);
+				logger.error("An error occurred while stopping resource " + resource + " of subsystem " + target, e);
 			}
 		}
 		// TODO Can we automatically assume it actually is resolved?
-		subsystem.setState(State.RESOLVED);
+		target.setState(State.RESOLVED);
 		try {
-			subsystem.setDeploymentManifest(new DeploymentManifest(
-					subsystem.getDeploymentManifest(),
+			target.setDeploymentManifest(new DeploymentManifest(
+					target.getDeploymentManifest(),
 					null,
-					subsystem.isAutostart(),
-					subsystem.getSubsystemId(),
+					target.isAutostart(),
+					target.getSubsystemId(),
 					SubsystemIdentifier.getLastId(),
-					subsystem.getLocation(),
+					target.getLocation(),
 					false,
 					false));
 		}
@@ -90,7 +88,7 @@ public class StopAction extends Abstract
 	}
 	
 	private void stopBundleResource(Resource resource) throws BundleException {
-		if (subsystem.isRoot())
+		if (target.isRoot())
 			return;
 		((BundleRevision)resource).getBundle().stop();
 	}
@@ -112,6 +110,6 @@ public class StopAction extends Abstract
 	}
 	
 	private void stopSubsystemResource(Resource resource) throws IOException {
-		new StopAction((AriesSubsystem)resource, !((AriesSubsystem)resource).isRoot(), false).run();
+		new StopAction(target, (AriesSubsystem)resource, !((AriesSubsystem)resource).isRoot()).run();
 	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceInstaller.java Mon Aug 20 20:58:27 2012
@@ -80,13 +80,14 @@ public class SubsystemResourceInstaller 
 	}
 	
 	private AriesSubsystem installAriesSubsystem(AriesSubsystem subsystem) throws Exception {
+		// If the state is null, this is a brand new subsystem. If the state is
+		// not null, this is a persisted subsystem. For brand new subsystems,
+		// an INSTALLING event must be propagated.
+		if (subsystem.getState() == null)
+			subsystem.setState(State.INSTALLING);
 		addChild(subsystem);
+		addReference(subsystem);
 		addConstituent(subsystem);
-		if (!isDependency())
-			addReference(subsystem);
-		// TODO Is this check really necessary?
-		if (!State.INSTALLING.equals(subsystem.getState()))
-			return subsystem;
 		addSubsystem(subsystem);
 		if (subsystem.isScoped())
 			RegionContextBundleHelper.installRegionContextBundle(subsystem);
@@ -114,7 +115,10 @@ public class SubsystemResourceInstaller 
 		// Simulate installation of shared content so that necessary relationships are established.
 		for (Resource content : subsystem.getResource().getSharedContent())
 			ResourceInstaller.newInstance(coordination, content, subsystem).install();
-		subsystem.setState(State.INSTALLED);
+		// Only brand new subsystems should have acquired the INSTALLING state,
+		// in which case an INSTALLED event must be propagated.
+		if (State.INSTALLING.equals(subsystem.getState()))
+			subsystem.setState(State.INSTALLED);
 		return subsystem;
 	}
 	

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Subsystems.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Subsystems.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Subsystems.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Subsystems.java Mon Aug 20 20:58:27 2012
@@ -25,7 +25,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.aries.subsystem.core.archive.AriesSubsystemParentsHeader;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.resource.Resource;
@@ -47,7 +46,7 @@ public class Subsystems {
 		child.addedParent(parent, referenceCount);
 	}
 	
-	public void addConstituent(AriesSubsystem subsystem, Resource constituent, boolean isContent) {
+	public void addConstituent(AriesSubsystem subsystem, Resource constituent, boolean referenced) {
 		synchronized (subsystemToConstituents) {
 			Set<Resource> constituents = subsystemToConstituents.get(subsystem);
 			if (constituents == null) {
@@ -56,8 +55,7 @@ public class Subsystems {
 			}
 			constituents.add(constituent);
 		}
-		if (isContent)
-			subsystem.addedContent(constituent);
+		subsystem.addedConstituent(constituent, referenced);
 	}
 	
 	public void addReference(AriesSubsystem subsystem, Resource resource) {
@@ -108,6 +106,7 @@ public class Subsystems {
 				}
 			});
 			if (fileList.isEmpty()) {
+				// There are no persisted subsystems, including root.
 				SubsystemResource resource;
 				try {
 					resource = new SubsystemResource(file);
@@ -145,6 +144,7 @@ public class Subsystems {
 				}
 			}
 			else {
+				// There are persisted subsystems.
 				Coordination coordination = Utils.createCoordination();
 				Collection<AriesSubsystem> subsystems = new ArrayList<AriesSubsystem>(fileList.size());
 				try {
@@ -156,16 +156,6 @@ public class Subsystems {
 					root = getSubsystemById(0);
 					graph = new SubsystemGraph(root);
 					ResourceInstaller.newInstance(coordination, root, root).install();
-					for (AriesSubsystem s : subsystems) {
-						AriesSubsystemParentsHeader header = s.getDeploymentManifest().getAriesSubsystemParentsHeader();
-						if (header == null)
-							continue;
-						for (AriesSubsystemParentsHeader.Clause clause : header.getClauses()) {
-							ResourceInstaller.newInstance(coordination, s, getSubsystemById(clause.getId())).install();
-							if (s.isAutostart())
-								new StartAction(s, false).run();
-						}
-					}
 				} catch (Exception e) {
 					coordination.fail(e);
 				} finally {

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/UninstallAction.java Mon Aug 20 20:58:27 2012
@@ -18,27 +18,27 @@ import java.util.EnumSet;
 import org.osgi.service.subsystem.Subsystem.State;
 
 public class UninstallAction extends AbstractAction {
-	public UninstallAction(AriesSubsystem subsystem, boolean disableRootCheck, boolean explicit) {
-		super(subsystem, disableRootCheck, explicit);
+	public UninstallAction(AriesSubsystem requestor, AriesSubsystem target, boolean disableRootCheck) {
+		super(requestor, target, disableRootCheck);
 	}
 	
 	@Override
 	public Object run() {
 		checkValid();
 		checkRoot();
-		State state = subsystem.getState();
+		State state = target.getState();
 		if (EnumSet.of(State.UNINSTALLED).contains(state))
 			return null;
 		else if (EnumSet.of(State.INSTALL_FAILED, State.INSTALLING, State.RESOLVING, State.STARTING, State.STOPPING, State.UNINSTALLING).contains(state)) {
 			waitForStateChange();
-			subsystem.uninstall();
+			target.uninstall();
 		}
 		else if (state.equals(State.ACTIVE)) {
-			new StopAction(subsystem, disableRootCheck, explicit).run();
-			subsystem.uninstall();
+			new StopAction(requestor, target, disableRootCheck).run();
+			target.uninstall();
 		}
 		else
-			ResourceUninstaller.newInstance(subsystem, subsystem).uninstall();
+			ResourceUninstaller.newInstance(requestor, target).uninstall();
 		return null;
 	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java Mon Aug 20 20:58:27 2012
@@ -13,6 +13,10 @@
  */
 package org.apache.aries.subsystem.core.internal;
 
+import org.apache.aries.subsystem.core.archive.DeploymentManifest;
+import org.apache.aries.subsystem.core.archive.ProvisionResourceHeader;
+import org.apache.aries.subsystem.core.archive.SubsystemContentHeader;
+import org.apache.aries.subsystem.core.archive.SubsystemManifest;
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.resource.Resource;
@@ -92,6 +96,33 @@ public class Utils {
 				IdentityNamespace.TYPE_FRAGMENT.equals(type);
 	}
 	
+	/*
+	 * The Deployed-Content header in the deployment manifest is used to store
+	 * information about explicitly installed resources and provisioned
+	 * dependencies in addition to content for persistence purposes. This method
+	 * returns true only if the resource is "true" content of the subsystem and,
+	 * therefore, uses the Subsystem-Content header from the subsystem manifest.
+	 */
+	public static boolean isContent(AriesSubsystem subsystem, Resource resource) {
+		SubsystemManifest subsystemManifest = subsystem.getSubsystemManifest();
+		if (subsystemManifest == null)
+			return false;
+		SubsystemContentHeader subsystemContentHeader = subsystemManifest.getSubsystemContentHeader();
+		if (subsystemContentHeader == null)
+			return false;
+		return subsystemContentHeader.contains(resource);
+	}
+	
+	public static boolean isDependency(AriesSubsystem subsystem, Resource resource) {
+		DeploymentManifest manifest = subsystem.getDeploymentManifest();
+		if (manifest == null)
+			return false;
+		ProvisionResourceHeader header = manifest.getProvisionResourceHeader();
+		if (header == null)
+			return false;
+		return header.contains(resource);
+	}
+	
 	public static boolean isInstallableResource(Resource resource) {
 		return !isSharedResource(resource);
 	}

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AutostartTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AutostartTest.java?rev=1375215&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AutostartTest.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/AutostartTest.java Mon Aug 20 20:58:27 2012
@@ -0,0 +1,531 @@
+/*
+ * Licensed 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;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
+
+import aQute.lib.osgi.Constants;
+
+@RunWith(JUnit4TestRunner.class)
+public class AutostartTest extends SubsystemTest {
+	/*
+	 * Subsystem-SymbolicName: application.a.esa
+	 * Subsystem-Content: bundle.a.jar
+	 */
+	private static final String APPLICATION_A = "application.a.esa";
+	/*
+	 * Subsystem-SymbolicName: application.b.esa
+	 * Subsystem-Content: bundle.a.jar,application.a.esa;type=osgi.subsystem.application
+	 */
+	private static final String APPLICATION_B = "application.b.esa";
+	/*
+	 * Bundle-SymbolicName: bundle.a.jar
+	 * Export-Package: x
+	 */
+	private static final String BUNDLE_A = "bundle.a.jar";
+	/*
+	 * Bundle-SymbolicName: bundle.b.jar
+	 * Import-Package: x
+	 */
+	private static final String BUNDLE_B = "bundle.b.jar";
+	/*
+	 * Subsystem-SymbolicName: composite.a.esa
+	 * Subsystem-Type: osgi.subsystem.composite
+	 * Subsystem-Content: bundle.a.jar;version="[0,0]"
+	 * Export-Package: x
+	 */
+	private static final String COMPOSITE_A = "composite.a.esa";
+	/*
+	 * Subsystem-SymbolicName: composite.b.esa
+	 * Subsystem-Type: osgi.subsystem.composite
+	 * Subsystem-Content: bundle.a.jar;version="[0,0]"
+	 * Import-Package: x
+	 * Preferred-Provider: composite.a.esa
+	 */
+	private static final String COMPOSITE_B = "composite.b.esa";
+	/*
+	 * Subsystem-SymbolicName: feature.a.esa
+	 * Subsystem-Type: osgi.subsystem.feature
+	 * Subsystem-Content: bundle.a.jar
+	 */
+	private static final String FEATURE_A = "feature.a.esa";
+	/*
+	 * Subsystem-SymbolicName: feature.b.esa
+	 * Subsystem-Type: osgi.subsystem.feature
+	 * Subsystem-Content: bundle.a.jar,feature.a.esa;type=osgi.subsystem.feature
+	 */
+	private static final String FEATURE_B = "feature.b.esa";
+	/*
+	 * Subsystem-SymbolicName: feature.c.esa
+	 * Subsystem-Type: osgi.subsystem.feature
+	 * Subsystem-Content: bundle.a.jar,feature.a.esa;type=osgi.subsystem.feature
+	 */
+	private static final String FEATURE_C = "feature.c.esa";
+	
+	private static void createApplicationA() throws IOException {
+		createApplicationAManifest();
+		createSubsystem(APPLICATION_A, BUNDLE_A);
+	}
+	
+	private static 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 static void createApplicationB() throws IOException {
+		createApplicationBManifest();
+		createSubsystem(APPLICATION_B, BUNDLE_A, APPLICATION_A);
+	}
+	
+	private static 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 + ',' + APPLICATION_A + ';' + IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE + '=' + SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION);
+		createManifest(APPLICATION_B + ".mf", attributes);
+	}
+	
+	private static void createBundleA() throws IOException {
+		Map<String, String> headers = new HashMap<String, String>();
+		headers.put(Constants.EXPORT_PACKAGE, "x");
+		createBundle(BUNDLE_A, headers);
+	}
+	
+	private static void createBundleB() throws IOException {
+		Map<String, String> headers = new HashMap<String, String>();
+		headers.put(Constants.IMPORT_PACKAGE, "x");
+		createBundle(BUNDLE_B, headers);
+	}
+	
+	private static void createCompositeA() throws IOException {
+		createCompositeAManifest();
+		createSubsystem(COMPOSITE_A, BUNDLE_A);
+	}
+	
+	private static 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, BUNDLE_A + ';' + IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE + "=\"[0,0]\"");
+		attributes.put(Constants.EXPORT_PACKAGE, "x");
+		createManifest(COMPOSITE_A + ".mf", attributes);
+	}
+	
+	private static void createCompositeB() throws IOException {
+		createCompositeBManifest();
+		createSubsystem(COMPOSITE_B, BUNDLE_B);
+	}
+	
+	private static 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_B + ';' + IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE + "=\"[0,0]\"");
+		attributes.put(Constants.IMPORT_PACKAGE, "x");
+		attributes.put(SubsystemConstants.PREFERRED_PROVIDER, COMPOSITE_A);
+		createManifest(COMPOSITE_B + ".mf", attributes);
+	}
+	
+	private static void createFeatureA() throws IOException {
+		createFeatureAManifest();
+		createSubsystem(FEATURE_A, BUNDLE_A);
+	}
+	
+	private static 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);
+		attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A);
+		createManifest(FEATURE_A + ".mf", attributes);
+	}
+	
+	private static void createFeatureB() throws IOException {
+		createFeatureBManifest();
+		createSubsystem(FEATURE_B, BUNDLE_A);
+	}
+	
+	private static 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 static void createFeatureC() throws IOException {
+		createFeatureCManifest();
+		createSubsystem(FEATURE_C, BUNDLE_A, FEATURE_A);
+	}
+	
+	private static 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);
+		attributes.put(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A + ',' + FEATURE_A + ';' + IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE + '=' + SubsystemConstants.SUBSYSTEM_TYPE_FEATURE);
+		createManifest(FEATURE_C + ".mf", attributes);
+	}
+	
+	private static boolean createdTestFiles;
+	@Before
+	public static void createTestFiles() throws Exception {
+		if (createdTestFiles)
+			return;
+		createBundleA();
+		createBundleB();
+		createApplicationA();
+		createApplicationB();
+		createCompositeA();
+		createCompositeB();
+		createFeatureA();
+		createFeatureB();
+		createFeatureC();
+		createdTestFiles = true;
+	}
+	
+	public void setUp() throws Exception {
+		super.setUp();
+	}
+	
+	@Test
+	public void testAutostartScoped() throws Exception {
+		Subsystem subsystem = null;
+		try {
+			subsystem = installSubsystemFromFile(APPLICATION_A);
+			restartSubsystemsImplBundle();
+			subsystem = findSubsystemService(subsystem.getSubsystemId());
+			assertState(Subsystem.State.INSTALLED, subsystem);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, subsystem);
+			startSubsystem(subsystem);
+			restartSubsystemsImplBundle();
+			subsystem = findSubsystemService(subsystem.getSubsystemId());
+			assertState(Subsystem.State.ACTIVE, subsystem);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, subsystem);
+			stopSubsystem(subsystem);
+			restartSubsystemsImplBundle();
+			subsystem = findSubsystemService(subsystem.getSubsystemId());
+			assertState(Subsystem.State.RESOLVED, subsystem);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, subsystem);
+		}
+		finally {
+			stopAndUninstallSubsystemSilently(subsystem);
+		}
+	}
+	
+	@Test
+	public void testAutostartUnscoped() throws Exception {
+		Subsystem subsystem = null;
+		try {
+			subsystem = installSubsystemFromFile(FEATURE_A);
+			restartSubsystemsImplBundle();
+			subsystem = findSubsystemService(subsystem.getSubsystemId());
+			assertState(Subsystem.State.INSTALLED, subsystem);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, subsystem);
+			startSubsystem(subsystem);
+			restartSubsystemsImplBundle();
+			subsystem = findSubsystemService(subsystem.getSubsystemId());
+			assertState(Subsystem.State.ACTIVE, subsystem);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, subsystem);
+			stopSubsystem(subsystem);
+			restartSubsystemsImplBundle();
+			subsystem = findSubsystemService(subsystem.getSubsystemId());
+			assertState(Subsystem.State.RESOLVED, subsystem);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, subsystem);
+		}
+		finally {
+			stopAndUninstallSubsystemSilently(subsystem);
+		}
+	}
+	
+	@Test
+	public void testAutostartChildScoped() throws Exception {
+		Subsystem compositeA = null;
+		try {
+			compositeA = installSubsystemFromFile(COMPOSITE_A);
+			Subsystem applicationA = installSubsystemFromFile(compositeA, APPLICATION_A);
+			
+			restartSubsystemsImplBundle();
+			compositeA = findSubsystemService(compositeA.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());
+			assertState(Subsystem.State.INSTALLED, compositeA);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, compositeA);
+			assertState(Subsystem.State.INSTALLED, applicationA);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, applicationA);
+			startSubsystem(compositeA);
+			
+			restartSubsystemsImplBundle();
+			compositeA = findSubsystemService(compositeA.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, compositeA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, compositeA);
+			assertState(Subsystem.State.RESOLVED, applicationA);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, applicationA);
+			startSubsystemFromResolved(applicationA);
+			
+			restartSubsystemsImplBundle();
+			compositeA = findSubsystemService(compositeA.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, compositeA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, compositeA);
+			assertState(Subsystem.State.ACTIVE, applicationA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, applicationA);
+			stopSubsystem(applicationA);
+			
+			restartSubsystemsImplBundle();
+			compositeA = findSubsystemService(compositeA.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, compositeA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, compositeA);
+			assertState(Subsystem.State.RESOLVED, applicationA);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, applicationA);
+			startSubsystemFromResolved(applicationA);
+			stopSubsystem(compositeA);
+			
+			restartSubsystemsImplBundle();
+			compositeA = findSubsystemService(compositeA.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());;
+			assertState(Subsystem.State.RESOLVED, compositeA);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, compositeA);
+			assertState(Subsystem.State.RESOLVED, applicationA);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, compositeA);
+		}
+		finally {
+			stopAndUninstallSubsystemSilently(compositeA);
+		}
+	}
+	
+	@Test
+	public void testAutostartChildUnscoped() throws Exception {
+		Subsystem featureA = null;
+		try {
+			featureA = installSubsystemFromFile(FEATURE_A);
+			Subsystem featureB = installSubsystemFromFile(featureA, FEATURE_B);
+			
+			restartSubsystemsImplBundle();
+			featureA = findSubsystemService(featureA.getSubsystemId());
+			featureB = findSubsystemService(featureB.getSubsystemId());
+			assertState(Subsystem.State.INSTALLED, featureA);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, featureA);
+			assertState(Subsystem.State.INSTALLED, featureB);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, featureB);
+			startSubsystem(featureA);
+			
+			restartSubsystemsImplBundle();
+			featureA = findSubsystemService(featureA.getSubsystemId());
+			featureB = findSubsystemService(featureB.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, featureA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureA);
+			assertState(Subsystem.State.RESOLVED, featureB);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureB);
+			startSubsystemFromResolved(featureB);
+			
+			restartSubsystemsImplBundle();
+			featureA = findSubsystemService(featureA.getSubsystemId());
+			featureB = findSubsystemService(featureB.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, featureA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureA);
+			assertState(Subsystem.State.ACTIVE, featureB);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureB);
+			stopSubsystem(featureB);
+			
+			restartSubsystemsImplBundle();
+			featureA = findSubsystemService(featureA.getSubsystemId());
+			featureB = findSubsystemService(featureB.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, featureA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureA);
+			assertState(Subsystem.State.RESOLVED, featureB);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureB);
+			startSubsystemFromResolved(featureB);
+			stopSubsystem(featureA);
+			
+			restartSubsystemsImplBundle();
+			featureA = findSubsystemService(featureA.getSubsystemId());
+			featureB = findSubsystemService(featureB.getSubsystemId());;
+			assertState(Subsystem.State.RESOLVED, featureA);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, featureA);
+			assertState(Subsystem.State.RESOLVED, featureB);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, featureA);
+		}
+		finally {
+			stopAndUninstallSubsystemSilently(featureA);
+		}
+	}
+	
+	@Test
+	public void testAutostartChildAsContentScoped() throws Exception {
+		Subsystem applicationB = null;
+		try {
+			applicationB = installSubsystemFromFile(APPLICATION_B);
+			Subsystem applicationA = applicationB.getChildren().iterator().next();
+			
+			restartSubsystemsImplBundle();
+			applicationB = findSubsystemService(applicationB.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());
+			assertState(Subsystem.State.INSTALLED, applicationB);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, applicationB);
+			assertState(Subsystem.State.INSTALLED, applicationA);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, applicationA);
+			startSubsystem(applicationB);
+			
+			restartSubsystemsImplBundle();
+			applicationB = findSubsystemService(applicationB.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, applicationB);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, applicationB);
+			assertState(Subsystem.State.ACTIVE, applicationA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, applicationA);
+			stopSubsystem(applicationA);
+			
+			restartSubsystemsImplBundle();
+			applicationB = findSubsystemService(applicationB.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, applicationB);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, applicationB);
+			assertState(Subsystem.State.ACTIVE, applicationA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, applicationA);
+			stopSubsystem(applicationB);
+			
+			restartSubsystemsImplBundle();
+			applicationB = findSubsystemService(applicationB.getSubsystemId());
+			applicationA = findSubsystemService(applicationA.getSubsystemId());;
+			assertState(Subsystem.State.RESOLVED, applicationB);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, applicationB);
+			assertState(Subsystem.State.RESOLVED, applicationA);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, applicationA);
+		}
+		finally {
+			stopAndUninstallSubsystemSilently(applicationB);
+		}
+	}
+	
+	@Test
+	public void testAutostartChildAsContentUnscoped() throws Exception {
+		Subsystem featureC = null;
+		try {
+			featureC = installSubsystemFromFile(FEATURE_C);
+			Subsystem featureA = featureC.getChildren().iterator().next();
+			
+			restartSubsystemsImplBundle();
+			featureC = findSubsystemService(featureC.getSubsystemId());
+			featureA = findSubsystemService(featureA.getSubsystemId());
+			assertState(Subsystem.State.INSTALLED, featureC);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, featureC);
+			assertState(Subsystem.State.INSTALLED, featureA);
+			assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, featureA);
+			
+			startSubsystem(featureC);
+			restartSubsystemsImplBundle();
+			featureC = findSubsystemService(featureC.getSubsystemId());
+			featureA = findSubsystemService(featureA.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, featureC);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureC);
+			assertState(Subsystem.State.ACTIVE, featureA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureA);
+			
+			stopSubsystem(featureA);
+			restartSubsystemsImplBundle();
+			featureC = findSubsystemService(featureC.getSubsystemId());
+			featureA = findSubsystemService(featureA.getSubsystemId());;
+			assertState(Subsystem.State.ACTIVE, featureC);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureC);
+			assertState(Subsystem.State.ACTIVE, featureA);
+			assertBundleState(Bundle.ACTIVE, BUNDLE_A, featureA);
+			
+			stopSubsystem(featureC);
+			restartSubsystemsImplBundle();
+			featureC = findSubsystemService(featureC.getSubsystemId());
+			featureA = findSubsystemService(featureA.getSubsystemId());;
+			assertState(Subsystem.State.RESOLVED, featureC);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, featureC);
+			assertState(Subsystem.State.RESOLVED, featureA);
+			assertBundleState(Bundle.RESOLVED, BUNDLE_A, featureA);
+		}
+		finally {
+			stopAndUninstallSubsystemSilently(featureC);
+		}
+	}
+	
+	@Test
+	public void testAutostartDependency() throws Exception {
+		Subsystem compositeA = installSubsystemFromFile(COMPOSITE_A);
+		try {
+			Subsystem compositeB = installSubsystemFromFile(COMPOSITE_B);
+			try {
+				restartSubsystemsImplBundle();
+				compositeB = findSubsystemService(compositeB.getSubsystemId());
+				compositeA = findSubsystemService(compositeA.getSubsystemId());
+				assertState(Subsystem.State.INSTALLED, compositeB);
+				assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_B, compositeB);
+				assertState(Subsystem.State.INSTALLED, compositeA);
+				assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_A, compositeA);
+				
+				startSubsystem(compositeA);
+				restartSubsystemsImplBundle();
+				compositeB = findSubsystemService(compositeB.getSubsystemId());
+				compositeA = findSubsystemService(compositeA.getSubsystemId());
+				assertState(Subsystem.State.INSTALLED, compositeB);
+				assertBundleState(Bundle.INSTALLED | Bundle.RESOLVED, BUNDLE_B, compositeB);
+				assertState(Subsystem.State.ACTIVE, compositeA);
+				assertBundleState(Bundle.ACTIVE, BUNDLE_A, compositeA);
+				
+				stopSubsystem(compositeA);
+				startSubsystem(compositeB);
+				restartSubsystemsImplBundle();
+				compositeB = findSubsystemService(compositeB.getSubsystemId());
+				compositeA = findSubsystemService(compositeA.getSubsystemId());
+				assertState(Subsystem.State.ACTIVE, compositeB);
+				assertBundleState(Bundle.ACTIVE, BUNDLE_B, compositeB);
+				assertState(Subsystem.State.ACTIVE, compositeA);
+				assertBundleState(Bundle.ACTIVE, BUNDLE_A, compositeA);
+				
+				stopSubsystem(compositeB);
+				restartSubsystemsImplBundle();
+				compositeB = findSubsystemService(compositeB.getSubsystemId());
+				compositeA = findSubsystemService(compositeA.getSubsystemId());
+				assertState(Subsystem.State.RESOLVED, compositeB);
+				assertBundleState(Bundle.RESOLVED, BUNDLE_B, compositeB);
+				assertState(Subsystem.State.RESOLVED, compositeA);
+				assertBundleState(Bundle.RESOLVED, BUNDLE_A, compositeA);
+				
+				uninstallSubsystem(compositeB);
+				restartSubsystemsImplBundle();
+				compositeA = findSubsystemService(compositeA.getSubsystemId());
+				assertState(Subsystem.State.RESOLVED, compositeA);
+				assertBundleState(Bundle.RESOLVED, BUNDLE_A, compositeA);
+				
+				startSubsystemFromResolved(compositeA);
+				restartSubsystemsImplBundle();
+				compositeA = findSubsystemService(compositeA.getSubsystemId());
+				assertState(Subsystem.State.ACTIVE, compositeA);
+				assertBundleState(Bundle.ACTIVE, BUNDLE_A, compositeA);
+			}
+			finally {
+				stopAndUninstallSubsystemSilently(compositeB);
+			}
+		}
+		finally {
+			stopAndUninstallSubsystemSilently(compositeA);
+		}
+	}
+}

Modified: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RootSubsystemTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RootSubsystemTest.java?rev=1375215&r1=1375214&r2=1375215&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RootSubsystemTest.java (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RootSubsystemTest.java Mon Aug 20 20:58:27 2012
@@ -20,6 +20,7 @@ import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceEvent;
 import org.osgi.framework.Version;
 import org.osgi.service.subsystem.Subsystem;
 
@@ -54,14 +55,17 @@ public class RootSubsystemTest extends S
 		core.uninstall();
 		core = installBundle("org.apache.aries.subsystem", "org.apache.aries.subsystem.core");
 		core.start();
+		// There should be install events since the persisted root subsystem was
+		// deleted when the subsystems implementation bundle was uninstalled.
 		assertServiceEventsInstall(root);
 		assertServiceEventsResolve(root);
 		assertServiceEventsStart(root);
 		core.stop();
 		assertServiceEventsStop(root);
 		core.start();
-		assertServiceEventsInstall(root);
-		assertServiceEventsResolve(root);
+		// There should be no install events or RESOLVING event since there
+		// should be a persisted root subsystem already in the RESOLVED state.
+		assertServiceEventResolved(root, ServiceEvent.REGISTERED);
 		assertServiceEventsStart(root);
 	}
 	

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=1375215&r1=1375214&r2=1375215&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 Aug 20 20:58:27 2012
@@ -65,6 +65,7 @@ import org.osgi.framework.ServiceListene
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.Version;
 import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.resource.Resource;
 import org.osgi.service.repository.Repository;
 import org.osgi.service.repository.RepositoryContent;
@@ -391,7 +392,7 @@ public abstract class SubsystemTest exte
 	
 	protected void assertServiceEventsResolve(Subsystem subsystem) throws InterruptedException {
 		assertEvent(subsystem, Subsystem.State.RESOLVING, subsystemEvents.poll(subsystem.getSubsystemId(), 5000));
-		assertEvent(subsystem, Subsystem.State.RESOLVED, subsystemEvents.poll(subsystem.getSubsystemId(), 5000));
+		assertServiceEventResolved(subsystem, ServiceEvent.MODIFIED);
 	}
 	
 	protected void assertServiceEventsStart(Subsystem subsystem) throws InterruptedException {
@@ -401,9 +402,13 @@ public abstract class SubsystemTest exte
 	
 	protected void assertServiceEventsStop(Subsystem subsystem) throws InterruptedException {
 		assertEvent(subsystem, Subsystem.State.STOPPING, subsystemEvents.poll(subsystem.getSubsystemId(), 5000));
-		assertEvent(subsystem, Subsystem.State.RESOLVED, subsystemEvents.poll(subsystem.getSubsystemId(), 5000));
+		assertServiceEventResolved(subsystem, ServiceEvent.MODIFIED);
 		// Don't forget about the unregistering event, which will have the same state as before.
-		assertEvent(subsystem, Subsystem.State.RESOLVED, subsystemEvents.poll(subsystem.getSubsystemId(), 5000), ServiceEvent.UNREGISTERING);
+		assertServiceEventResolved(subsystem, ServiceEvent.UNREGISTERING);
+	}
+	
+	protected void assertServiceEventResolved(Subsystem subsystem, int type) throws InterruptedException {
+		assertEvent(subsystem, Subsystem.State.RESOLVED, subsystemEvents.poll(subsystem.getSubsystemId(), 5000), type);
 	}
 	
 	protected void assertState(State expected, State actual) {
@@ -531,6 +536,11 @@ public abstract class SubsystemTest exte
 		write(name, fixture);
 	}
 	
+	protected Subsystem findSubsystemService(long id) throws InvalidSyntaxException {
+		String filter = "(" + SubsystemConstants.SUBSYSTEM_ID_PROPERTY + "=" + id + ")";
+		return getOsgiService(Subsystem.class, filter, 5000);
+	}
+	
 	protected Bundle getBundle(Subsystem subsystem, String symbolicName) {
 		for (Bundle bundle : subsystem.getBundleContext().getBundles()) {
 			if (symbolicName.equals(bundle.getSymbolicName())) { 
@@ -557,6 +567,15 @@ public abstract class SubsystemTest exte
 		return null;
 	}
 	
+	protected Bundle getConstituentAsBundle(Subsystem subsystem, String symbolicName, Version version, String type) {
+		return getConstituentAsBundleRevision(subsystem, symbolicName, version, type).getBundle();
+	}
+	
+	protected BundleRevision getConstituentAsBundleRevision(Subsystem subsystem, String symbolicName, Version version, String type) {
+		Resource resource = getConstituent(subsystem, symbolicName, version, type);
+		return (BundleRevision)resource;
+	}
+	
 	protected Bundle getRegionContextBundle(Subsystem subsystem) {
 		BundleContext bc = subsystem.getBundleContext();
 		assertNotNull("No region context bundle", bc);
@@ -660,6 +679,12 @@ public abstract class SubsystemTest exte
 		registerRepositoryService(resources);
 	}
 	
+	protected void restartSubsystemsImplBundle() throws BundleException {
+		Bundle b = getSubsystemCoreBundle();
+		b.stop();
+		b.start();
+	}
+	
 	protected void startBundle(Bundle bundle) throws BundleException {
 		startBundle(bundle, getRootSubsystem());
 	}
@@ -670,6 +695,10 @@ public abstract class SubsystemTest exte
 	}
 	
 	protected void startSubsystem(Subsystem subsystem) throws Exception {
+		startSubsystemFromInstalled(subsystem);
+	}
+	
+	protected void startSubsystemFromInstalled(Subsystem subsystem) throws InterruptedException {
 		assertState(State.INSTALLED, subsystem);
 		subsystemEvents.clear();
 		subsystem.start();
@@ -680,6 +709,15 @@ public abstract class SubsystemTest exte
 		assertState(State.ACTIVE, subsystem);
 	}
 	
+	protected void startSubsystemFromResolved(Subsystem subsystem) throws InterruptedException {
+		assertState(State.RESOLVED, subsystem);
+		subsystemEvents.clear();
+		subsystem.start();
+		assertEvent(subsystem, State.STARTING, 5000);
+		assertEvent(subsystem, State.ACTIVE, 5000);
+		assertState(State.ACTIVE, subsystem);
+	}
+	
 	protected void stopAndUninstallSubsystemSilently(Subsystem subsystem) {
 		stopSubsystemSilently(subsystem);
 		uninstallSubsystemSilently(subsystem);