aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jwr...@apache.org
Subject svn commit: r1717826 [1/3] - 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-core/src/test/java/org/apache/aries/subsystem...
Date Thu, 03 Dec 2015 18:25:00 GMT
Author: jwross
Date: Thu Dec  3 18:25:00 2015
New Revision: 1717826

URL: http://svn.apache.org/viewvc?rev=1717826&view=rev
Log:
[ARIES-1383] Provide option to disable the provisioning of dependencies at install time.

FUNCTIONALITY

Don't delete the temporary file after installation with apache-aries-provision-dependencies:=resolve. The file may be needed in order to install dependencies packaged as part of
the archive. Currently temporary files will not be automatically deleted for subsystems using the new directive with a value of "resolve". They will continue to be deleted for all
other subsystems. We should look at addressing this in the future.

In StartAction, move the installation of dependencies to just before resolution so that all checks apply.

Anticipate the INSTALLING state when apache-aries-provision-dependencies:=resolve in UninstallAction.

When transitioning from INSTALLING to INSTALLED, in addition to computing and installing the dependencies, we must also compute the Provision-Resource header and update the
deployment manifest.

Make sure apache-aries-provision-dependencies directive is always present with default value when not specified.

Move directive from Subsystem-SymbolicName to Subsystem-Type header consistent with the provision-policy directive.

Refactor DirectiveFactory to use a map when creating directives.

Fix issue where subsystems could never obtain the state INSTALL_FAILED.

Fix issue where correct state transitions related to INSTALL_FAILED do not occur.

An unscoped subsystem with a value of apache-aries-provision-dependencies different than the parent should fail installation.

Do not allow the installation of a child into an INSTALLING parent.

When installing multiple subsystems as part of the same archive, the local repository should reflect the capabilities of any child subsystems so that the parent
resolution will succeed in order to create the correct sharing policy. This is necessary for the case where dependencies were packaged as part of the archive of a child
subsystem.

When starting a subsystem, child subsystems with apache-aries-provision-dependencies:=resolve and still in the INSTALLING state should have their dependencies installed first.

When locating a region to use for capability validation purposes, the search now stops at the first scoped ancestor whose sharing policy has already been set rather than
blindly using the immediate parent. This covers the case of multiple subsystems from the same archive being installed. The sharing policy is "set" upon entering the
INSTALLED state.

Fix issue where scoped children were not treated as part of the target region.

A target region is associated with a "controlling scoped subsystem". This is the subsystem without which the region would not exist. Recall that the subsystem graph is a
directed acyclic graph with one, and only one, source vertex, namely the root subsystem. A target region, therefore, consists of all successors of the controlling scoped
subsystem having no intervening scoped predecessor.

Fix issue where stopping a subsystem did not allow for the possibility of a subsystem with apache-aries-provision-dependencies:=resolve to be in the INSTALLING state.

Neither features nor implicitly installed subsystems may override the apache-aries-provision-dependencies value of a parent.

The root subsystem does not need its subsystem manifest validated.

The temporary file of an installed subsystem should not be deleted if any implicitly installed children have apache-aries-provision-dependencies:=resolve.

Cannot set the default value for apache-aries-provision-dependencies in the directive class itself since the default is based on the parent subsystem's value.

Move the computation of the default value to where the subsystem is first being created out of the raw content.

When checking the visibility of a capability from an installable resource, we want to stop walking up the region tree if the parent subsystem accepts dependencies because we know the
resource will be installed there and visible to that region.

RegionUpdater.addRequirements may now be called with a null argument. This means that the connection between a child (i.e. the tail) and the parent (i.e. the head) will be deleted. In
other words, the child no longer has an export sharing policy. This was necessary in order to support rolling back the policy if resolution fails.

Subsystems that are referenced by a starting subsystem, are in the INSTALLING state, and have apache-aries-provision-dependencies:=resolve must be resolved.

The export sharing policy of a subsystem must be enabled before attempting resolution and must be rolled back if resolution fails.

Add thread local in order to detect when the same subsystem is being started twice on the same thread. This can happen when two or more subsystems have circular dependencies.

Refactor so that the steps of the resolution process are more clear.

Installation of shared content should not be delayed when apache-aries-provision-dependencies:=resolve.

When a subsystem is being resolved or started, other subsystems sharing content must be resolved. Otherwise, the resolver hook will prevent the shared content from resolving.

Use closed version ranges when computing the Subsystem-Content header. If the Subsystem-Content header is not specified, it is assumed that the provider wants the resources
packaged in the archive, and only those resources, used. For more flexibility, the Subsystem-Content header may be specified with more open version ranges.

Starting a subsystem now requires a global lock. This is necessary in order to support apache-aries-provision-dependencies:=resolve, particularly with regard to circular dependencies.
This means that all subsystem starts will now be synchronous. This should be optimized in the future with a more granular locking strategy.

Subsystems containing a referenced bundle of a resolving subsystem as a constituent must also be resolved.

Support the ability to restart subsystems with apache-aries-provision-dependencies:=resolve in the INSTALLING state.

Add new AriesSubsystem-OriginalContent header.

When computing the current wiring for resolution, do not include bundles whose wiring is null.

Initialize the parent field of a persisted subsystem resource with the first scoped parent.

Handle non-hierarchical URIs, such as those derived from JAR URLs, as part of a persistent, INSTALLING subsystem restart.

Given apache-aries-provision-dependencies:=resolve, need to push INSTALLING parents into INSTALLED to ensure all dependencies are available for resolution.

Given apache-aries-provision-dependencies:=resolve, need to return the region of the first scoped ancestor whose sharing policy has been set for validating capabilities.

Allow for implicit subsystem installations during resolution when determining what is or is not content.

TESTING

Add test cases listed in JIRA as well as some others.

Make the SubsystemEventHandler test utility class public.

Fix SubsystemTest to handle INSTALLING apache-aries-provision-dependencies:=resolve.

Add new utility builder classes. Note that the lack of these will break several commits prior to this one.

Add the ability to build a bundle archive as bytes for use as test repository content.

Add facility for automatically stopping and uninstalling subsystems without the need for try/catch/finally blocks.

Fix tests to expect the new closed version ranges used by computed Subsystem-Content headers.

Added:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesProvisionDependenciesDirective.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallDependencies.java
    aries/trunk/subsystem/subsystem-core/src/test/java/org/apache/aries/subsystem/core/archive/AriesProvisionDependenciesHeaderTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1383Test.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/BundleArchiveBuilder.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/SubsystemArchiveBuilder.java
Modified:
    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/archive/SubsystemContentHeader.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemSymbolicNameHeader.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemTypeHeader.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.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/Constants.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallAction.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/LocalRepository.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RawSubsystemResource.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.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/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/SubsystemManifestValidator.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResource.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/TargetRegion.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-core/src/test/resources/files/SUBSYSTEM.MF.1
    aries/trunk/subsystem/subsystem-core/src/test/resources/files/SUBSYSTEM.MF.2
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/HelloWorldTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/InstallTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemEventHandler.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1426Test.java

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesProvisionDependenciesDirective.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesProvisionDependenciesDirective.java?rev=1717826&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesProvisionDependenciesDirective.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AriesProvisionDependenciesDirective.java Thu Dec  3 18:25:00 2015
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+/**
+ * Aries specific implementation directive that can be added to the
+ * SubsystemSymbolicName header to defer provision of dependencies to start time
+ * (refer to jira aries-1383 for fuller description of this behavior).
+ * <p>
+ * The legal values for the directives are "start" and "install". The default is
+ * install.
+ * <p>
+ * There are exactly two instances of this type constructed. Statically
+ * references are
+ * {@code AriesProvisionDependenciesDirective.PROVISION_DEPENDENCIES_AT_INSTALL}
+ * or
+ * {@code AriesProvisionDependenciesDirective.PROVISION_DEPENDENCIES_AT_START}.
+ */
+public class AriesProvisionDependenciesDirective extends AbstractDirective {
+    public static final String NAME = "apache-aries-provision-dependencies";
+    
+    public static final String VALUE_INSTALL = "install";
+    public static final String VALUE_RESOLVE = "resolve";
+
+    public static final AriesProvisionDependenciesDirective INSTALL = new AriesProvisionDependenciesDirective(VALUE_INSTALL);
+    public static final AriesProvisionDependenciesDirective RESOLVE = new AriesProvisionDependenciesDirective(VALUE_RESOLVE);
+
+    public static final AriesProvisionDependenciesDirective DEFAULT = INSTALL;
+
+    public static AriesProvisionDependenciesDirective getInstance(String value) {
+        if (VALUE_INSTALL.equals(value))
+            return INSTALL;
+        if (VALUE_RESOLVE.equals(value))
+            return RESOLVE;
+        throw new IllegalArgumentException(value);
+    }
+
+    private AriesProvisionDependenciesDirective(String value) {
+        super(NAME, value);
+    }
+
+    public String getProvisionDependencies() {
+        return getValue();
+    }
+
+    public boolean isInstall() {
+        return this == INSTALL;
+    }
+
+    public boolean isResolve() {
+        return this == RESOLVE;
+    }
+}

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=1717826&r1=1717825&r2=1717826&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 Thu Dec  3 18:25:00 2015
@@ -13,24 +13,78 @@
  */
 package org.apache.aries.subsystem.core.archive;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class DirectiveFactory {
+	private interface Creator {
+		Directive create(String value);
+	}
+	
+	private static final Map<String, Creator> map = new HashMap<String, Creator>();
+	
+	static {
+		map.put(AriesProvisionDependenciesDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return AriesProvisionDependenciesDirective.getInstance(value);
+			}
+		});
+		map.put(CardinalityDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return CardinalityDirective.getInstance(value);
+			}
+		});
+		map.put(EffectiveDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return EffectiveDirective.getInstance(value);
+			}
+		});
+		map.put(FilterDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return new FilterDirective(value);
+			}
+		});
+		map.put(ProvisionPolicyDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return ProvisionPolicyDirective.getInstance(value);
+			}
+		});
+		map.put(ReferenceDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return ReferenceDirective.getInstance(value);
+			}
+		});
+		map.put(ResolutionDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return ResolutionDirective.getInstance(value);
+			}
+		});
+		map.put(StartOrderDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return new StartOrderDirective(value);
+			}
+		});
+		map.put(VisibilityDirective.NAME, new Creator() {
+			@Override
+			public Directive create(String value) {
+				return VisibilityDirective.getInstance(value);
+			}
+		});
+	}
+	
 	public static Directive createDirective(String name, String value) {
-		if (ResolutionDirective.NAME.equals(name))
-			return ResolutionDirective.getInstance(value);
-		if (StartOrderDirective.NAME.equals(name))
-			return new StartOrderDirective(value);
-		if (FilterDirective.NAME.equals(name))
-			return new FilterDirective(value);
-		if (EffectiveDirective.NAME.equals(name))
-			return EffectiveDirective.getInstance(value);
-		if (VisibilityDirective.NAME.equals(name))
-			return VisibilityDirective.getInstance(value);
-		if (ProvisionPolicyDirective.NAME.equals(name))
-			return ProvisionPolicyDirective.getInstance(value);
-		if (ReferenceDirective.NAME.equals(name))
-			return ReferenceDirective.getInstance(value);
-		if (CardinalityDirective.NAME.equals(name))
-			return CardinalityDirective.getInstance(value);
-		return new GenericDirective(name, value);
+		Creator creator = map.get(name);
+		if (creator == null) {
+			return new GenericDirective(name, value);
+		}
+		return creator.create(value);
 	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemContentHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemContentHeader.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemContentHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemContentHeader.java Thu Dec  3 18:25:00 2015
@@ -121,9 +121,11 @@ public class SubsystemContentHeader exte
 		builder.append(symbolicName)
 			.append(';')
 			.append(Clause.ATTRIBUTE_VERSION)
-			.append('=')
+			.append("=\"[")
 			.append(version.toString())
-			.append(';')
+			.append(',')
+			.append(version.toString())
+			.append("]\";")
 			.append(Clause.ATTRIBUTE_TYPE)
 			.append('=')
 			.append(type);

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemSymbolicNameHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemSymbolicNameHeader.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemSymbolicNameHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemSymbolicNameHeader.java Thu Dec  3 18:25:00 2015
@@ -13,9 +13,10 @@
  */
 package org.apache.aries.subsystem.core.archive;
 
+import org.osgi.service.subsystem.SubsystemConstants;
+
 public class SubsystemSymbolicNameHeader extends SymbolicNameHeader {
-	// TODO Add to constants.
-	public static final String NAME = "Subsystem-SymbolicName";
+	public static final String NAME = SubsystemConstants.SUBSYSTEM_SYMBOLICNAME;
 	
 	public SubsystemSymbolicNameHeader(String value) {
 		super(NAME, value);

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemTypeHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemTypeHeader.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemTypeHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemTypeHeader.java Thu Dec  3 18:25:00 2015
@@ -13,18 +13,25 @@
  */
 package org.apache.aries.subsystem.core.archive;
 
+import java.util.Collection;
 import java.util.Collections;
 
 import org.osgi.service.subsystem.SubsystemConstants;
 
 public class SubsystemTypeHeader extends AbstractClauseBasedHeader<SubsystemTypeHeader.Clause> {
     public static class Clause extends AbstractClause {
+    	private static final Collection<Parameter> defaultParameters = generateDefaultParameters(
+    			ProvisionPolicyDirective.REJECT_DEPENDENCIES);
+    	
 		public Clause(String clause) {
 			super(
             		parsePath(clause, Patterns.SUBSYSTEM_TYPE, false), 
             		parseParameters(clause, false), 
-            		generateDefaultParameters(
-            				ProvisionPolicyDirective.REJECT_DEPENDENCIES));
+            		defaultParameters);
+		}
+		
+		public AriesProvisionDependenciesDirective getProvisionDependenciesDirective() {
+			return (AriesProvisionDependenciesDirective)getDirective(DIRECTIVE_PROVISION_DEPENDENCIES);
 		}
 				
 		public ProvisionPolicyDirective getProvisionPolicyDirective() {
@@ -36,10 +43,13 @@ public class SubsystemTypeHeader extends
 		}
 	}
 	
-	public static final String DIRECTIVE_PROVISION_POLICY = SubsystemConstants.PROVISION_POLICY_DIRECTIVE;
+	public static final String DIRECTIVE_PROVISION_DEPENDENCIES = AriesProvisionDependenciesDirective.NAME;
+    public static final String DIRECTIVE_PROVISION_POLICY = ProvisionPolicyDirective.NAME;
 	public static final String NAME = SubsystemConstants.SUBSYSTEM_TYPE;
-	public static final String PROVISION_POLICY_ACCEPT_DEPENDENCIES = SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES;
-	public static final String PROVISION_POLICY_REJECT_DEPENDENCIES = SubsystemConstants.PROVISION_POLICY_REJECT_DEPENDENCIES;
+	public static final String ARIES_PROVISION_DEPENDENCIES_INSTALL = AriesProvisionDependenciesDirective.VALUE_INSTALL;
+	public static final String ARIES_PROVISION_DEPENDENCIES_RESOLVE = AriesProvisionDependenciesDirective.VALUE_RESOLVE;
+	public static final String PROVISION_POLICY_ACCEPT_DEPENDENCIES = ProvisionPolicyDirective.VALUE_ACCEPT_DEPENDENCIES;
+	public static final String PROVISION_POLICY_REJECT_DEPENDENCIES = ProvisionPolicyDirective.VALUE_REJECT_DEPENDENCIES;
 	public static final String TYPE_APPLICATION = SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION;
 	public static final String TYPE_COMPOSITE = SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE;
 	public static final String TYPE_FEATURE = SubsystemConstants.SUBSYSTEM_TYPE_FEATURE;
@@ -70,6 +80,10 @@ public class SubsystemTypeHeader extends
 		return NAME;
 	}
 	
+	public AriesProvisionDependenciesDirective getAriesProvisionDependenciesDirective() {
+		return clauses.iterator().next().getProvisionDependenciesDirective();
+	}
+	
 	public ProvisionPolicyDirective getProvisionPolicyDirective() {
 		return clauses.iterator().next().getProvisionPolicyDirective();
 	}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BasicSubsystem.java Thu Dec  3 18:25:00 2015
@@ -34,13 +34,17 @@ import java.util.Map.Entry;
 import java.util.Set;
 
 import org.apache.aries.subsystem.AriesSubsystem;
+import org.apache.aries.subsystem.core.archive.AriesProvisionDependenciesDirective;
 import org.apache.aries.subsystem.core.archive.AriesSubsystemParentsHeader;
 import org.apache.aries.subsystem.core.archive.DeployedContentHeader;
 import org.apache.aries.subsystem.core.archive.DeploymentManifest;
 import org.apache.aries.subsystem.core.archive.Header;
+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.apache.aries.subsystem.core.archive.SubsystemTypeHeader;
 import org.apache.aries.util.filesystem.FileSystem;
+import org.apache.aries.util.filesystem.ICloseableDirectory;
 import org.apache.aries.util.filesystem.IDirectory;
 import org.apache.aries.util.io.IOUtils;
 import org.eclipse.equinox.region.Region;
@@ -268,6 +272,15 @@ public class BasicSubsystem implements R
 		return getSubsystemManifest().getSubsystemVersionHeader().getVersion();
 	}
 
+    /** Get "aries-provision-dependencies" directive. 
+     * 
+     * @return requested directive or null if the directive is not specified in the header
+     */
+	public AriesProvisionDependenciesDirective getAriesProvisionDependenciesDirective() {
+        return getSubsystemManifest().getSubsystemTypeHeader().getAriesProvisionDependenciesDirective();
+    }
+	
+	
 	@Override
 	public AriesSubsystem install(String location) {
 		return install(location, (InputStream)null);
@@ -393,7 +406,7 @@ public class BasicSubsystem implements R
 	synchronized SubsystemResource getResource() {
 		if (resource == null) {
 			try {
-				resource = new SubsystemResource(directory);
+				resource = new SubsystemResource(null, directory);
 			}
 			catch (Exception e) {
 				throw new SubsystemException(e);
@@ -686,19 +699,48 @@ public class BasicSubsystem implements R
 
 	@Override
 	public AriesSubsystem install(String location, final InputStream content, InputStream deploymentManifest) {
+		AriesSubsystem result = null;
+		IDirectory directory = null;
 		try {
-			return install(location, content == null ? null : 
+			directory = content == null ? null : 
 				AccessController.doPrivileged(new PrivilegedAction<IDirectory>() {
 					@Override
 					public IDirectory run() {
 						return FileSystem.getFSRoot(content);
 					}
-				}),
-				deploymentManifest);
+				});
+			result = install(location, directory, deploymentManifest);
+			return result;
 		}
 		finally {
 			// This method must guarantee the content input stream was closed.
+			// TODO Not sure closing the content is necessary. The content will
+			// either be null of will have been closed while copying the data
+			// to the temporary file.
 			IOUtils.close(content);
+			// If appropriate, delete the temporary file. Subsystems having
+			// apache-aries-provision-dependencies:=resolve may need the file
+			// at start time if it contains any dependencies.
+			if (directory instanceof ICloseableDirectory) {
+				if (result == null
+						|| Utils.isProvisionDependenciesInstall((BasicSubsystem)result)
+						|| !wasInstalledWithChildrenHavingProvisionDependenciesResolve()) {
+					final IDirectory toClose = directory;
+					AccessController.doPrivileged(new PrivilegedAction<Void>() {
+						@Override
+						public Void run() {
+							try {
+								((ICloseableDirectory) toClose).close();
+							}
+							catch (IOException ioex) {
+								logger.info("Exception calling close for content {}. Exception {}", 
+										content, ioex);					
+							}
+							return null;
+						}
+					});
+				}
+			}
 		}
 	}
 	
@@ -711,4 +753,38 @@ public class BasicSubsystem implements R
 			translation.write(file);
 		}
 	}
+	
+	void computeDependenciesPostInstallation() throws IOException {
+		resource.computeDependencies(null);
+		ProvisionResourceHeader header = resource.computeProvisionResourceHeader();
+		setDeploymentManifest(
+				new DeploymentManifest.Builder()
+						.manifest(deploymentManifest)
+						.header(header)
+						.build());
+	}
+	
+	private boolean wasInstalledWithChildrenHavingProvisionDependenciesResolve() {
+		return wasInstalledWithChildrenHavingProvisionDependenciesResolve(this);
+	}
+	
+	private static boolean wasInstalledWithChildrenHavingProvisionDependenciesResolve(Subsystem child) {
+		BasicSubsystem bs = (BasicSubsystem) child;
+		SubsystemManifest manifest = bs.getSubsystemManifest();
+		SubsystemTypeHeader header = manifest.getSubsystemTypeHeader();
+		AriesProvisionDependenciesDirective directive = header.getAriesProvisionDependenciesDirective();
+		if (directive.isResolve()) {
+			return true;
+		}
+		return wasInstalledWithChildrenHavingProvisionDependenciesResolve(child.getChildren());
+	}
+	
+	private static boolean wasInstalledWithChildrenHavingProvisionDependenciesResolve(Collection<Subsystem> children) {
+		for (Subsystem child : children) {
+			if (wasInstalledWithChildrenHavingProvisionDependenciesResolve(child)) {
+				return true;
+			}
+		}
+		return false;
+	}
 }

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=1717826&r1=1717825&r2=1717826&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 Thu Dec  3 18:25:00 2015
@@ -21,7 +21,6 @@ import java.util.List;
 
 import org.apache.aries.util.io.IOUtils;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
 import org.osgi.framework.Version;
 import org.osgi.framework.startlevel.BundleStartLevel;
 import org.osgi.framework.wiring.BundleCapability;
@@ -33,7 +32,6 @@ import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
 import org.osgi.service.coordinator.Coordination;
-import org.osgi.service.coordinator.Participant;
 import org.osgi.service.subsystem.SubsystemException;
 
 public class BundleResourceInstaller extends ResourceInstaller {
@@ -199,9 +197,6 @@ public class BundleResourceInstaller ext
 		try {
 			bundle = provisionTo.getRegion().installBundleAtLocation(getLocation(), is);
 		}
-		catch (BundleException e) {
-			throw new SubsystemException(e);
-		}
 		finally {
 			ThreadLocalSubsystem.remove();
 			// Although Region.installBundle ultimately calls BundleContext.install,
@@ -210,15 +205,6 @@ public class BundleResourceInstaller ext
 			// be closed.
 			IOUtils.close(is);
 		}
-		coordination.addParticipant(new Participant() {
-			public void ended(Coordination coordination) throws Exception {
-				// Nothing
-			}
-
-			public void failed(Coordination coordination) throws Exception {
-				bundle.uninstall();
-			}
-		});
 		// Set the start level of all bundles managed (i.e. installed) by the
 		// subsystems implementation to 1 in case the framework's default bundle
 		// start level has been changed. Otherwise, start failures will occur

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Constants.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Constants.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Constants.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Constants.java Thu Dec  3 18:25:00 2015
@@ -16,6 +16,7 @@ package org.apache.aries.subsystem.core.
 import org.osgi.framework.namespace.IdentityNamespace;
 
 public class Constants {
+	public static final String AriesSubsystemOriginalContent = "AriesSubsystem-OriginalContent";
 	public static final String BundleSymbolicName = org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME;
 	public static final String BundleVersion = org.osgi.framework.Constants.BUNDLE_VERSION;
 	public static final String RegionContextBundleSymbolicNamePrefix = "org.osgi.service.subsystem.region.context.";

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallAction.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallAction.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallAction.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallAction.java Thu Dec  3 18:25:00 2015
@@ -14,18 +14,15 @@
 package org.apache.aries.subsystem.core.internal;
 
 import java.io.InputStream;
-import java.io.IOException;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
-import org.apache.aries.util.filesystem.ICloseableDirectory;
 import org.apache.aries.util.filesystem.IDirectory;
 import org.osgi.service.coordinator.Coordination;
 import org.osgi.service.coordinator.CoordinationException;
+import org.osgi.service.subsystem.Subsystem.State;
 import org.osgi.service.subsystem.SubsystemException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class InstallAction implements PrivilegedAction<BasicSubsystem> {
 	private final IDirectory content;
@@ -33,7 +30,6 @@ public class InstallAction implements Pr
 	private final InputStream deploymentManifest;
 	private final String location;
 	private final BasicSubsystem parent;
-	private static final Logger logger = LoggerFactory.getLogger(InstallAction.class);
 	
 	public InstallAction(String location, IDirectory content, BasicSubsystem parent, AccessControlContext context, InputStream deploymentManifest) {
 		this.location = location;
@@ -45,6 +41,10 @@ public class InstallAction implements Pr
 	
 	@Override
 	public BasicSubsystem run() {
+		State state = parent.getState();
+	    if (State.INSTALLING.equals(state)) {
+	        throw new SubsystemException("A child subsystem may not be installed while the parent is in the INSTALLING state");
+	    }
 		// Initialization of a null coordination must be privileged and,
 		// therefore, occur in the run() method rather than in the constructor.
 		Coordination coordination = Utils.createCoordination(parent);
@@ -91,25 +91,9 @@ public class InstallAction implements Pr
 					throw (SecurityException)t;
 				throw new SubsystemException(t);
 			}
-			finally {
-				closeContentIfIClosable();
-			}
 		}
 		return result;
 	}
-
-	private void closeContentIfIClosable() {
-		//clean up temp file
-		if (content instanceof ICloseableDirectory) {
-			try{
-				((ICloseableDirectory) content).close();
-			}
-			catch (IOException ioex) {
-				logger.info("Exception calling close for content {}. Exception {}", 
-						content, ioex);					
-			}
-		} 
-	}
 	
 	private void checkLifecyclePermission(final BasicSubsystem subsystem) {
 		AccessController.doPrivileged(new PrivilegedAction<Object>() {

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallDependencies.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallDependencies.java?rev=1717826&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallDependencies.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/InstallDependencies.java Thu Dec  3 18:25:00 2015
@@ -0,0 +1,27 @@
+package org.apache.aries.subsystem.core.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.osgi.resource.Resource;
+import org.osgi.service.coordinator.Coordination;
+
+public class InstallDependencies {
+    public void install(BasicSubsystem subsystem, BasicSubsystem parent, Coordination coordination) throws Exception{
+        // Install dependencies first...
+        List<Resource> dependencies = new ArrayList<Resource>(subsystem.getResource().getInstallableDependencies());
+        Collections.sort(dependencies, new InstallResourceComparator());
+        for (Resource dependency : dependencies)
+            ResourceInstaller.newInstance(coordination, dependency, subsystem).install();
+        for (Resource dependency : subsystem.getResource().getSharedDependencies()) {
+            // TODO This needs some more thought. The following check
+            // protects against a child subsystem that has its parent as a
+            // dependency. Are there other places of concern as well? Is it
+            // only the current parent that is of concern or should all
+            // parents be checked?
+            if (parent==null || !dependency.equals(parent))
+                ResourceInstaller.newInstance(coordination, dependency, subsystem).install();
+        }
+    }
+}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/LocalRepository.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/LocalRepository.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/LocalRepository.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/LocalRepository.java Thu Dec  3 18:25:00 2015
@@ -26,9 +26,7 @@ public class LocalRepository implements
 	
 	public LocalRepository(Collection<Resource> resources) {
 		repository = new CapabilitySetRepository();
-		for (Resource resource : resources) {
-		    repository.addResource(resource);
-		}
+		addResources(resources);
 	}
 	
 	@Override
@@ -36,4 +34,17 @@ public class LocalRepository implements
 			Collection<? extends Requirement> requirements) {
 		return repository.findProviders(requirements);
 	}
+	
+	private void addResources(Collection<Resource> resources) {
+		for (Resource resource : resources) {
+			addResource(resource);
+		}
+	}
+	
+	private void addResource(Resource resource) {
+		repository.addResource(resource);
+		if (resource instanceof RawSubsystemResource) {
+			addResources(((RawSubsystemResource)resource).getResources());
+		}
+	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RawSubsystemResource.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RawSubsystemResource.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RawSubsystemResource.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RawSubsystemResource.java Thu Dec  3 18:25:00 2015
@@ -18,6 +18,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URISyntaxException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -32,8 +33,10 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.aries.subsystem.ContentHandler;
+import org.apache.aries.subsystem.core.archive.AriesProvisionDependenciesDirective;
 import org.apache.aries.subsystem.core.archive.Attribute;
 import org.apache.aries.subsystem.core.archive.DeploymentManifest;
+import org.apache.aries.subsystem.core.archive.GenericHeader;
 import org.apache.aries.subsystem.core.archive.Header;
 import org.apache.aries.subsystem.core.archive.ImportPackageHeader;
 import org.apache.aries.subsystem.core.archive.RequireBundleHeader;
@@ -131,7 +134,7 @@ public class RawSubsystemResource implem
             resources = computeResources(content, manifest);
 			fakeImportServiceResource = createFakeResource(manifest);
 			localRepository = computeLocalRepository();
-			manifest = computeSubsystemManifestBeforeRequirements(manifest);
+			manifest = computeSubsystemManifestBeforeRequirements(content, manifest);
 			requirements = computeRequirements(manifest);
 			subsystemManifest = computeSubsystemManifestAfterRequirements(manifest);
 			capabilities = computeCapabilities();
@@ -148,9 +151,6 @@ public class RawSubsystemResource implem
 	}
 
 	public RawSubsystemResource(IDirectory idir, BasicSubsystem parent) throws IOException, URISyntaxException, ResolutionException {
-		resources = Collections.emptyList();
-		fakeImportServiceResource = null; // not needed for persistent subsystems
-		localRepository = computeLocalRepository();
 		subsystemManifest = initializeSubsystemManifest(idir);
 		requirements = subsystemManifest.toRequirements(this);
 		capabilities = subsystemManifest.toCapabilities(this);
@@ -159,6 +159,30 @@ public class RawSubsystemResource implem
 		location = new Location(deploymentManifest.getHeaders().get(DeploymentManifest.ARIESSUBSYSTEM_LOCATION).getValue());
 		parentSubsystem = parent;
 		translations = Collections.emptyList();
+		Map<String, Header<?>> headers = deploymentManifest.getHeaders();
+		if (State.INSTALLING.equals(
+				State.valueOf(
+						headers.get(
+								DeploymentManifest.ARIESSUBSYSTEM_STATE).getValue()))
+								&& subsystemManifest.getSubsystemTypeHeader().getAriesProvisionDependenciesDirective().isResolve()) {
+			URL url = new URL(headers.get(Constants.AriesSubsystemOriginalContent).getValue());
+			Collection<Resource> resources;
+			try {
+				resources = computeResources(FileSystem.getFSRoot(new File(url.toURI())), subsystemManifest);
+			}
+			catch (IllegalArgumentException e) {
+				// Thrown by File if the URI is not hierarchical. For example,
+				// when handling a JAR URL.
+				resources = computeResources(FileSystem.getFSRoot(url.openStream()), subsystemManifest);
+			}
+			this.resources = resources;
+			fakeImportServiceResource = createFakeResource(subsystemManifest);
+		}
+		else {
+			resources = Collections.emptyList();
+			fakeImportServiceResource = null;
+		}
+		localRepository = computeLocalRepository();
 	}
 
 	private static Resource createFakeResource(SubsystemManifest manifest) {
@@ -302,6 +326,10 @@ public class RawSubsystemResource implem
 	private void addSubsystemSymbolicNameHeader(SubsystemManifest.Builder builder, SubsystemManifest manifest) {
 		addHeader(builder, computeSubsystemSymbolicNameHeader(manifest));
 	}
+	
+	private void addSubsystemTypeHeader(SubsystemManifest.Builder builder, SubsystemManifest manifest) {
+		addHeader(builder, computeSubsystemTypeHeader(manifest));
+	}
 
 	private void addSubsystemVersionHeader(SubsystemManifest.Builder builder, SubsystemManifest manifest) {
 		addHeader(builder, computeSubsystemVersionHeader(manifest));
@@ -523,11 +551,13 @@ public class RawSubsystemResource implem
 		return builder.build();
 	}
 
-	private SubsystemManifest computeSubsystemManifestBeforeRequirements(SubsystemManifest manifest) {
+	private SubsystemManifest computeSubsystemManifestBeforeRequirements(IDirectory content, SubsystemManifest manifest) throws MalformedURLException {
 		SubsystemManifest.Builder builder = new SubsystemManifest.Builder().manifest(manifest);
 		addSubsystemSymbolicNameHeader(builder, manifest);
 		addSubsystemVersionHeader(builder, manifest);
+		addSubsystemTypeHeader(builder, manifest);
 		addSubsystemContentHeader(builder, manifest);
+		builder.header(new GenericHeader(Constants.AriesSubsystemOriginalContent, String.valueOf(content.toURL())));
 		return builder.build();
 	}
 
@@ -540,6 +570,23 @@ public class RawSubsystemResource implem
 			symbolicName = "org.apache.aries.subsystem." + id;
 		return new SubsystemSymbolicNameHeader(symbolicName);
 	}
+	
+	private SubsystemTypeHeader computeSubsystemTypeHeader(SubsystemManifest manifest) {
+		SubsystemTypeHeader header = manifest.getSubsystemTypeHeader();
+		AriesProvisionDependenciesDirective directive = header.getAriesProvisionDependenciesDirective();
+		if (directive != null) {
+			// Nothing to do because the directive was specified in the original 
+			// manifest. Validation of the value occurs later.
+			return header;
+		}
+		// The directive was not specified in the original manifest. The value 
+		// of the parent directive becomes the default.
+		SubsystemManifest parentManifest = ((BasicSubsystem)parentSubsystem).getSubsystemManifest();
+		SubsystemTypeHeader parentHeader = parentManifest.getSubsystemTypeHeader();
+		directive = parentHeader.getAriesProvisionDependenciesDirective();
+		header = new SubsystemTypeHeader(header.getValue() + ';' + directive);
+		return header;
+	}
 
 	private SubsystemVersionHeader computeSubsystemVersionHeader(SubsystemManifest manifest) {
 		SubsystemVersionHeader header = manifest.getSubsystemVersionHeader();
@@ -604,11 +651,17 @@ public class RawSubsystemResource implem
 							+ ';'
 							+ SubsystemTypeHeader.DIRECTIVE_PROVISION_POLICY
 							+ ":="
-							+ SubsystemTypeHeader.PROVISION_POLICY_ACCEPT_DEPENDENCIES)
+							+ SubsystemTypeHeader.PROVISION_POLICY_ACCEPT_DEPENDENCIES
+							+ ';'
+							+ AriesProvisionDependenciesDirective.INSTALL.toString())
 					.build();
 	}
 
 	private boolean isComposite(SubsystemManifest manifest) {
 		return SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE.equals(manifest.getSubsystemTypeHeader().getType());
 	}
+	
+	Collection<Resource> getResources() {
+		return resources;
+	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/RegionUpdater.java Thu Dec  3 18:25:00 2015
@@ -66,7 +66,12 @@ public class RegionUpdater {
 								.append(head.getName())
 								.toString());
 			}
-			addRequirements(requirements, builder);
+			if (requirements == null) {
+				heads.put(head.getName(), null);
+			}
+			else {
+				addRequirements(requirements, builder);
+			}
 			addHeadRegions(heads, tail, copy);
 			addTailRegions(tails, tail, copy);
 			// Replace the current digraph.
@@ -92,8 +97,13 @@ public class RegionUpdater {
 	}
 	
 	private void addHeadRegions(Map<String, RegionFilterBuilder> heads, Region tail, RegionDigraph digraph) throws BundleException {
-		for (Map.Entry<String, RegionFilterBuilder> entry : heads.entrySet())
-			tail.connectRegion(digraph.getRegion(entry.getKey()), entry.getValue().build());
+		for (Map.Entry<String, RegionFilterBuilder> entry : heads.entrySet()) {
+			RegionFilterBuilder builder = entry.getValue();
+			if (builder == null) {
+				continue;
+			}
+			tail.connectRegion(digraph.getRegion(entry.getKey()), builder.build());
+		}
 	}
 	
 	private void addTailRegions(Map<String, RegionFilterBuilder> tails, Region head, RegionDigraph digraph) throws BundleException {

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java Thu Dec  3 18:25:00 2015
@@ -22,6 +22,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.aries.subsystem.core.archive.ProvisionPolicyDirective;
+import org.apache.aries.subsystem.core.archive.SubsystemManifest;
+import org.apache.aries.subsystem.core.archive.SubsystemTypeHeader;
 import org.apache.aries.subsystem.core.internal.BundleResourceInstaller.BundleConstituent;
 import org.apache.aries.subsystem.core.internal.DependencyCalculator.MissingCapability;
 import org.apache.aries.subsystem.core.repository.Repository;
@@ -32,6 +35,7 @@ import org.osgi.framework.namespace.Exec
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.namespace.NativeNamespace;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWiring;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Namespace;
 import org.osgi.resource.Requirement;
@@ -171,11 +175,18 @@ public class ResolveContext extends org.
 	private void addWiring(Resource resource, Map<Resource, Wiring> wirings) {
 		if (resource instanceof BundleConstituent) {
 			BundleConstituent bc = (BundleConstituent)resource;
-			wirings.put(bc.getBundle().adapt(BundleRevision.class), bc.getWiring());
+			BundleWiring wiring = bc.getWiring();
+			if (wiring != null) {
+				wirings.put(bc.getBundle().adapt(BundleRevision.class), wiring);
+			}
 		}
 		else if (resource instanceof BundleRevision) {
 			BundleRevision br = (BundleRevision)resource;
-			wirings.put(br, br.getWiring());
+			BundleWiring wiring = br.getWiring();
+			if (wiring != null) {
+				wirings.put(br, wiring);
+			}
+			
 		}
 	}
 
@@ -188,14 +199,41 @@ public class ResolveContext extends org.
 		}
 		return Collections.unmodifiableMap(wirings);
 	}
+	
+	private boolean isContent(Resource resource) {
+		return this.resource.isContent(resource);
+	}
+
+	private boolean isInstallable(Resource resource) {
+		return !isShared(resource);
+	}
 
+	private boolean isShared(Resource resource) {
+		return Utils.isSharedResource(resource);
+	}
+
+	private boolean isValid(Capability capability, Requirement requirement) throws BundleException, IOException, InvalidSyntaxException, URISyntaxException {
+		if (IdentityNamespace.IDENTITY_NAMESPACE.equals(capability.getNamespace()))
+			return true;
+		Region from = findRegionForCapabilityValidation(capability.getResource());
+		Region to = findRegionForCapabilityValidation(requirement.getResource());
+		return new SharingPolicyValidator(from, to).isValid(capability);
+	}
+	
+	private boolean isAcceptDependencies() {
+		SubsystemManifest manifest = resource.getSubsystemManifest();
+		SubsystemTypeHeader header = manifest.getSubsystemTypeHeader();
+		ProvisionPolicyDirective directive = header.getProvisionPolicyDirective();
+		return directive.isAcceptDependencies();
+	}
+	
 	private Region findRegionForCapabilityValidation(Resource resource) throws BundleException, IOException, InvalidSyntaxException, URISyntaxException {
 		if (isInstallable(resource)) {
 			// This is an installable resource so we need to figure out where it
 			// will be installed.
 			if (isContent(resource) // If the resource is content of this subsystem, it will be installed here.
 					// Or if this subsystem accepts dependencies, the resource will be installed here.
-					|| this.resource.getSubsystemManifest().getSubsystemTypeHeader().getProvisionPolicyDirective().isAcceptDependencies()) {
+					|| isAcceptDependencies()) {
 				if (this.resource.isComposite()) {
 					// Composites define their own sharing policy with which
 					// their regions are already configured by the time we get
@@ -206,48 +244,49 @@ public class ResolveContext extends org.
 				// are visible to their scoped parent. Features import
 				// everything. Applications have their sharing policies
 				// computed, so if capabilities are visible to the parent, we
-				// know we can make them visible to the application.
-				return this.resource.getParents().iterator().next().getRegion();
-			}
-			// Same reasoning as above applies here.
-			if (this.resource.isComposite() && this.resource.getSubsystemManifest().getSubsystemTypeHeader().getProvisionPolicyDirective().isAcceptDependencies()) {
-				 return this.resource.getRegion();
+				// know we can make them visible to the application. 
+				BasicSubsystem parent = this.resource.getParents().iterator().next();
+				// If the parent accepts dependencies, the resource will 
+				// be installed there and all capabilities will be visible.
+				if (parent.getSubsystemManifest().getSubsystemTypeHeader().getProvisionPolicyDirective().isAcceptDependencies()) {
+					return parent.getRegion();
+				}
+				// Otherwise, the "parent" is defined as the first scoped 
+				// ancestor whose sharing policy has already been set. This 
+				// covers the case of multiple subsystems from the same archive 
+				// being installed whose regions will form a tree of depth N.
+				parent = Utils.findFirstScopedAncestorWithSharingPolicy(this.resource);
+				return parent.getRegion();
 			}
 			return Utils.findFirstSubsystemAcceptingDependenciesStartingFrom(this.resource.getParents().iterator().next()).getRegion();
 		}
 		else {
 			// This is an already installed resource from the system repository.
 			if (Utils.isBundle(resource)) {
+				if (this.resource.getSubsystemManifest().getSubsystemTypeHeader().getAriesProvisionDependenciesDirective().isResolve()) {
+					// If we get here with a subsystem that is 
+					// apache-aries-provision-dependencies:=resolve, it means
+					// that a restart has occurred with the subsystem in the
+					// INSTALLING state. It's content has already been installed.
+					// However, because the sharing policy has not yet been set,
+					// we must treat it similarly to the installable content case
+					// above.
+					return Utils.findFirstScopedAncestorWithSharingPolicy(this.resource).getRegion();
+				}
 			    BundleRevision revision = resource instanceof BundleRevision ? (BundleRevision)resource : ((BundleRevisionResource)resource).getRevision();
 				// If it's a bundle, use region digraph to get the region in order
 				// to account for bundles in isolated regions outside of the
 				// subsystems API.
 				return Activator.getInstance().getRegionDigraph().getRegion(revision.getBundle());
 			}
-			else
+			else {
+				if (this.resource.getSubsystemManifest().getSubsystemTypeHeader().getAriesProvisionDependenciesDirective().isResolve()) {
+					return Utils.findFirstScopedAncestorWithSharingPolicy(this.resource).getRegion();
+				}
 				// If it's anything else, get the region from one of the
 				// subsystems referencing it.
 				return Activator.getInstance().getSubsystems().getSubsystemsReferencing(resource).iterator().next().getRegion();
+			}
 		}
 	}
-
-	private boolean isContent(Resource resource) {
-		return this.resource.isContent(resource);
-	}
-
-	private boolean isInstallable(Resource resource) {
-		return !isShared(resource);
-	}
-
-	private boolean isShared(Resource resource) {
-		return Utils.isSharedResource(resource);
-	}
-
-	private boolean isValid(Capability capability, Requirement requirement) throws BundleException, IOException, InvalidSyntaxException, URISyntaxException {
-		if (IdentityNamespace.IDENTITY_NAMESPACE.equals(capability.getNamespace()))
-			return true;
-		Region from = findRegionForCapabilityValidation(capability.getResource());
-		Region to = findRegionForCapabilityValidation(requirement.getResource());
-		return new SharingPolicyValidator(from, to).isValid(capability);
-	}
 }

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=1717826&r1=1717825&r2=1717826&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 Thu Dec  3 18:25:00 2015
@@ -20,7 +20,6 @@ import org.osgi.framework.ServiceReferen
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.resource.Resource;
 import org.osgi.service.coordinator.Coordination;
-import org.osgi.service.coordinator.Participant;
 import org.osgi.service.subsystem.SubsystemConstants;
 import org.osgi.service.subsystem.SubsystemException;
 
@@ -52,10 +51,16 @@ public abstract class ResourceInstaller
 
     protected final Coordination coordination;
 	protected final BasicSubsystem provisionTo;
+	/* resource to install */
 	protected final Resource resource;
+	/* parent subsystem being installed into */
 	protected final BasicSubsystem subsystem;
 
 	public ResourceInstaller(Coordination coordination, Resource resource, BasicSubsystem subsystem) {
+		if (coordination == null || resource == null || subsystem == null) {
+			// We're assuming these are not null post construction, so enforce it here.
+			throw new NullPointerException();
+		}
 		this.coordination = coordination;
 		this.resource = resource;
 		this.subsystem = subsystem;
@@ -76,17 +81,6 @@ public abstract class ResourceInstaller
 		if (provisionTo == null || resource.equals(provisionTo))
 			return;
 		Activator.getInstance().getSubsystems().addConstituent(provisionTo, resource, isReferencedProvisionTo());
-		coordination.addParticipant(new Participant() {
-			@Override
-			public void ended(Coordination arg0) throws Exception {
-				// Nothing
-			}
-
-			@Override
-			public void failed(Coordination arg0) throws Exception {
-				Activator.getInstance().getSubsystems().removeConstituent(provisionTo, resource);
-			}
-		});
 	}
 
 	protected void addReference(final Resource resource) {
@@ -100,16 +94,6 @@ public abstract class ResourceInstaller
 		// other resources.
 		if (isReferencedSubsystem()) {
 			Activator.getInstance().getSubsystems().addReference(subsystem, resource);
-			coordination.addParticipant(new Participant() {
-				@Override
-				public void ended(Coordination arg0) throws Exception {
-					// Nothing
-				}
-				@Override
-				public void failed(Coordination arg0) throws Exception {
-					Activator.getInstance().getSubsystems().removeReference(subsystem, resource);
-				}
-			});
 		}
 	}
 

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=1717826&r1=1717825&r2=1717826&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 Thu Dec  3 18:25:00 2015
@@ -15,12 +15,15 @@ package org.apache.aries.subsystem.core.
 
 import java.io.IOException;
 import java.net.URISyntaxException;
+import java.security.AccessController;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.Set;
 
 import org.apache.aries.subsystem.ContentHandler;
 import org.apache.aries.subsystem.core.archive.ExportPackageCapability;
@@ -30,6 +33,7 @@ import org.apache.aries.subsystem.core.a
 import org.apache.aries.subsystem.core.archive.SubsystemContentHeader;
 import org.apache.aries.subsystem.core.archive.SubsystemExportServiceCapability;
 import org.apache.aries.subsystem.core.archive.SubsystemExportServiceHeader;
+import org.apache.aries.subsystem.core.internal.BundleResourceInstaller.BundleConstituent;
 import org.eclipse.equinox.region.Region;
 import org.eclipse.equinox.region.RegionFilter;
 import org.eclipse.equinox.region.RegionFilterBuilder;
@@ -56,6 +60,13 @@ import org.slf4j.LoggerFactory;
 
 public class StartAction extends AbstractAction {
 	private static final Logger logger = LoggerFactory.getLogger(StartAction.class);
+	
+	private static final ThreadLocal<Set<Subsystem>> subsystemsStartingOnCurrentThread = new ThreadLocal<Set<Subsystem>>() {
+		@Override
+		protected Set<Subsystem> initialValue() {
+			return new HashSet<Subsystem>();
+		}
+	};
 
 	private final Coordination coordination;
 	private final BasicSubsystem instigator;
@@ -79,73 +90,120 @@ public class StartAction extends Abstrac
 		this.coordination = coordination;
 		this.resolveOnly = resolveOnly;
 	}
+	
+	private Object doRun() {
+		// TODO We now support circular dependencies so a sane locking strategy
+		// is required now more than ever before. Needs to be much more granular
+		// (and complex) than this. Perhaps something along the lines of a state
+		// change lock per subsystem then use a global lock only while acquiring
+		// the necessary state change locks.
+		synchronized (StartAction.class) {
+			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 start from state " + state);
+		    // The following states must wait with the exception of INSTALLING
+		    // combined with apache-aries-provision-dependencies:=resolve.
+		    if ((State.INSTALLING.equals(state) 
+		    		&& Utils.isProvisionDependenciesInstall(target))
+		    	            || EnumSet.of(State.RESOLVING, State.STARTING, State.STOPPING).contains(state)) {
+		        waitForStateChange(state);
+		        return new StartAction(instigator, requestor, target, coordination).run();
+		    }
+		    // The following states mean the requested state has already been attained.
+		    if (State.ACTIVE.equals(state))
+		        return null;
+		    // Always start if target is content of requestor.
+		    if (!Utils.isContent(requestor, target)) {
+		        // Always 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;
+		                }
+		            }
+		        }
+		    }
+		    Coordination coordination = this.coordination;
+		    if (coordination == null) {
+		        coordination = Utils.createCoordination(target);
+		    }
+		    try {
+		    	// If necessary, install the dependencies.
+		    	if (State.INSTALLING.equals(target.getState()) && 
+		    			!Utils.isProvisionDependenciesInstall(target)) {
+		    		Collection<Subsystem> subsystems = new ArrayList<Subsystem>();
+		    		subsystems.addAll(Activator.getInstance().getSubsystems().getChildren(target));
+		    		subsystems.addAll(target.getParents());
+		    		for (Subsystem subsystem : subsystems) {
+		    			if (State.INSTALLING.equals(subsystem.getState())) {
+		    				BasicSubsystem bs = (BasicSubsystem)subsystem;
+		    				bs.computeDependenciesPostInstallation();
+		    	            new InstallDependencies().install(bs, null, coordination);
+		    	            bs.setState(State.INSTALLED);
+		    			}
+		    		}
+		    		target.computeDependenciesPostInstallation();
+		            new InstallDependencies().install(target, null, coordination);
+		            target.setState(State.INSTALLED);
+		    	}
+		        // Resolve if necessary.
+		        if (State.INSTALLED.equals(target.getState()))
+		            resolve(target, coordination);
+		        if (resolveOnly)
+		            return null;
+		        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.
+		        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));
+		        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
+		        // region and transition to INSTALLED.
+		    } finally {
+		        try {
+		            // Don't end the coordination if the subsystem being started
+		            // (i.e. the target) did not begin it.
+		            if (coordination.getName().equals(Utils.computeCoordinationName(target)))
+		                coordination.end();
+		        } catch (CoordinationException e) {
+		        	// If the target's state is INSTALLING then installing the
+		        	// dependencies failed, in which case we want to leave it as is.
+		        	if (!State.INSTALLING.equals(target.getState())) {
+		        		target.setState(State.RESOLVED);
+		        	}
+		            Throwable t = e.getCause();
+		            if (t instanceof SubsystemException)
+		                throw (SubsystemException)t;
+		            throw new SubsystemException(t);
+		        }
+		    }
+		    return null;
+		}
+	}
 
 	@Override
 	public Object run() {
-		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);
-		// The following states must wait.
-		if (EnumSet.of(State.INSTALLING, State.RESOLVING, State.STARTING, State.STOPPING).contains(state)) {
-			waitForStateChange(state);
-			return new StartAction(instigator, requestor, target, coordination).run();
-		}
-		// The following states mean the requested state has already been attained.
-		if (State.ACTIVE.equals(state))
+		Set<Subsystem> subsystems = subsystemsStartingOnCurrentThread.get();
+		if (subsystems.contains(target)) {
 			return null;
-		// Always start if target is content of requestor.
-		if (!Utils.isContent(requestor, target)) {
-			// Always 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;
-					}
-				}
-			}
-		}
-		Coordination coordination = this.coordination;
-		if (coordination == null)
-			coordination = Utils.createCoordination(target);
-		try {
-			// Resolve if necessary.
-			if (State.INSTALLED.equals(state))
-				resolve(target);
-			if (resolveOnly)
-				return null;
-			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.
-			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));
-			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
-			// region and transition to INSTALLED.
-		} finally {
-			try {
-				// Don't end the coordination if the subsystem being started
-				// (i.e. the target) did not begin it.
-				if (coordination.getName().equals(Utils.computeCoordinationName(target)))
-					coordination.end();
-			} catch (CoordinationException e) {
-				target.setState(State.RESOLVED);
-				Throwable t = e.getCause();
-				if (t instanceof SubsystemException)
-					throw (SubsystemException)t;
-				throw new SubsystemException(t);
-			}
 		}
-		return null;
+		subsystems.add(target);
+	    try {
+	    	return doRun();
+	    }
+	    finally {
+	    	subsystems.remove(target);
+	    }
 	}
 
 	private static Collection<Bundle> getBundles(BasicSubsystem subsystem) {
@@ -158,90 +216,83 @@ public class StartAction extends Abstrac
 		result.trimToSize();
 		return result;
 	}
-
-	private static void resolve(BasicSubsystem subsystem) {
+	
+	private static void emitResolvingEvent(BasicSubsystem 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);
+	}
+	
+	private static void emitResolvedEvent(BasicSubsystem subsystem) {
+		// 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);
+	}
+	
+	private static void resolveSubsystems(BasicSubsystem subsystem, Coordination coordination) {
+		//resolve dependencies to ensure framework resolution succeeds
+		Subsystems subsystems = Activator.getInstance().getSubsystems();
+		for (Resource dep : subsystems.getResourcesReferencedBy(subsystem)) {
+			if (dep instanceof BasicSubsystem 
+					&& !subsystems.getChildren(subsystem).contains(dep)) {
+				resolveSubsystem((BasicSubsystem)dep, coordination);
+			}
+			else if (dep instanceof BundleRevision
+					&& !subsystem.getConstituents().contains(dep)) {
+				for (BasicSubsystem constituentOf : subsystems.getSubsystemsByConstituent(
+						new BundleConstituent(null, (BundleRevision)dep))) {
+					resolveSubsystem(constituentOf, coordination);
+				}
+			}
+		}
+		for (Subsystem child : subsystems.getChildren(subsystem)) {
+			resolveSubsystem((BasicSubsystem)child, coordination);
+		}
+		for (Resource resource : subsystem.getResource().getSharedContent()) {
+			for (BasicSubsystem constituentOf : subsystems.getSubsystemsByConstituent(
+					resource instanceof BundleRevision ? new BundleConstituent(null, (BundleRevision)resource) : resource)) {
+				resolveSubsystem(constituentOf, coordination);
+			}
+		}
+	}
+	
+	private static void resolveSubsystem(BasicSubsystem subsystem, Coordination coordination) {
+		State state = subsystem.getState();
+		if (State.INSTALLED.equals(state)) {
+			AccessController.doPrivileged(new StartAction(subsystem, subsystem, subsystem, coordination, true));
+		}
+		else if (State.INSTALLING.equals(state)
+				&& !Utils.isProvisionDependenciesInstall(subsystem)) {
+			AccessController.doPrivileged(new StartAction(subsystem, subsystem, subsystem, coordination, true));
+		}
+	}
+	
+	private static void resolveBundles(BasicSubsystem subsystem) {
+		FrameworkWiring frameworkWiring = Activator.getInstance().getBundleContext().getBundle(0)
+				.adapt(FrameworkWiring.class);
+		// TODO I think this is insufficient. Do we need both
+		// pre-install and post-install environments for the Resolver?
+		Collection<Bundle> bundles = getBundles(subsystem);
+		if (!frameworkWiring.resolveBundles(bundles)) {
+			handleFailedResolution(subsystem, bundles, frameworkWiring);
+		}
+	}
+
+	private static void resolve(BasicSubsystem subsystem, Coordination coordination) {
+		emitResolvingEvent(subsystem);
 		try {
 			// The root subsystem should follow the same event pattern for
 			// state transitions as other subsystems. However, an unresolvable
 			// root subsystem should have no effect, so there's no point in
 			// actually doing the resolution work.
 			if (!subsystem.isRoot()) {
-				//resolve dependencies to ensure framework resolution succeeds
-				for (Resource dep : Activator.getInstance().getSubsystems().getResourcesReferencedBy(subsystem)) {
-					if (dep instanceof BasicSubsystem &&
-						!Activator.getInstance().getSubsystems().getChildren(subsystem).contains(dep)) {
-						if (State.INSTALLED == (((BasicSubsystem) dep).getState())) {
-						    resolve((BasicSubsystem) dep);
-						}
-					}
-				}
-				
-				for (Subsystem child : Activator.getInstance().getSubsystems().getChildren(subsystem)) {
-					if (State.INSTALLED.equals(child.getState())) {
-						resolve((BasicSubsystem)child);
-					}
-				}
-
-				FrameworkWiring frameworkWiring = Activator.getInstance().getBundleContext().getBundle(0)
-						.adapt(FrameworkWiring.class);
-
-				// TODO I think this is insufficient. Do we need both
-				// pre-install and post-install environments for the Resolver?
-				Collection<Bundle> bundles = getBundles(subsystem);
-				if (!frameworkWiring.resolveBundles(bundles)) {
-					//work out which bundles could not be resolved
-					Collection<Bundle> unresolved = new ArrayList<Bundle>();
-					StringBuilder diagnostics = new StringBuilder();
-					diagnostics.append(String.format("Unable to resolve bundles for subsystem/version/id %s/%s/%s:\n", 
-							subsystem.getSymbolicName(), subsystem.getVersion(), subsystem.getSubsystemId()));
-					String fmt = "%d : STATE %s : %s : %s : %s";
-					for(Bundle bundle:bundles){
-						if((bundle.getState() & Bundle.RESOLVED) != Bundle.RESOLVED) {
-							unresolved.add(bundle);
-						}
-						String state = null;
-						switch(bundle.getState()) {
-							case Bundle.ACTIVE :
-								state = "ACTIVE";
-								break;
-							case Bundle.INSTALLED :
-								state = "INSTALLED";
-								break;
-							case Bundle.RESOLVED :
-								state = "RESOLVED";
-								break;
-							case Bundle.STARTING :
-								state = "STARTING";
-								break;
-							case Bundle.STOPPING :
-								state = "STOPPING";
-								break;
-							case Bundle.UNINSTALLED :
-								state = "UNINSTALLED";
-								break;
-							default :
-								//convert common states to text otherwise default to just showing the ID
-								state = "[" + Integer.toString(bundle.getState()) + "]";
-								break;
-						}
-						diagnostics.append(String.format(fmt, bundle.getBundleId(), state, 
-								bundle.getSymbolicName(), bundle.getVersion().toString(), 
-								bundle.getLocation()));
-						diagnostics.append("\n");
-					}
-					logger.error(diagnostics.toString());
-					throw new SubsystemException("Framework could not resolve the bundles: " + unresolved);
-				}
-				setExportIsolationPolicy(subsystem);
+				setExportIsolationPolicy(subsystem, coordination);
+				resolveSubsystems(subsystem, coordination);
+				resolveBundles(subsystem);
 			}
-			// 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);
+			emitResolvedEvent(subsystem);
 		}
 		catch (Throwable t) {
 			subsystem.setState(State.INSTALLED);
@@ -251,11 +302,11 @@ public class StartAction extends Abstrac
 		}
 	}
 
-	private static void setExportIsolationPolicy(BasicSubsystem subsystem) throws InvalidSyntaxException, IOException, BundleException, URISyntaxException, ResolutionException {
+	private static void setExportIsolationPolicy(BasicSubsystem subsystem, Coordination coordination) throws InvalidSyntaxException, IOException, BundleException, URISyntaxException, ResolutionException {
 		if (!subsystem.isComposite())
 			return;
-		Region from = ((BasicSubsystem)subsystem.getParents().iterator().next()).getRegion();
-		Region to = subsystem.getRegion();
+		final Region from = ((BasicSubsystem)subsystem.getParents().iterator().next()).getRegion();
+		final Region to = subsystem.getRegion();
 		RegionFilterBuilder builder = from.getRegionDigraph().createRegionFilterBuilder();
 		setExportIsolationPolicy(builder, subsystem.getDeploymentManifest().getExportPackageHeader(), subsystem);
 		setExportIsolationPolicy(builder, subsystem.getDeploymentManifest().getProvideCapabilityHeader(), subsystem);
@@ -267,6 +318,18 @@ public class StartAction extends Abstrac
 			logger.debug("Establishing region connection: from=" + from
 					+ ", to=" + to + ", filter=" + regionFilter);
 		from.connectRegion(to, regionFilter);
+		coordination.addParticipant(new Participant() {
+			@Override
+			public void ended(Coordination coordination) throws Exception {
+				// Nothing.
+			}
+
+			@Override
+			public void failed(Coordination coordination) throws Exception {
+				RegionUpdater updater = new RegionUpdater(from, to);
+				updater.addRequirements(null);
+			}
+		});
 	}
 
 	private static void setExportIsolationPolicy(RegionFilterBuilder builder, ExportPackageHeader header, BasicSubsystem subsystem) throws InvalidSyntaxException {
@@ -408,4 +471,53 @@ public class StartAction extends Abstrac
 			}
 		});
 	}
+	
+	private static void handleFailedResolution(BasicSubsystem subsystem, Collection<Bundle> bundles, FrameworkWiring wiring) {
+			logFailedResolution(subsystem, bundles);
+			throw new SubsystemException("Framework could not resolve the bundles: " + bundles);
+	}
+	
+	private static void logFailedResolution(BasicSubsystem subsystem, Collection<Bundle> bundles) {
+		//work out which bundles could not be resolved
+		Collection<Bundle> unresolved = new ArrayList<Bundle>();
+		StringBuilder diagnostics = new StringBuilder();
+		diagnostics.append(String.format("Unable to resolve bundles for subsystem/version/id %s/%s/%s:\n", 
+				subsystem.getSymbolicName(), subsystem.getVersion(), subsystem.getSubsystemId()));
+		String fmt = "%d : STATE %s : %s : %s : %s";
+		for(Bundle bundle:bundles){
+			if((bundle.getState() & Bundle.RESOLVED) != Bundle.RESOLVED) {
+				unresolved.add(bundle);
+			}
+			String state = null;
+			switch(bundle.getState()) {
+				case Bundle.ACTIVE :
+					state = "ACTIVE";
+					break;
+				case Bundle.INSTALLED :
+					state = "INSTALLED";
+					break;
+				case Bundle.RESOLVED :
+					state = "RESOLVED";
+					break;
+				case Bundle.STARTING :
+					state = "STARTING";
+					break;
+				case Bundle.STOPPING :
+					state = "STOPPING";
+					break;
+				case Bundle.UNINSTALLED :
+					state = "UNINSTALLED";
+					break;
+				default :
+					//convert common states to text otherwise default to just showing the ID
+					state = "[" + Integer.toString(bundle.getState()) + "]";
+					break;
+			}
+			diagnostics.append(String.format(fmt, bundle.getBundleId(), state, 
+					bundle.getSymbolicName(), bundle.getVersion().toString(), 
+					bundle.getLocation()));
+			diagnostics.append("\n");
+		}
+		logger.error(diagnostics.toString());
+	}
 }

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=1717826&r1=1717825&r2=1717826&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 Thu Dec  3 18:25:00 2015
@@ -48,6 +48,9 @@ public class StopAction extends Abstract
 			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 (State.INSTALLING.equals(state) && !Utils.isProvisionDependenciesInstall(target)) {
+			return null;
+		}
 		else if (EnumSet.of(State.INSTALLING, State.RESOLVING, State.STARTING, State.STOPPING).contains(state)) {
 			waitForStateChange(state);
 			return new StopAction(requestor, target, disableRootCheck).run();

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemManifestValidator.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemManifestValidator.java?rev=1717826&r1=1717825&r2=1717826&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemManifestValidator.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemManifestValidator.java Thu Dec  3 18:25:00 2015
@@ -13,41 +13,70 @@
  */
 package org.apache.aries.subsystem.core.internal;
 
+import org.apache.aries.subsystem.core.archive.AriesProvisionDependenciesDirective;
 import org.apache.aries.subsystem.core.archive.PreferredProviderHeader;
+import org.apache.aries.subsystem.core.archive.ProvisionPolicyDirective;
 import org.apache.aries.subsystem.core.archive.SubsystemContentHeader;
 import org.apache.aries.subsystem.core.archive.SubsystemManifest;
+import org.apache.aries.subsystem.core.archive.SubsystemTypeHeader;
+import org.osgi.service.subsystem.Subsystem.State;
 import org.osgi.service.subsystem.SubsystemConstants;
 import org.osgi.service.subsystem.SubsystemException;
 
 public class SubsystemManifestValidator {
 	public static void validate(BasicSubsystem subsystem, SubsystemManifest manifest) {
+		if (subsystem.getResource().getId() == 0) {
+			return;
+		}
 		validatePreferredProviderHeader(manifest.getPreferredProviderHeader());
+		validateAriesProvisionDependenciesDirective(subsystem);
 		if (subsystem.isComposite()) {
 			SubsystemContentHeader header = manifest.getSubsystemContentHeader();
-			if (header == null)
+			if (header == null) {
 				return;
+			}
 			for (SubsystemContentHeader.Clause clause : header.getClauses()) {
-				if (!clause.getVersionRange().isExact())
+				if (!clause.getVersionRange().isExact()) {
 					throw new SubsystemException("Composite subsystem using version range for content: " + clause);
+				}
 			}
 		}
 		else if (subsystem.isFeature()) {
-			if (manifest.getSubsystemTypeHeader().getProvisionPolicyDirective().isAcceptDependencies())
+			SubsystemTypeHeader subsystemTypeHeader = manifest.getSubsystemTypeHeader();
+			ProvisionPolicyDirective provisionPolicyDirective = subsystemTypeHeader.getProvisionPolicyDirective();
+			if (provisionPolicyDirective.isAcceptDependencies()) {
 				throw new SubsystemException("Feature subsystems may not declare a provision-policy of acceptDependencies");
-			if (manifest.getHeaders().get(SubsystemConstants.PREFERRED_PROVIDER) != null)
+			}
+			if (manifest.getHeaders().get(SubsystemConstants.PREFERRED_PROVIDER) != null) {
 				throw new SubsystemException("Feature subsystems may not declare a " + SubsystemConstants.PREFERRED_PROVIDER + " header");
+			}
 		}
 	}
 	
 	private static void validatePreferredProviderHeader(PreferredProviderHeader header) {
-		if (header == null)
+		if (header == null) {
 			return;
+		}
 		for (PreferredProviderHeader.Clause clause : header.getClauses()) {
 			String type = (String)clause.getAttribute(PreferredProviderHeader.Clause.ATTRIBUTE_TYPE).getValue();
 			if (!(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE.equals(type) ||
 					SubsystemConstants.SUBSYSTEM_TYPE_FEATURE.equals(type) ||
-					Constants.ResourceTypeBundle.equals(type)))
+					Constants.ResourceTypeBundle.equals(type))) {
 				throw new SubsystemException("Unsupported " + PreferredProviderHeader.NAME + " type: " + type);
+			}
+		}
+	}
+	
+	private static void validateAriesProvisionDependenciesDirective(BasicSubsystem subsystem) {
+		AriesProvisionDependenciesDirective directive = subsystem.getAriesProvisionDependenciesDirective();
+		BasicSubsystem parent = subsystem.getResource().getParents().iterator().next();
+		AriesProvisionDependenciesDirective parentDirective = parent.getAriesProvisionDependenciesDirective();
+		if (!directive.equals(parentDirective) 
+				&& (subsystem.isFeature()
+						|| State.INSTALLING.equals(parent.getState()))) {
+			throw new SubsystemException("The value of the " 
+						+ AriesProvisionDependenciesDirective.NAME 
+						+ " directive must be the same as the parent subsystem for features and implicitly installed subsystems.");
 		}
 	}
 }



Mime
View raw message