You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by jw...@apache.org on 2012/02/23 20:36:51 UTC

svn commit: r1292916 - 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/main/java/org/apache/felix/resolver/imp...

Author: jwross
Date: Thu Feb 23 19:36:50 2012
New Revision: 1292916

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

(1) Subsystem resources are disabled for resolution only in the INSTALLING state, not the INSTALLED state.
(2) Import isolation policy is set as part of installation after entering INSTALLED state, not at resolution time.
(3) Fixed a couple of issues in the local copy of the felix resolver.
	(a) Util.isOptional returns true for mandatory requirements.
	(b) Util.isFragment always returns false.
(4) Added initial support for generation of Import-Package header for applications.
(5) Added new application test.
(6) Updated subsystem pom with pointers to updated dependencies.

Added:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/FilterDirective.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageRequirement.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestCapability.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepository.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepositoryContent.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestResource.java
Removed:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeploymentManifestFactory.java
Modified:
    aries/trunk/subsystem/pom.xml
    aries/trunk/subsystem/readme.txt
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DeploymentManifest.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageHeader.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/SubsystemResolverHook.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Util.java
    aries/trunk/subsystem/subsystem-itests/pom.xml
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/ApplicationTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java
    aries/trunk/subsystem/subsystem-itests/src/test/resources/application1/OSGI-INF/SUBSYSTEM.MF

Modified: aries/trunk/subsystem/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/pom.xml?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/pom.xml (original)
+++ aries/trunk/subsystem/pom.xml Thu Feb 23 19:36:50 2012
@@ -172,14 +172,14 @@
                                     <artifactId>org.eclipse.osgi</artifactId>
                                     <version>3.8.0-SNAPSHOT</version>
                                     <packaging>jar</packaging>
-                                    <downloadUrl>http://www.eclipse.org/downloads/download.php?file=/equinox/drops/S-3.8M5-201201251800/org.eclipse.osgi_3.8.0.v20120123-1419.jar&amp;url=http://download.eclipse.org/equinox/drops/S-3.8M5-201201251800/org.eclipse.osgi_3.8.0.v20120123-1419.jar&amp;mirror_id=1</downloadUrl>
+                                    <downloadUrl>http://www.eclipse.org/downloads/download.php?file=/equinox/drops/N20120222-2000/org.eclipse.osgi_3.8.0.N20120222-2000.jar&amp;url=http://download.eclipse.org/equinox/drops/N20120222-2000/org.eclipse.osgi_3.8.0.N20120222-2000.jar&amp;mirror_id=1</downloadUrl>
                                 </artifactItem>
                                 <artifactItem>
                                     <groupId>org.eclipse.equinox</groupId>
                                     <artifactId>org.eclipse.equinox.coordinator</artifactId>
                                     <version>3.8.0-SNAPSHOT</version>
                                     <packaging>jar</packaging>
-                                    <downloadUrl>http://www.eclipse.org/downloads/download.php?file=/equinox/drops/S-3.8M5-201201251800/org.eclipse.equinox.coordinator_1.1.0.v20111117-1150.jar&amp;url=http://download.eclipse.org/equinox/drops/S-3.8M5-201201251800/org.eclipse.equinox.coordinator_1.1.0.v20111117-1150.jar&amp;mirror_id=1</downloadUrl>
+                                    <downloadUrl>http://www.eclipse.org/downloads/download.php?file=/equinox/drops/N20120222-2000/org.eclipse.equinox.coordinator_1.1.0.N20120222-2000.jar&amp;url=http://download.eclipse.org/equinox/drops/N20120222-2000/org.eclipse.equinox.coordinator_1.1.0.N20120222-2000.jar&amp;mirror_id=1</downloadUrl>
                                 </artifactItem>
                                 <artifactItem>
                                     <groupId>org.eclipse.equinox</groupId>

Modified: aries/trunk/subsystem/readme.txt
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/readme.txt?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/readme.txt (original)
+++ aries/trunk/subsystem/readme.txt Thu Feb 23 19:36:50 2012
@@ -1,12 +1,3 @@
-***** NOTE ON CURRENT STATUS *****
-Recent changes require updated jars of org.eclipse.osgi and 
-org.eclipse.equinox.coordinator in your local m2 repository in order to build
-successfully. These jars are not yet available from a public repository but will
-be soon. In the meantime, if you require a successful subsystems build (note 
-that subsystems is not included as part of the normal Aries build), please 
-contact me for copies of these jars (jwross@us.ibm.com).
-***** END NOTE ON CURRENT STATUS *****
-
 The Subsystems subproject uses some unreleased and difficult to find equinox 
 artifacts.
 

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=1292916&r1=1292915&r2=1292916&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 Thu Feb 23 19:36:50 2012
@@ -16,14 +16,17 @@ import java.util.Map.Entry;
 import java.util.jar.Attributes;
 import java.util.jar.Manifest;
 
-import org.apache.aries.subsystem.core.Resolver;
 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.obr.SubsystemEnvironment;
 import org.apache.aries.util.manifest.ManifestProcessor;
 import org.osgi.framework.Constants;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.resource.Requirement;
 import org.osgi.framework.resource.Resource;
 import org.osgi.framework.resource.Wire;
+import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.service.subsystem.SubsystemConstants;
 import org.osgi.service.subsystem.SubsystemException;
 
@@ -65,13 +68,16 @@ public class DeploymentManifest {
 			long id, 
 			long lastId, 
 			String location,
-			boolean overwrite) {
+			boolean overwrite,
+			boolean acceptDependencies) {
 		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<?>>();
 			Collection<Resource> resources = new HashSet<Resource>();
 			SubsystemContentHeader contentHeader = subsystemManifest.getSubsystemContentHeader();
+			Map<Resource, List<Wire>> resolution = null;
+			Collection<Resource> deployedContent = new HashSet<Resource>();
 			if (contentHeader != null) {
 				for (SubsystemContentHeader.Content content : contentHeader.getContents()) {
 					OsgiIdentityRequirement requirement = new OsgiIdentityRequirement(content.getName(), content.getVersionRange(), content.getType(), false);
@@ -85,9 +91,8 @@ public class DeploymentManifest {
 					resources.add(resource);
 				}
 				// TODO This does not validate that all content bundles were found.
-				Map<Resource, List<Wire>> resolution = Activator.getInstance().getResolver().resolve(environment, new ArrayList<Resource>(resources), Collections.EMPTY_LIST);
+				resolution = Activator.getInstance().getResolver().resolve(environment, new ArrayList<Resource>(resources), Collections.EMPTY_LIST);
 				// TODO Once we have a resolver that actually returns lists of wires, we can use them to compute other manifest headers such as Import-Package.
-				Collection<Resource> deployedContent = new HashSet<Resource>();
 				Collection<Resource> provisionResource = new HashSet<Resource>();
 				for (Resource resource : resolution.keySet()) {
 					if (contentHeader.contains(resource))
@@ -105,6 +110,8 @@ public class DeploymentManifest {
 			headers.put(SUBSYSTEM_VERSION, subsystemManifest.getSubsystemVersionHeader());
 			SubsystemTypeHeader typeHeader = subsystemManifest.getSubsystemTypeHeader();
 			if (SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION.equals(typeHeader.getValue())) {
+				if (resolution != null)
+					headers.put(IMPORT_PACKAGE, computeImportPackageHeader(resolution, deployedContent, acceptDependencies));
 				// TODO Compute additional headers for an application.
 			}
 			// TODO Add to constants.
@@ -132,6 +139,10 @@ public class DeploymentManifest {
 		return headers;
 	}
 	
+	public ImportPackageHeader getImportPackageHeader() {
+		return (ImportPackageHeader)getHeaders().get(IMPORT_PACKAGE);
+	}
+	
 	public ProvisionResourceHeader getProvisionResourceHeader() {
 		return (ProvisionResourceHeader)getHeaders().get(PROVISION_RESOURCE);
 	}
@@ -146,4 +157,30 @@ 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 ImportPackageRequirement(requirement).toClause());
+				}
+			}
+		}
+		return new ImportPackageHeader(clauses);
+	}
 }

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=1292916&r1=1292915&r2=1292916&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 Feb 23 19:36:50 2012
@@ -19,6 +19,8 @@ public class DirectiveFactory {
 			return ResolutionDirective.getInstance(value);
 		if (StartOrderDirective.NAME.equals(name))
 			return new StartOrderDirective(value);
+		if (FilterDirective.NAME.equals(name))
+			return new FilterDirective(value);
 		return new GenericDirective(name, value);
 	}
 }

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/FilterDirective.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/FilterDirective.java?rev=1292916&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/FilterDirective.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/FilterDirective.java Thu Feb 23 19:36:50 2012
@@ -0,0 +1,28 @@
+package org.apache.aries.subsystem.core.archive;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+
+public class FilterDirective extends AbstractDirective {
+	public static final String NAME = Constants.FILTER_DIRECTIVE;
+	
+	public FilterDirective(String value) {
+		super(NAME, value);
+		try {
+			FrameworkUtil.createFilter(value);
+		}
+		catch (InvalidSyntaxException e) {
+			throw new IllegalArgumentException("Invalid filter: " + value, e);
+		}
+	}
+
+	public String toString() {
+		return new StringBuilder()
+		.append(getName())
+		.append(":=\"")
+		.append(getValue())
+		.append('\"')
+		.toString();
+	}
+}

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=1292916&r1=1292915&r2=1292916&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 Thu Feb 23 19:36:50 2012
@@ -115,7 +115,7 @@ public interface Grammar {
 	public static final String SYMBOLICNAME = TOKEN + "(?:\\." + TOKEN + ")*";
 	public static final String PACKAGENAME = UNIQUENAME;
 	public static final String PACKAGENAMES = PACKAGENAME + "(?:\\;" + PACKAGENAME + ")*";
-	public static final String IMPORT = PACKAGENAMES + "(?:\\;" + Grammar.PARAMETER + ")*";
+	public static final String IMPORT = PACKAGENAMES + "(?:;(?:" + PARAMETER + "))*";
 	public static final String IMPORTPACKAGE = IMPORT + "(?:\\," + IMPORT + ")*";
 	
 	/*

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageHeader.java?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageHeader.java Thu Feb 23 19:36:50 2012
@@ -20,56 +20,55 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.resource.Capability;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.resource.Requirement;
 import org.osgi.framework.resource.Resource;
 import org.osgi.framework.wiring.BundleRevision;
 
 public class ImportPackageHeader implements Header<ImportPackageHeader.Clause> {
 	public static class Clause implements org.apache.aries.subsystem.core.archive.Clause {
-		private static final String REGEX = '(' + Grammar.PACKAGENAMES + ")(?:\\;(" + Grammar.PARAMETER + "))*";
-		private static final Pattern PATTERN = Pattern.compile(REGEX);
+		private static final String REGEX1 = '(' + Grammar.PACKAGENAMES + ")(?=;|\\z)";
+		private static final String REGEX2 = '(' + Grammar.PARAMETER + ")(?=;|\\z)";
+		private static final Pattern PATTERN1 = Pattern.compile(REGEX1);
+		private static final Pattern PATTERN2 = Pattern.compile(REGEX2);
 		
 		private final Map<String, Parameter> myParameters = new HashMap<String, Parameter>();
 		private final String myPath;
 		
 		public Clause(String clause) {
-			Matcher matcher = PATTERN.matcher(clause);
-			if (!matcher.matches()) {
+			Matcher matcher = PATTERN1.matcher(clause);
+			if (matcher.find())
+				myPath = matcher.group();
+			else
 				throw new IllegalArgumentException("Invalid " + Constants.IMPORT_PACKAGE + " header clause: " + clause);
-			}
-			myPath = matcher.group(1);
-			for (int i = 2; i <= matcher.groupCount(); i++) {
-				String group = matcher.group(i);
-				if (group != null) {
-					Parameter parameter = ParameterFactory.create(group);
-					myParameters.put(parameter.getName(), parameter);
-				}
-			}
-			Attribute attribute = new GenericAttribute(BundleRevision.PACKAGE_NAMESPACE, getPath());
-			myParameters.put(attribute.getName(), attribute);
-			attribute = getAttribute(Constants.VERSION_ATTRIBUTE);
-			if (attribute == null) {
-				attribute = new VersionRangeAttribute();
-				myParameters.put(attribute.getName(), attribute);
-			}
-			Directive directive = getDirective(Constants.FILTER_DIRECTIVE);
-			if (directive == null) {
-				StringBuilder builder = new StringBuilder("(&");
-				for (Attribute a : getAttributes()) {
-					a.appendToFilter(builder);
-				}
-				directive = new GenericDirective(Constants.FILTER_DIRECTIVE, builder.append(')').toString());
-				myParameters.put(directive.getName(), directive);
-			}
+			matcher.usePattern(PATTERN2);
+			while (matcher.find()) {
+				Parameter parameter = ParameterFactory.create(matcher.group());
+				myParameters.put(parameter.getName(), parameter);
+			}
+//			Attribute attribute = new GenericAttribute(BundleRevision.PACKAGE_NAMESPACE, getPath());
+//			myParameters.put(attribute.getName(), attribute);
+//			attribute = getAttribute(Constants.VERSION_ATTRIBUTE);
+//			if (attribute == null) {
+//				attribute = new VersionRangeAttribute();
+//				myParameters.put(attribute.getName(), attribute);
+//			}
+//			Directive directive = getDirective(Constants.FILTER_DIRECTIVE);
+//			if (directive == null) {
+//				StringBuilder builder = new StringBuilder("(&");
+//				for (Attribute a : getAttributes()) {
+//					a.appendToFilter(builder);
+//				}
+//				directive = new GenericDirective(Constants.FILTER_DIRECTIVE, builder.append(')').toString());
+//				myParameters.put(directive.getName(), directive);
+//			}
 		}
 		
 		public Attribute getAttribute(String name) {
@@ -128,47 +127,43 @@ public class ImportPackageHeader impleme
 		
 		public Requirement getRequirement(final Resource resource) {
 			return new Requirement() {
+				@Override
 				public String getNamespace() {
 					return BundleRevision.PACKAGE_NAMESPACE;
 				}
-
+				@Override
 				public Map<String, String> getDirectives() {
 					Collection<Directive> directives = Clause.this.getDirectives();
 					Map<String, String> result = new HashMap<String, String>(directives.size() + 1);
 					for (Directive directive : directives) {
 						result.put(directive.getName(), directive.getValue());
 					}
+					if (result.get(PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE) == null) {
+						StringBuilder builder = new StringBuilder("(&");
+						for (Entry<String, Object> entry : getAttributes().entrySet())
+							builder.append('(').append(entry.getKey()).append('=').append(entry.getValue()).append(')');
+						result.put(PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, builder.append(')').toString());
+					}
 					return result;
 				}
-
+				@Override
 				public Map<String, Object> getAttributes() {
 					Collection<Attribute> attributes = Clause.this.getAttributes();
 					Map<String, Object> result = new HashMap<String, Object>(attributes.size() + 1);
 					for (Attribute attribute : attributes) {
 						result.put(attribute.getName(), attribute.getValue());
 					}
+					if (result.get(PackageNamespace.PACKAGE_NAMESPACE) == null) {
+						result.put(PackageNamespace.PACKAGE_NAMESPACE, getPath());
+					}
+					if (result.get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE) == null)
+						result.put(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion.toString());
 					return result;
 				}
-
+				@Override
 				public Resource getResource() {
 					return resource;
 				}
-
-				public boolean matches(Capability capability) {
-					if (!getNamespace().equals(capability.getNamespace()))
-						return false;
-					Filter filter;
-					try {
-						filter = FrameworkUtil.createFilter(getDirectives().get(Constants.FILTER_DIRECTIVE));
-					}
-					catch (InvalidSyntaxException e) {
-						return false;
-					}
-					if (!filter.matches(capability.getAttributes()))
-							return false;
-					
-					return true;
-				}
 			};
 		}
 		
@@ -186,27 +181,43 @@ public class ImportPackageHeader impleme
 		}
 	}
 	
+	public static final String ATTRIBUTE_BUNDLE_SYMBOLICNAME = PackageNamespace.CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE;
+	public static final String ATTRIBUTE_BUNDLE_VERSION = PackageNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE;
+	public static final String ATTRIBUTE_VERSION = PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE;
 	public static final String NAME = Constants.IMPORT_PACKAGE;
+	public static final String DIRECTIVE_RESOLUTION = PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE;
+	public static final String RESOLUTION_MANDATORY = PackageNamespace.RESOLUTION_MANDATORY;
+	public static final String RESOLUTION_OPTIONAL = PackageNamespace.RESOLUTION_OPTIONAL;
 	
-	private static final String REGEX = '(' + Grammar.IMPORT + ")(?:\\,(" + Grammar.IMPORT + "))*";
+	private static final String REGEX = Grammar.IMPORT + "(?=,|\\z)";
 	private static final Pattern PATTERN = Pattern.compile(REGEX);
 	
-	private final Set<Clause> clauses = new HashSet<Clause>();
-	private final String value;
+//	private static String valueOf(Collection<Clause> clauses) {
+//		StringBuilder sb = new StringBuilder();
+//		for (Clause clause : clauses) {
+//			sb.append(clause).append(',');
+//		}
+//		if (sb.length() != 0)
+//			sb.deleteCharAt(sb.length() - 1);
+//		return sb.toString();
+//	}
+	
+	private final Set<Clause> clauses;
+//	private final String value;
+	
+	public ImportPackageHeader(Collection<Clause> clauses) {
+		this.clauses = new HashSet<Clause>(clauses);
+	}
 	
 	public ImportPackageHeader(String header) {
 		Matcher matcher = PATTERN.matcher(header);
-		if (!matcher.matches()) {
-			throw new IllegalArgumentException("Invalid " + Constants.IMPORT_PACKAGE + " header: " + header);
-		}
-		for (int i = 1; i <= matcher.groupCount(); i++) {
-			String group = matcher.group(i);
-			if (group != null) {
-				Clause clause = new Clause(group);
-				clauses.add(clause);
-			}
-		}
-		value = header;
+		Set<Clause> clauses = new HashSet<Clause>();
+		while (matcher.find())
+			clauses.add(new Clause(matcher.group()));
+		if (clauses.isEmpty())
+			throw new IllegalArgumentException("Invalid header syntax -> " + NAME + ": " + header);
+//		value = header;
+		this.clauses = clauses;
 	}
 	
 	public Collection<ImportPackageHeader.Clause> getClauses() {
@@ -226,14 +237,13 @@ public class ImportPackageHeader impleme
 		return result;
 	}
 	
+	@Override
 	public String getValue() {
-		return value;
+		return toString();
 	}
 	
 	public String toString() {
-		StringBuilder builder = new StringBuilder()
-				.append(getName())
-				.append(": ");
+		StringBuilder builder = new StringBuilder();
 		for (Clause clause : getClauses()) {
 			builder.append(clause);
 		}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageRequirement.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageRequirement.java?rev=1292916&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageRequirement.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ImportPackageRequirement.java Thu Feb 23 19:36:50 2012
@@ -0,0 +1,52 @@
+package org.apache.aries.subsystem.core.archive;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.resource.Requirement;
+
+public class ImportPackageRequirement {
+	private static final String BUNDLE_SYMBOLICNAME = PackageNamespace.CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE;
+	private static final String BUNDLE_VERSION = PackageNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE;
+	private static final String EQUAL = "=";
+	private static final String FILTER = PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE;
+	private static final String GREATER_THAN = ">";
+	private static final String GREATER_THAN_OR_EQUAL = GREATER_THAN + EQUAL;
+	private static final String LESS_THAN = "<";
+	private static final String LESS_THAN_OR_EQUAL = LESS_THAN + EQUAL;
+	private static final String NAMESPACE = PackageNamespace.PACKAGE_NAMESPACE;
+	private static final String RESOLUTION = PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE;
+	private static final String RESOLUTION_MANDATORY = PackageNamespace.RESOLUTION_MANDATORY;
+	private static final String RESOLUTION_OPTIONAL = PackageNamespace.RESOLUTION_OPTIONAL;
+	private static final String VERSION = PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE;
+	
+	private static final String REGEX = 
+			"\\((" + NAMESPACE + ")(=)([^\\)]+)\\)";
+	private static final Pattern PATTERN = Pattern.compile(REGEX);
+	
+	private final String packageName;
+	
+	public ImportPackageRequirement(Requirement requirement) {
+		if (!NAMESPACE.equals(requirement.getNamespace()))
+			throw new IllegalArgumentException("Requirement must be in the '" + NAMESPACE + "' namespace");
+		String filter = requirement.getDirectives().get(FILTER);
+		String packageName = null;
+		Matcher matcher = PATTERN.matcher(filter);
+		while (matcher.find()) {
+			String name = matcher.group(1);
+			String operator = matcher.group(2);
+			String value = matcher.group(3);
+			if (NAMESPACE.equals(name)) {
+				packageName = value;
+			}
+		}
+		if (packageName == null)
+			throw new IllegalArgumentException("Missing filter key: " + NAMESPACE);
+		this.packageName = packageName;
+	}
+	
+	public ImportPackageHeader.Clause toClause() {
+		return new ImportPackageHeader.Clause(packageName);
+	}
+}

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=1292916&r1=1292915&r2=1292916&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 Thu Feb 23 19:36:50 2012
@@ -47,6 +47,7 @@ import org.apache.aries.subsystem.core.a
 import org.apache.aries.subsystem.core.archive.DeployedContentHeader.DeployedContent;
 import org.apache.aries.subsystem.core.archive.DeploymentManifest;
 import org.apache.aries.subsystem.core.archive.Header;
+import org.apache.aries.subsystem.core.archive.ImportPackageHeader;
 import org.apache.aries.subsystem.core.archive.ProvisionResourceHeader;
 import org.apache.aries.subsystem.core.archive.ProvisionResourceHeader.ProvisionedResource;
 import org.apache.aries.subsystem.core.archive.SubsystemArchive;
@@ -63,8 +64,10 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.Version;
 import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.resource.Capability;
 import org.osgi.framework.resource.Requirement;
 import org.osgi.framework.resource.Resource;
@@ -261,6 +264,7 @@ public class AriesSubsystem implements S
 				id,
 				lastId,
 				location,
+				true,
 				true));
 		// TODO Begin proof of concept.
 		// This is a proof of concept for initializing the relationships between the root subsystem and bundles
@@ -529,6 +533,7 @@ public class AriesSubsystem implements S
 				.create(getSymbolicName() + '-' + getSubsystemId(), 0);
 		try {
 			// TODO Need to make sure the constituents are ordered by start level.
+			// TODO This doesn't start dependencies that are constituents in a parent subsystem.
 			for (Resource resource : constituents) {
 				startResource(resource, coordination);
 			}
@@ -685,6 +690,7 @@ public class AriesSubsystem implements S
 				id,
 				lastId,
 				location,
+				false,
 				false);
 		try {
 			archive.setDeploymentManifest(manifest);
@@ -758,7 +764,8 @@ public class AriesSubsystem implements S
 					id,
 					lastId,
 					location,
-					true));
+					true,
+					false));
 		}
 		return archive.getDeploymentManifest();
 	}
@@ -835,6 +842,7 @@ public class AriesSubsystem implements S
 			installResource(resource, coordination, true);
 		}
 		setState(State.INSTALLED);
+		setImportIsolationPolicy();
 		if (autostart)
 			start();
 	}
@@ -995,17 +1003,9 @@ public class AriesSubsystem implements S
 		return ROOT_LOCATION.equals(getLocation());
 	}
 	
-	private void setExportIsolationPolicy() {
-		// Archive is null for root subsystem.
-		if (archive == null)
-			return;
-		// TODO Implement export isolation policy for composites.
-	}
-	
 	private void resolve() {
 		setState(State.RESOLVING);
 		try {
-			setImportIsolationPolicy();
 			// TODO I think this is insufficient. Do we need both
 			// pre-install and post-install environments for the Resolver?
 			Collection<Bundle> bundles = getBundles();
@@ -1028,21 +1028,42 @@ public class AriesSubsystem implements S
 		}
 	}
 	
-	private void setImportIsolationPolicy() throws BundleException {
+	private void setExportIsolationPolicy() {
 		// Archive is null for root subsystem.
 		if (archive == null)
 			return;
-		// Feature contents are stored in the parent (or higher) region and take on the associated isolation.
+		// TODO Implement export isolation policy for composites.
+	}
+
+	private void setImportIsolationPolicy() throws BundleException, IOException, InvalidSyntaxException {
+		// Nothing to do if this is the root subsystem.
+		if (isRoot())
+			return;
+		// Features share the same isolation as that of their scoped parent.
 		if (isFeature()) {
 			return;
 		}
 		if (isApplication()) {
 			// TODO Implement import isolation policy for applications.
-			// Applications have an implicit import policy equating to "import everything that I require", which is not the same as features.
-			// This must be computed from the application requirements and will be done using the Wires returned by the Resolver, when one is available.
-			region.connectRegion(
-					((AriesSubsystem)getParents().iterator().next()).region, 
-					region.getRegionDigraph().createRegionFilterBuilder().allowAll(RegionFilter.VISIBLE_ALL_NAMESPACE).build());
+			// TODO Support for generic requirements such as osgi.ee.
+			ImportPackageHeader importPackage = getDeploymentManifest().getImportPackageHeader();
+			if (importPackage != null) {
+				for (ImportPackageHeader.Clause clause : importPackage.getClauses()) {
+					Region from = region;
+					Region to = ((AriesSubsystem)getParents().iterator().next()).region;
+					String policy = RegionFilter.VISIBLE_PACKAGE_NAMESPACE;
+					String filter = clause.getRequirement(this).getDirectives().get(PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE);
+					if (LOGGER.isDebugEnabled())
+						LOGGER.debug("Establishing region connection: from="
+								+ from + ", to=" + to + ", policy=" + policy
+								+ ", filter=" + filter);
+					from.connectRegion(
+							to, 
+							from.getRegionDigraph().createRegionFilterBuilder().allow(
+									RegionFilter.VISIBLE_PACKAGE_NAMESPACE, 
+									filter).build());
+				}
+			}
 		}
 		else if (isComposite()) {
 			// TODO Implement import isolation policy for composites.

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=1292916&r1=1292915&r2=1292916&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 Thu Feb 23 19:36:50 2012
@@ -14,7 +14,6 @@
 package org.apache.aries.subsystem.core.internal;
 
 import java.util.Collection;
-import java.util.EnumSet;
 import java.util.Iterator;
 
 import org.osgi.framework.hooks.resolver.ResolverHook;
@@ -46,8 +45,8 @@ public class SubsystemResolverHook imple
 						continue;
 					}
 					// Otherwise, the candidate is part of an application or composite subsystem requiring isolation.
-					// But only when in the INSTALLING or INSTALLED state.
-					if (EnumSet.of(Subsystem.State.INSTALLING, Subsystem.State.INSTALLED).contains(subsystem.getState())) {
+					// But only when in the INSTALLING state.
+					if (Subsystem.State.INSTALLING.equals(subsystem.getState())) {
 						iterator.remove();
 					}
 				}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Util.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Util.java?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Util.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Util.java Thu Feb 23 19:36:50 2012
@@ -65,7 +65,7 @@ public class Util
         List<Capability> caps = resource.getCapabilities(null);
         for (Capability cap : caps)
         {
-            if (cap.getNamespace().equals(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE))
+            if (cap.getNamespace().equals(IdentityNamespace.IDENTITY_NAMESPACE))
             {
                 String type = (String)
                     cap.getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE);
@@ -78,8 +78,7 @@ public class Util
     public static boolean isOptional(Requirement req)
     {
         String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE);
-        return ((resolution == null)
-            || resolution.equalsIgnoreCase(Constants.RESOLUTION_OPTIONAL));
+        return Constants.RESOLUTION_OPTIONAL.equals(resolution);
     }
 
     public static List<Requirement> getDynamicRequirements(List<Requirement> reqs)

Modified: aries/trunk/subsystem/subsystem-itests/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/pom.xml?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/pom.xml (original)
+++ aries/trunk/subsystem/subsystem-itests/pom.xml Thu Feb 23 19:36:50 2012
@@ -426,7 +426,6 @@
                         <exclude>**/Abstract*.java</exclude>
                     </excludes>
                     <includes>
-                        <include>**/Test*.java</include>
                         <include>**/*Test.java</include>
                     </includes>
                 </configuration>

Modified: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/ApplicationTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/ApplicationTest.java?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/ApplicationTest.java (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/ApplicationTest.java Thu Feb 23 19:36:50 2012
@@ -18,51 +18,139 @@
  */
 package org.apache.aries.subsystem.itests;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
 
+import org.apache.aries.subsystem.itests.util.TestCapability;
+import org.apache.aries.subsystem.itests.util.TestRepository;
+import org.apache.aries.subsystem.itests.util.TestRepositoryContent;
 import org.apache.aries.subsystem.itests.util.Utils;
 import org.apache.aries.unittest.fixture.ArchiveFixture;
 import org.apache.aries.unittest.fixture.ArchiveFixture.ZipFixture;
 import org.junit.Before;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.resource.Resource;
+import org.osgi.service.repository.Repository;
 import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
 
 @RunWith(JUnit4TestRunner.class)
 public class ApplicationTest extends SubsystemTest {
+	private static void createApplication(String name, String[] content) throws Exception {
+		ZipFixture feature = ArchiveFixture
+				.newZip()
+				.binary("OSGI-INF/SUBSYSTEM.MF",
+						ApplicationTest.class.getClassLoader().getResourceAsStream(
+								name + "/OSGI-INF/SUBSYSTEM.MF"));
+		for (String s : content) {
+			try {
+				feature.binary(s,
+						ApplicationTest.class.getClassLoader().getResourceAsStream(
+								name + '/' + s));
+			}
+			catch (Exception e) {
+				feature.binary(s, new FileInputStream(new File(s)));
+			}
+		}
+		feature.end();
+		FileOutputStream fos = new FileOutputStream(name + ".esa");
+		try {
+			feature.writeOut(fos);
+		} finally {
+			Utils.closeQuietly(fos);
+		}
+	}
+	
 	@Before
-    public static void doCreateApplications() throws Exception {
+	public static void createApplications() throws Exception {
 		if (createdApplications) {
 			return;
 		}
-		ZipFixture testEba = ArchiveFixture
-				.newZip()
-				.binary("OSGI-INF/APPLICATION.MF",
-						ApplicationTest.class.getClassLoader()
-								.getResourceAsStream(
-										"application1/OSGI-INF/APPLICATION.MF"))
-				.binary("tb1.jar",
-						ApplicationTest.class.getClassLoader()
-								.getResourceAsStream("application1/tb1.jar"))
-				.end();
-		FileOutputStream fout = new FileOutputStream("application1.eba");
+		createApplication("application1", new String[]{"tb1.jar"});
+		createdApplications = true;
+	}
+	
+	public void setUp() {
+		super.setUp();
 		try {
-			testEba.writeOut(fout);
-			createdApplications = true;
-		} finally {
-			Utils.closeQuietly(fout);
+			serviceRegistrations.add(
+					bundleContext.registerService(
+							Repository.class, 
+							createTestRepository(), 
+							null));
 		}
-    }
+		catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+	}
     
-    //@Test
+	/*
+	 * Subsystem application1 has content bundle tb1.jar.
+	 * Bundle tb1.jar has an import package dependency on org.apache.aries.subsystem.itests.tb3.
+	 */
+    @Test
     public void testApplication1() throws Exception {
-    	String application = "application1.eba";
-    	Subsystem subsystem = assertSubsystemLifeCycle(new File(application));
-    	assertId(subsystem);
-        assertLocation(application, subsystem);
-        assertSymbolicName("org.apache.aries.subsystem.application1", subsystem);
-        assertVersion("1.0.0", subsystem);
-        assertConstituents(2, subsystem);
+    	Subsystem application1 = installSubsystemFromFile("application1.esa");
+    	try {
+	    	assertSymbolicName("org.apache.aries.subsystem.application1", application1);
+			assertVersion("0.0.0", application1);
+			assertType(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, application1);
+			assertChildren(0, application1);
+			assertConstituents(2, application1);
+			startSubsystem(application1);
+			assertBundleState(Bundle.RESOLVED|Bundle.ACTIVE, "org.apache.aries.subsystem.itests.tb1", application1);
+			assertBundleState(Bundle.RESOLVED|Bundle.ACTIVE, "org.apache.aries.subsystem.itests.tb3", getRootSubsystem());
+    	}
+    	finally {
+    		stopSubsystem(application1);
+    		uninstallScopedSubsystem(application1);
+    	}
+    }
+    
+    private byte[] createTestBundle3Content() throws IOException {
+    	Manifest manifest = new Manifest();
+    	manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+    	manifest.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, "org.apache.aries.subsystem.itests.tb3");
+    	manifest.getMainAttributes().putValue(Constants.EXPORT_PACKAGE, "org.apache.aries.subsystem.itests.tb3");
+    	ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    	JarOutputStream jos = new JarOutputStream(baos, manifest);
+    	jos.close();
+    	return baos.toByteArray();
+    }
+    
+    private Resource createTestBundle3Resource() throws IOException {
+    	return new TestRepositoryContent.Builder()
+    	.capability(
+    			new TestCapability.Builder()
+    			.namespace(IdentityNamespace.IDENTITY_NAMESPACE)
+    			.attribute(IdentityNamespace.IDENTITY_NAMESPACE, "org.apache.aries.subsystem.itests.tb3")
+    			.attribute(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion)
+    			.attribute(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE))
+    	.capability(
+    			new TestCapability.Builder()
+    			.namespace(PackageNamespace.PACKAGE_NAMESPACE)
+    			.attribute(PackageNamespace.PACKAGE_NAMESPACE, "org.apache.aries.subsystem.itests.tb3")
+    			.attribute(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, "0.0.0"))
+    			.content(createTestBundle3Content())
+    	.build();
+    }
+    
+    private Repository createTestRepository() throws IOException {
+    	return new TestRepository.Builder()
+    	.resource(createTestBundle3Resource())
+    	.build();
     }
 }

Modified: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/SubsystemTest.java Thu Feb 23 19:36:50 2012
@@ -190,7 +190,7 @@ public abstract class SubsystemTest exte
 	
 	protected final SubsystemEventHandler subsystemEvents = new SubsystemEventHandler();
 	
-	private Collection<ServiceRegistration<?>> serviceRegistrations = new ArrayList<ServiceRegistration<?>>();
+	protected Collection<ServiceRegistration<?>> serviceRegistrations = new ArrayList<ServiceRegistration<?>>();
 	
 	public void setUp() {
 		super.setUp();
@@ -213,6 +213,18 @@ public abstract class SubsystemTest exte
 		super.tearDown();
 	}
 	
+	protected void assertBundleState(int state, String symbolicName, Subsystem subsystem) {
+    	boolean found = false;
+    	for (Bundle bundle : subsystem.getBundleContext().getBundles()) {
+			if (symbolicName.equals(bundle.getSymbolicName())) {
+				assertTrue("Wrong state: " + symbolicName, (bundle.getState() & state) != 0);
+				found = true;
+				break;
+			}
+		}
+    	assertTrue("Bundle '" + symbolicName + "' not found in region context bundle of '" + subsystem + "'", found);
+    }
+	
 	protected void assertChild(Subsystem parent, Subsystem child) {
 		Collection<Subsystem> children = new ArrayList<Subsystem>(1);
 		children.add(child);

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestCapability.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestCapability.java?rev=1292916&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestCapability.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestCapability.java Thu Feb 23 19:36:50 2012
@@ -0,0 +1,78 @@
+package org.apache.aries.subsystem.itests.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Resource;
+
+public class TestCapability implements Capability {
+	public static class Builder {
+		private final Map<String, Object> attributes = new HashMap<String, Object>();
+		private final Map<String, String> directives = new HashMap<String, String>();
+		
+		private String namespace;
+		private Resource resource;
+		
+		public Builder attribute(String name, Object value) {
+			attributes.put(name,  value);
+			return this;
+		}
+		
+		public TestCapability build() {
+			return new TestCapability(namespace, attributes, directives, resource);
+		}
+		
+		public Builder directive(String name, String value) {
+			directives.put(name, value);
+			return this;
+		}
+		
+		public Builder namespace(String value) {
+			namespace = value;
+			return this;
+		}
+		
+		public Builder resource(Resource value) {
+			resource = value;
+			return this;
+		}
+	}
+	
+	private final Map<String, Object> attributes;
+	private final Map<String, String> directives;
+	private final String namespace;
+	private final Resource resource;
+	
+	public TestCapability(
+			String namespace,
+			Map<String, Object> attributes,
+			Map<String, String> directives,
+			Resource resource) {
+		this.namespace = namespace;
+		this.attributes = new HashMap<String, Object>(attributes);
+		this.directives = new HashMap<String, String>(directives);
+		this.resource = resource;
+	}
+
+	@Override
+	public Map<String, Object> getAttributes() {
+		return Collections.unmodifiableMap(attributes);
+	}
+
+	@Override
+	public Map<String, String> getDirectives() {
+		return Collections.unmodifiableMap(directives);
+	}
+
+	@Override
+	public String getNamespace() {
+		return namespace;
+	}
+
+	@Override
+	public Resource getResource() {
+		return resource;
+	}
+}

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepository.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepository.java?rev=1292916&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepository.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepository.java Thu Feb 23 19:36:50 2012
@@ -0,0 +1,54 @@
+package org.apache.aries.subsystem.itests.util;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.subsystem.core.ResourceHelper;
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+import org.osgi.framework.resource.Resource;
+import org.osgi.service.repository.Repository;
+
+public class TestRepository implements Repository {
+	public static class Builder {
+		private final Collection<Resource> resources = new HashSet<Resource>();
+		
+		public TestRepository build() {
+			return new TestRepository(resources);
+		}
+		
+		public Builder resource(Resource value) {
+			resources.add(value);
+			return this;
+		}
+	}
+	
+	private final Collection<Resource> resources;
+	
+	public TestRepository(Collection<Resource> resources) {
+		this.resources = resources;
+	}
+	@Override
+	public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
+		Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>();
+		for (Requirement requirement : requirements) {
+			for (Resource resource : resources) {
+				List<Capability> capabilities = resource.getCapabilities(requirement.getNamespace());
+				for (Capability capability : capabilities) {
+					if (ResourceHelper.matches(requirement, capability)) {
+						Collection<Capability> c = result.get(requirement);
+						if (c == null) {
+							c = new HashSet<Capability>();
+							result.put(requirement, c);
+						}
+						c.add(capability);
+					}
+				}
+			}
+		}
+		return result;
+	}
+}

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepositoryContent.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepositoryContent.java?rev=1292916&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepositoryContent.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestRepositoryContent.java Thu Feb 23 19:36:50 2012
@@ -0,0 +1,54 @@
+package org.apache.aries.subsystem.itests.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.resource.Requirement;
+import org.osgi.service.repository.RepositoryContent;
+
+public class TestRepositoryContent extends TestResource implements RepositoryContent {
+	public static class Builder {
+		private final List<TestCapability.Builder> capabilities = new ArrayList<TestCapability.Builder>();
+		private final List<Requirement> requirements = new ArrayList<Requirement>();
+		
+		private byte[] content;
+		
+		public TestRepositoryContent build() {
+			return new TestRepositoryContent(capabilities, requirements, content);
+		}
+		
+		public Builder capability(TestCapability.Builder value) {
+			capabilities.add(value);
+			return this;
+		}
+		
+		public Builder content(byte[] value) {
+			content = value;
+			return this;
+		}
+		
+		public Builder requirement(Requirement value) {
+			requirements.add(value);
+			return this;
+		}
+	}
+	
+	private final byte[] content;
+	
+	public TestRepositoryContent(
+			List<TestCapability.Builder> capabilities, 
+			List<Requirement> requirements,
+			byte[] content) {
+		super(capabilities, requirements);
+		this.content = content;
+	}
+
+	@Override
+	public InputStream getContent() throws IOException {
+		return new ByteArrayInputStream(content);
+	}
+
+}

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestResource.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestResource.java?rev=1292916&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestResource.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/util/TestResource.java Thu Feb 23 19:36:50 2012
@@ -0,0 +1,64 @@
+package org.apache.aries.subsystem.itests.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+import org.osgi.framework.resource.Resource;
+
+public class TestResource implements Resource {
+	public static class Builder {
+		private final List<TestCapability.Builder> capabilities = new ArrayList<TestCapability.Builder>();
+		private final List<Requirement> requirements = new ArrayList<Requirement>();
+		
+		public TestResource build() {
+			return new TestResource(capabilities, requirements);
+		}
+		
+		public Builder capability(TestCapability.Builder value) {
+			capabilities.add(value);
+			return this;
+		}
+		
+		public Builder requirement(Requirement value) {
+			requirements.add(value);
+			return this;
+		}
+	}
+	
+	private final List<Capability> capabilities;
+	private final List<Requirement> requirements;
+	
+	public TestResource(List<TestCapability.Builder> capabilities, List<Requirement> requirements) {
+		this.capabilities = new ArrayList<Capability>(capabilities.size());
+		for (TestCapability.Builder builder : capabilities)
+			this.capabilities.add(builder.resource(this).build());
+		this.requirements = requirements;
+	}
+
+	@Override
+	public List<Capability> getCapabilities(String namespace) {
+		if (namespace == null)
+			return Collections.unmodifiableList(capabilities);
+		ArrayList<Capability> result = new ArrayList<Capability>(capabilities.size());
+		for (Capability capability : capabilities)
+			if (namespace.equals(capability.getNamespace()))
+				result.add(capability);
+		result.trimToSize();
+		return Collections.unmodifiableList(result);
+	}
+
+	@Override
+	public List<Requirement> getRequirements(String namespace) {
+		if (namespace == null)
+			return Collections.unmodifiableList(requirements);
+		ArrayList<Requirement> result = new ArrayList<Requirement>(requirements.size());
+		for (Requirement requirement : requirements)
+			if (namespace.equals(requirement.getNamespace()))
+				result.add(requirement);
+		result.trimToSize();
+		return Collections.unmodifiableList(result);
+	}
+}

Modified: aries/trunk/subsystem/subsystem-itests/src/test/resources/application1/OSGI-INF/SUBSYSTEM.MF
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/resources/application1/OSGI-INF/SUBSYSTEM.MF?rev=1292916&r1=1292915&r2=1292916&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/resources/application1/OSGI-INF/SUBSYSTEM.MF (original)
+++ aries/trunk/subsystem/subsystem-itests/src/test/resources/application1/OSGI-INF/SUBSYSTEM.MF Thu Feb 23 19:36:50 2012
@@ -1,6 +1,2 @@
-Manifest-Version: 1.0
-Subsystem-ManifestVersion: 1.0
 Subsystem-SymbolicName: org.apache.aries.subsystem.application1
-Subsystem-Version: 1.0.0
-Subsystem-Content: org.apache.felix.fileinstall;version=2.0.8,org.apache.aries.subsystem.itests.tb1;version=1.0.0
-Subsystem-Type: osgi.application
\ No newline at end of file
+Subsystem-Content: org.apache.aries.subsystem.itests.tb1;version=1.0.0
\ No newline at end of file