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/04/12 01:26:49 UTC

svn commit: r1325064 - in /aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core: archive/ internal/ obr/

Author: jwross
Date: Wed Apr 11 23:26:48 2012
New Revision: 1325064

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

Added initial support for Preferred-Provider.

Added:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/PreferredProviderHeader.java
Removed:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/
Modified:
    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/Grammar.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/HeaderFactory.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemManifest.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypeAttribute.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/Constants.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemEnvironment.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/SubsystemResolverHook.java

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=1325064&r1=1325063&r2=1325064&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 Wed Apr 11 23:26:48 2012
@@ -17,15 +17,10 @@ import java.util.jar.Attributes;
 import java.util.jar.Manifest;
 
 import org.apache.aries.subsystem.core.internal.Activator;
-import org.apache.aries.subsystem.core.internal.AriesSubsystem;
 import org.apache.aries.subsystem.core.internal.OsgiIdentityRequirement;
 import org.apache.aries.subsystem.core.internal.SubsystemEnvironment;
 import org.apache.aries.util.manifest.ManifestProcessor;
 import org.osgi.framework.Constants;
-import org.osgi.framework.namespace.BundleNamespace;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
 import org.osgi.resource.Wire;
 import org.osgi.service.subsystem.SubsystemConstants;
@@ -106,7 +101,7 @@ public class DeploymentManifest {
 		Map<String, Header<?>> headers;
 		if (deploymentManifest == null // We're generating a new deployment manifest.
 				|| (deploymentManifest != null && overwrite)) { // A deployment manifest already exists but overwriting it with subsystem manifest content is desired.
-			headers = new HashMap<String, Header<?>>();
+			headers = computeHeaders(subsystemManifest);
 			Collection<Resource> resources = new HashSet<Resource>();
 			SubsystemContentHeader contentHeader = subsystemManifest.getSubsystemContentHeader();
 			Map<Resource, List<Wire>> resolution = null;
@@ -138,48 +133,6 @@ public class DeploymentManifest {
 				if (!provisionResource.isEmpty())
 					headers.put(PROVISION_RESOURCE, ProvisionResourceHeader.newInstance(provisionResource));
 			}
-			headers.put(SUBSYSTEM_SYMBOLICNAME, subsystemManifest.getSubsystemSymbolicNameHeader());
-			headers.put(SUBSYSTEM_VERSION, subsystemManifest.getSubsystemVersionHeader());
-			SubsystemTypeHeader typeHeader = subsystemManifest.getSubsystemTypeHeader();
-			if (typeHeader.isApplication()) {
-				if (resolution != null) {
-					Header<?> header = computeImportPackageHeader(resolution, deployedContent, acceptDependencies);
-					if (header != null)
-						headers.put(IMPORT_PACKAGE, header);
-					header = computeRequireCapabilityHeader(resolution, deployedContent, acceptDependencies);
-					if (header != null)
-						headers.put(REQUIRE_CAPABILITY, header);
-					header = computeRequireBundleHeader(resolution, deployedContent, acceptDependencies);
-					if (header != null)
-						headers.put(REQUIRE_BUNDLE, header);
-				}
-				// TODO Compute additional headers for an application.
-			}
-			else if (typeHeader.isComposite()) {
-				Header<?> header = subsystemManifest.getImportPackageHeader();
-				if (header != null)
-					headers.put(IMPORT_PACKAGE, header);
-				header = subsystemManifest.getRequireCapabilityHeader();
-				if (header != null)
-					headers.put(REQUIRE_CAPABILITY, header);
-				header = subsystemManifest.getSubsystemImportServiceHeader();
-				if (header != null)
-					headers.put(SUBSYSTEM_IMPORTSERVICE, header);
-				header = subsystemManifest.getRequireBundleHeader();
-				if (header != null)
-					headers.put(REQUIRE_BUNDLE, header);
-				header = subsystemManifest.getExportPackageHeader();
-				if (header != null)
-					headers.put(EXPORT_PACKAGE, header);
-				header = subsystemManifest.getProvideCapabilityHeader();
-				if (header != null)
-					headers.put(PROVIDE_CAPABILITY, header);
-				header = subsystemManifest.getSubsystemExportServiceHeader();
-				if (header != null)
-					headers.put(SUBSYSTEM_EXPORTSERVICE, header);
-				// TODO Compute additional headers for a composite. 
-			}
-			// Features require no additional headers.
 		}
 		else {
 			headers = new HashMap<String, Header<?>>(deploymentManifest.getHeaders());
@@ -248,88 +201,7 @@ public class DeploymentManifest {
 		manifest.write(out);
 	}
 	
-	private static ImportPackageHeader computeImportPackageHeader(
-			Map<Resource, List<Wire>> resolution, 
-			Collection<Resource> content,
-			boolean acceptDependencies) {
-		Collection<ImportPackageHeader.Clause> clauses = new ArrayList<ImportPackageHeader.Clause>();
-		for (Entry<Resource, List<Wire>> entry : resolution.entrySet()) {
-			for (Wire wire : entry.getValue()) {
-				Resource provider = wire.getProvider();
-				if (content.contains(provider))
-					// If the provider is a content resource, we don't need an import.
-					continue;
-				// The provider is a dependency that is already provisioned or needs provisioning.
-				if (acceptDependencies && !((provider instanceof BundleRevision) || (provider instanceof AriesSubsystem)))
-					// If the application accepts dependencies and the provider is a dependency that needs provisioning,
-					// we don't need an import.
-					continue;
-				// For all other cases, we need an import.
-				Requirement requirement = wire.getRequirement();
-				if (PackageNamespace.PACKAGE_NAMESPACE.equals(requirement.getNamespace())) {
-					clauses.add(new ImportPackageHeader.Clause(requirement));
-				}
-			}
-		}
-		if (clauses.isEmpty())
-			return null;
-		return new ImportPackageHeader(clauses);
-	}
-	
-	private static RequireBundleHeader computeRequireBundleHeader(
-			Map<Resource, List<Wire>> resolution, 
-			Collection<Resource> content,
-			boolean acceptDependencies) {
-		Collection<RequireBundleHeader.Clause> clauses = new ArrayList<RequireBundleHeader.Clause>();
-		for (Entry<Resource, List<Wire>> entry : resolution.entrySet()) {
-			for (Wire wire : entry.getValue()) {
-				Resource provider = wire.getProvider();
-				if (content.contains(provider))
-					// If the provider is a content resource, we don't need an import.
-					continue;
-				// The provider is a dependency that is already provisioned or needs provisioning.
-				if (acceptDependencies && !((provider instanceof BundleRevision) || (provider instanceof AriesSubsystem)))
-					// If the application accepts dependencies and the provider is a dependency that needs provisioning,
-					// we don't need an import.
-					continue;
-				// For all other cases, we need an import.
-				Requirement requirement = wire.getRequirement();
-				if (BundleNamespace.BUNDLE_NAMESPACE.equals(requirement.getNamespace())) {
-					clauses.add(new RequireBundleHeader.Clause(requirement));
-				}
-			}
-		}
-		if (clauses.isEmpty())
-			return null;
-		return new RequireBundleHeader(clauses);
-	}
-	
-	private static RequireCapabilityHeader computeRequireCapabilityHeader(
-			Map<Resource, List<Wire>> resolution, 
-			Collection<Resource> content,
-			boolean acceptDependencies) {
-		Collection<RequireCapabilityHeader.Clause> clauses = new ArrayList<RequireCapabilityHeader.Clause>();
-		for (Entry<Resource, List<Wire>> entry : resolution.entrySet()) {
-			for (Wire wire : entry.getValue()) {
-				Resource provider = wire.getProvider();
-				if (content.contains(provider))
-					// If the provider is a content resource, we don't need an imported capability.
-					continue;
-				// The provider is a dependency that is already provisioned or needs provisioning.
-				if (acceptDependencies && !((provider instanceof BundleRevision) || (provider instanceof AriesSubsystem)))
-					// If the application accepts dependencies and the provider is a dependency that needs provisioning,
-					// we don't need an import.
-					continue;
-				// For all other cases, we need an import.
-				Requirement requirement = wire.getRequirement();
-				// TODO Not sure if the startsWith check will be sufficient.
-				if (!requirement.getNamespace().startsWith("osgi.")) {
-					clauses.add(new RequireCapabilityHeader.Clause(requirement));
-				}
-			}
-		}
-		if (clauses.isEmpty())
-			return null;
-		return new RequireCapabilityHeader(clauses);
+	private Map<String, Header<?>> computeHeaders(SubsystemManifest manifest) {
+		return new HashMap<String, Header<?>>(manifest.getHeaders());
 	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java?rev=1325064&r1=1325063&r2=1325064&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java Wed Apr 11 23:26:48 2012
@@ -137,6 +137,9 @@ public interface Grammar {
 	public static final String SUBSYSTEM_EXPORTSERVICE = SERVICE + "(?:,\\s*(?:" + SERVICE + "))*";
 	public static final String SUBSYSTEM_IMPORTSERVICE = SERVICE + "(?:,\\s*(?:" + SERVICE + "))*";
 	
+	public static final String RESOURCE = SYMBOLICNAME + "(?:;\\s*(?:" + PARAMETER + "))*";
+	public static final String PREFERRED_PROVIDER = RESOURCE + "(?:,\\s*(?:" + RESOURCE + "))*";
+	
 	/*
 	 * number ::= digit+
 	 * version ::= major( '.' minor ( '.' micro ( '.' qualifier )? )? )?

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/HeaderFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/HeaderFactory.java?rev=1325064&r1=1325063&r2=1325064&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/HeaderFactory.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/HeaderFactory.java Wed Apr 11 23:26:48 2012
@@ -109,6 +109,8 @@ public class HeaderFactory {
 			return new BundleSymbolicNameHeader(value);
 		if (BundleVersionHeader.NAME.equals(name))
 			return new BundleVersionHeader(value);
+		if (PreferredProviderHeader.NAME.equals(name))
+			return new PreferredProviderHeader(value);
 		return new GenericHeader(name, value);
 			
 	}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/PreferredProviderHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/PreferredProviderHeader.java?rev=1325064&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/PreferredProviderHeader.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/PreferredProviderHeader.java Wed Apr 11 23:26:48 2012
@@ -0,0 +1,208 @@
+package org.apache.aries.subsystem.core.archive;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.aries.subsystem.core.ResourceHelper;
+import org.osgi.framework.VersionRange;
+import org.osgi.resource.Resource;
+import org.osgi.service.subsystem.SubsystemConstants;
+
+public class PreferredProviderHeader implements RequirementHeader<PreferredProviderHeader.Clause> {
+	public static class Clause implements org.apache.aries.subsystem.core.archive.Clause {
+		public static final String ATTRIBUTE_TYPE = TypeAttribute.NAME;
+		public static final String ATTRIBUTE_VERSION = VersionAttribute.NAME;
+		
+		private static final Pattern PATTERN_SYMBOLICNAME = Pattern.compile('(' + Grammar.SYMBOLICNAME + ")(?=;|\\z)");
+		private static final Pattern PATTERN_PARAMETER = Pattern.compile('(' + Grammar.PARAMETER + ")(?=;|\\z)");
+		
+		private static void fillInDefaults(Map<String, Parameter> parameters) {
+			Parameter parameter = parameters.get(ATTRIBUTE_VERSION);
+			if (parameter == null)
+				parameters.put(ATTRIBUTE_VERSION, VersionAttribute.DEFAULT);
+			parameter = parameters.get(ATTRIBUTE_TYPE);
+			if (parameter == null)
+				parameters.put(ATTRIBUTE_TYPE, TypeAttribute.newInstance(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE));
+		}
+		
+		private final String path;
+		private final Map<String, Parameter> parameters = new HashMap<String, Parameter>();
+		
+		public Clause(String clause) {
+			Matcher matcher = PATTERN_SYMBOLICNAME.matcher(clause);
+			if (!matcher.find())
+				throw new IllegalArgumentException("Missing resource path: " + clause);
+			path = matcher.group();
+			matcher.usePattern(PATTERN_PARAMETER);
+			while (matcher.find()) {
+				Parameter parameter = ParameterFactory.create(matcher.group());
+				parameters.put(parameter.getName(), parameter);
+			}
+			fillInDefaults(parameters);
+		}
+		
+		public boolean contains(Resource resource) {
+			return getSymbolicName().equals(
+					ResourceHelper.getSymbolicNameAttribute(resource))
+					&& getVersionRange().includes(
+							ResourceHelper.getVersionAttribute(resource))
+					&& getType().equals(
+							ResourceHelper.getTypeAttribute(resource));
+		}
+		
+		@Override
+		public Attribute getAttribute(String name) {
+			Parameter result = parameters.get(name);
+			if (result instanceof Attribute) {
+				return (Attribute)result;
+			}
+			return null;
+		}
+
+		@Override
+		public Collection<Attribute> getAttributes() {
+			ArrayList<Attribute> attributes = new ArrayList<Attribute>(parameters.size());
+			for (Parameter parameter : parameters.values()) {
+				if (parameter instanceof Attribute) {
+					attributes.add((Attribute)parameter);
+				}
+			}
+			attributes.trimToSize();
+			return attributes;
+		}
+
+		@Override
+		public Directive getDirective(String name) {
+			Parameter result = parameters.get(name);
+			if (result instanceof Directive) {
+				return (Directive)result;
+			}
+			return null;
+		}
+
+		@Override
+		public Collection<Directive> getDirectives() {
+			ArrayList<Directive> directives = new ArrayList<Directive>(parameters.size());
+			for (Parameter parameter : parameters.values()) {
+				if (parameter instanceof Directive) {
+					directives.add((Directive)parameter);
+				}
+			}
+			directives.trimToSize();
+			return directives;
+		}
+
+		@Override
+		public Parameter getParameter(String name) {
+			return parameters.get(name);
+		}
+
+		@Override
+		public Collection<Parameter> getParameters() {
+			return Collections.unmodifiableCollection(parameters.values());
+		}
+
+		@Override
+		public String getPath() {
+			return path;
+		}
+		
+		public String getSymbolicName() {
+			return path;
+		}
+		
+		public String getType() {
+			return (String)getAttribute(ATTRIBUTE_TYPE).getValue();
+		}
+		
+		public VersionRange getVersionRange() {
+			Attribute attribute = getAttribute(ATTRIBUTE_VERSION);
+			if (attribute instanceof VersionRangeAttribute)
+				return ((VersionRangeAttribute)attribute).getVersionRange();
+			return new VersionRange(attribute.getValue().toString());
+		}
+		
+		@Override
+		public String toString() {
+			StringBuilder builder = new StringBuilder()
+					.append(getPath());
+			for (Parameter parameter : getParameters()) {
+				builder.append(';').append(parameter);
+			}
+			return builder.toString();
+		}
+	}
+	
+	public static final String NAME = SubsystemConstants.PREFERRED_PROVIDER;
+
+	private static final Pattern PATTERN = Pattern.compile('(' + Grammar.PREFERRED_PROVIDER + ")(?=,|\\z)");
+	
+	private static Collection<Clause> processHeader(String header) {
+		Matcher matcher = PATTERN.matcher(header);
+		Set<Clause> clauses = new HashSet<Clause>();
+		while (matcher.find())
+			clauses.add(new Clause(matcher.group()));
+		return clauses;
+	}
+	
+	private final Set<Clause> clauses;
+	
+	public PreferredProviderHeader(Collection<Clause> clauses) {
+		if (clauses.isEmpty())
+			throw new IllegalArgumentException("A " + NAME + " header must have at least one clause");
+		this.clauses = new HashSet<Clause>(clauses);
+	}
+	
+	public PreferredProviderHeader(String value) {
+		this(processHeader(value));
+	}
+	
+	public boolean contains(Resource resource) {
+		for (Clause clause : getClauses())
+			if (clause.contains(resource))
+				return true;
+		return false;
+	}
+	
+	@Override
+	public Collection<PreferredProviderHeader.Clause> getClauses() {
+		return Collections.unmodifiableSet(clauses);
+	}
+
+	@Override
+	public String getName() {
+		return NAME;
+	}
+
+	@Override
+	public String getValue() {
+		return toString();
+	}
+	
+	@Override
+	public List<RequireBundleRequirement> toRequirements(Resource resource) {
+		List<RequireBundleRequirement> requirements = new ArrayList<RequireBundleRequirement>(clauses.size());
+//		for (Clause clause : clauses)
+//			requirements.add(clause.toRequirement(resource));
+		return requirements;
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		for (Clause clause : getClauses()) {
+			builder.append(clause).append(',');
+		}
+		// Remove the trailing comma. Note at least one clause is guaranteed to exist.
+		builder.deleteCharAt(builder.length() - 1);
+		return builder.toString();
+	}
+}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemManifest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemManifest.java?rev=1325064&r1=1325063&r2=1325064&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemManifest.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemManifest.java Wed Apr 11 23:26:48 2012
@@ -183,6 +183,10 @@ public class SubsystemManifest {
 		return (ImportPackageHeader)getHeaders().get(IMPORT_PACKAGE);
 	}
 	
+	public PreferredProviderHeader getPreferredProviderHeader() {
+		return (PreferredProviderHeader)getHeaders().get(PREFERRED_PROVIDER);
+	}
+	
 	public ProvideCapabilityHeader getProvideCapabilityHeader() {
 		return (ProvideCapabilityHeader)getHeaders().get(PROVIDE_CAPABILITY);
 	}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypeAttribute.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypeAttribute.java?rev=1325064&r1=1325063&r2=1325064&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypeAttribute.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypeAttribute.java Wed Apr 11 23:26:48 2012
@@ -13,10 +13,12 @@
  */
 package org.apache.aries.subsystem.core.archive;
 
+import org.osgi.framework.namespace.IdentityNamespace;
+
 public class TypeAttribute extends AbstractAttribute {
 	public static final TypeAttribute DEFAULT = new TypeAttribute();
 	// TODO Add to constants.
-	public static final String DEFAULT_VALUE = "osgi.bundle";
+	public static final String DEFAULT_VALUE = IdentityNamespace.TYPE_BUNDLE;
 	// TODO Add to constants.
 	public static final String NAME = "type";
 	

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=1325064&r1=1325063&r2=1325064&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 Wed Apr 11 23:26:48 2012
@@ -857,11 +857,10 @@ public class AriesSubsystem implements S
 	}
 	
 	private DeploymentManifest getDeploymentManifest() throws IOException, URISyntaxException {
-//		if (archive.getDeploymentManifest() == null) {
+		if (archive.getDeploymentManifest() == null)
 			archive.setDeploymentManifest(new DeploymentManifest(
 					archive.getDeploymentManifest(),
 					archive.getSubsystemManifest(), 
-//					environment,
 					new SubsystemEnvironment(this),
 					autostart,
 					id,
@@ -869,11 +868,12 @@ public class AriesSubsystem implements S
 					location,
 					true,
 					false));
-//		}
 		return archive.getDeploymentManifest();
 	}
 	
 	private synchronized void install(Coordination coordination, AriesSubsystem parent) throws Exception {
+		if (!State.INSTALLING.equals(getState()))
+			return;
 		if (!isFeature())
 			RegionContextBundleHelper.installRegionContextBundle(this);
 		Activator.getInstance().getSubsystemServiceRegistrar().register(this, parent);

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=1325064&r1=1325063&r2=1325064&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 Wed Apr 11 23:26:48 2012
@@ -1,9 +1,13 @@
 package org.apache.aries.subsystem.core.internal;
 
+import org.osgi.framework.namespace.IdentityNamespace;
+
 public class Constants {
 	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.";
+	public static final String ResourceTypeBundle = IdentityNamespace.TYPE_BUNDLE;
+	public static final String ResourceTypeFragment = IdentityNamespace.TYPE_FRAGMENT;
 	public static final String SubsystemServicePropertyRegions = "org.apache.aries.subsystem.service.regions";
 	
 	private Constants() {}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemEnvironment.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemEnvironment.java?rev=1325064&r1=1325063&r2=1325064&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemEnvironment.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemEnvironment.java Wed Apr 11 23:26:48 2012
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.SortedSet;
@@ -28,6 +27,7 @@ import java.util.TreeSet;
 
 import org.apache.aries.subsystem.core.Environment;
 import org.apache.aries.subsystem.core.ResourceHelper;
+import org.apache.aries.subsystem.core.archive.PreferredProviderHeader;
 import org.eclipse.equinox.region.Region;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -48,6 +48,64 @@ import org.slf4j.LoggerFactory;
  * So does the locating of providers for feature content with respect to children of the first parent that is not a feature.
  */
 public class SubsystemEnvironment implements Environment {
+	private static final class Comparator implements java.util.Comparator<Capability> {
+		private final AriesSubsystem subsystem;
+		
+		public Comparator(AriesSubsystem subsystem) {
+			this.subsystem = subsystem;
+		}
+		
+		@Override
+		public int compare(Capability c1, Capability c2) {
+			if (logger.isDebugEnabled())
+				logger.debug(LOG_ENTRY, "compare", new Object[]{c1, c2});
+			int result = comparePreferredProvider(c1, c2);
+			if (result == 0)
+				result = compareRuntimeResource(c1, c2);
+			logger.debug(LOG_EXIT, "compare", result);
+			return result;
+		}
+		
+		private int comparePreferredProvider(Capability c1, Capability c2) {
+			boolean pp1 = isPreferredProvider(c1);
+			boolean pp2 = isPreferredProvider(c2);
+			if (pp1 && !pp2)
+				return -1;
+			else if (!pp1 && pp2)
+				return 1;
+			return 0;
+		}
+		
+		private int compareRuntimeResource(Capability c1, Capability c2) {
+			boolean rr1 = isRuntimeResource(c1);
+			boolean rr2 = isRuntimeResource(c2);
+			if (rr1 && !rr2)
+				return -1;
+			else if (!rr1 && rr2)
+				return 1;
+			return 0;
+		}
+		
+		private boolean isPreferredProvider(Resource resource) {
+			PreferredProviderHeader header = subsystem.getArchive().getSubsystemManifest().getPreferredProviderHeader();
+			if (header == null)
+				return false;
+			return header.contains(resource);
+		}
+		
+		private boolean isPreferredProvider(Capability capability) {
+			return isPreferredProvider(capability.getResource());
+		}
+		
+		private boolean isRuntimeResource(Resource resource) {
+			return resource instanceof BundleRevision || resource instanceof AriesSubsystem;
+		}
+		
+		private boolean isRuntimeResource(Capability capability) {
+			return isRuntimeResource(capability.getResource());
+		}
+	}
+	
 	private static final Logger logger = LoggerFactory.getLogger(SubsystemEnvironment.class);
 	
 //	private final Set<Resource> resources = new HashSet<Resource>();
@@ -71,23 +129,7 @@ public class SubsystemEnvironment implem
 	public SortedSet<Capability> findProviders(Requirement requirement) {
 		logger.debug(LOG_ENTRY, "findProviders", requirement);
 		// TODO Need a more robust comparator. This is just a temporary place holder.
-		SortedSet<Capability> capabilities = new TreeSet<Capability>(
-				new Comparator<Capability>() {
-					@Override
-					public int compare(Capability capability1, Capability capability2) {
-						if (logger.isDebugEnabled())
-							logger.debug(LOG_ENTRY, "compare", new Object[]{capability1, capability2});
-						int result = 0;
-						boolean br1 = capability1.getResource() instanceof BundleRevision;
-						boolean br2 = capability2.getResource() instanceof BundleRevision;
-						if (br1 && !br2)
-							result = -1;
-						else if (!br1 && br2)
-							result = 1;
-						logger.debug(LOG_EXIT, "compare", result);
-						return result;
-					}
-				});
+		SortedSet<Capability> capabilities = new TreeSet<Capability>(new Comparator(subsystem));
 		if (requirement instanceof OsgiIdentityRequirement) { 
 			logger.debug("The requirement is an instance of OsgiIdentityRequirement");
 			// TODO Consider returning only the first capability matched by the requirement in this case.

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=1325064&r1=1325063&r2=1325064&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 Wed Apr 11 23:26:48 2012
@@ -1,5 +1,6 @@
 package org.apache.aries.subsystem.core.internal;
 
+import org.apache.aries.subsystem.core.archive.PreferredProviderHeader;
 import org.apache.aries.subsystem.core.archive.SubsystemContentHeader;
 import org.apache.aries.subsystem.core.archive.SubsystemManifest;
 import org.osgi.framework.VersionRange;
@@ -8,6 +9,7 @@ import org.osgi.service.subsystem.Subsys
 
 public class SubsystemManifestValidator {
 	public static void validate(AriesSubsystem subsystem, SubsystemManifest manifest) {
+		validatePreferredProviderHeader(manifest.getPreferredProviderHeader());
 		if (subsystem.isComposite()) {
 			SubsystemContentHeader header = manifest.getSubsystemContentHeader();
 			if (header == null)
@@ -26,6 +28,7 @@ public class SubsystemManifestValidator 
 		}
 	}
 	
+	// TODO Replace this with the new isExact() method on OSGi VersionRange.
 	private static boolean isExactVersion(VersionRange range) {
 		if (range.getLeftType() == VersionRange.LEFT_CLOSED
 		          && range.getLeft().equals(range.getRight())
@@ -34,4 +37,16 @@ public class SubsystemManifestValidator 
 		}
 		return false;
 	}
+	
+	private static void validatePreferredProviderHeader(PreferredProviderHeader header) {
+		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)))
+				throw new SubsystemException("Unsupported " + PreferredProviderHeader.NAME + " type: " + type);
+		}
+	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResolverHook.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResolverHook.java?rev=1325064&r1=1325063&r2=1325064&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResolverHook.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResolverHook.java Wed Apr 11 23:26:48 2012
@@ -13,13 +13,16 @@
  */
 package org.apache.aries.subsystem.core.internal;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 
+import org.apache.aries.subsystem.core.archive.PreferredProviderHeader;
 import org.osgi.framework.hooks.resolver.ResolverHook;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRequirement;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.resource.Resource;
 import org.osgi.service.subsystem.Subsystem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,7 +35,24 @@ public class SubsystemResolverHook imple
 	}
 
 	public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) {
-		// noop
+		// Filter out candidates that don't come from preferred providers when
+		// there is at least one preferred provider.
+		// (1) Find the subsystem(s) containing requirement.getResource() as a
+		// constituent.
+		Collection<AriesSubsystem> requirers = AriesSubsystem.getSubsystems(requirement.getResource());
+		// (2) For each candidate, ask each subsystem if the candidate or any of
+		// the candidate's containing subsystems is a preferred provider. If at
+		// least one preferred provider exists, filter out all other candidates
+		// that are not also preferred providers.
+		Collection<BundleCapability> preferredProviders = new ArrayList<BundleCapability>(candidates.size());
+		for (BundleCapability candidate : candidates)
+			for (AriesSubsystem subsystem : requirers) {
+				PreferredProviderHeader header = subsystem.getArchive().getSubsystemManifest().getPreferredProviderHeader();
+				if (header != null && (header.contains(candidate.getResource()) || isResourceConstituentOfPreferredSubsystem(candidate.getResource(), subsystem)))
+					preferredProviders.add(candidate);
+			}
+		if (!preferredProviders.isEmpty())
+			candidates.retainAll(preferredProviders);
 	}
 
 	public void filterResolvable(Collection<BundleRevision> candidates) {
@@ -65,4 +85,12 @@ public class SubsystemResolverHook imple
 	public void filterSingletonCollisions(BundleCapability singleton, Collection<BundleCapability> collisionCandidates) {
 		// noop
 	}
+	
+	private boolean isResourceConstituentOfPreferredSubsystem(Resource resource, AriesSubsystem preferer) {
+		Collection<AriesSubsystem> subsystems = AriesSubsystem.getSubsystems(resource);
+		for (AriesSubsystem subsystem : subsystems)
+			if (preferer.getArchive().getSubsystemManifest().getPreferredProviderHeader().contains(subsystem))
+				return true;
+		return false;
+	}
 }