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/08 14:54:44 UTC

svn commit: r1241900 [5/8] - in /aries/trunk/subsystem: ./ subsystem-api/ subsystem-api/src/main/java/org/osgi/service/repository/ subsystem-api/src/main/java/org/osgi/service/resolver/ subsystem-api/src/main/java/org/osgi/service/subsystem/ subsystem-...

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemEnvironment.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemEnvironment.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemEnvironment.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemEnvironment.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,256 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aries.subsystem.core.obr;
+
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.aries.subsystem.core.ResourceHelper;
+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.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.Wiring;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.service.repository.Repository;
+import org.osgi.service.resolver.Environment;
+import org.osgi.service.subsystem.Subsystem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * TODO
+ * The locating of providers for transitive dependencies needs to have subsystem type and share policies taken into account.
+ * 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 Logger logger = LoggerFactory.getLogger(SubsystemEnvironment.class);
+	
+	private final Set<Resource> resources = new HashSet<Resource>();
+	private final AriesSubsystem subsystem;
+	
+	public SubsystemEnvironment(AriesSubsystem subsystem) throws IOException, URISyntaxException {
+		this.subsystem = subsystem;
+	}
+	
+	@Override
+	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;
+						if (!br1 && br2)
+							result = 1;
+						logger.debug(LOG_EXIT, "compare", result);
+						return result;
+					}
+				});
+		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.
+			// This means we're looking for a content resource.
+			OsgiIdentityRequirement identity = (OsgiIdentityRequirement)requirement;
+			if (subsystem.isFeature()) {
+				// Features share content resources as well as transitive dependencies.
+				findConstituentProviders(requirement, capabilities);
+			}
+			findArchiveProviders(capabilities, identity, !identity.isTransitiveDependency());
+			findRepositoryServiceProviders(capabilities, identity, !identity.isTransitiveDependency());
+		}
+		else {
+			logger.debug("The requirement is NOT an instance of OsgiIdentityRequirement");
+			// This means we're looking for capabilities satisfying a requirement within a content resource or transitive dependency.
+			findArchiveProviders(capabilities, requirement, false);
+			findRepositoryServiceProviders(capabilities, requirement, false);
+			// TODO The following is a quick fix to ensure this environment always returns capabilities provided by the system bundle. Needs some more thought.
+			findConstituentProviders(requirement, capabilities);
+		}
+		logger.debug(LOG_EXIT, "findProviders", capabilities);
+		return capabilities;
+	}
+	
+	@Override
+	public Map<Requirement, SortedSet<Capability>> findProviders(Collection<? extends Requirement> requirements) {
+		logger.debug(LOG_ENTRY, "findProviders", requirements);
+		Map<Requirement, SortedSet<Capability>> result = new HashMap<Requirement, SortedSet<Capability>>(requirements.size());
+		for (Requirement requirement : requirements)
+			result.put(requirement, findProviders(requirement));
+		logger.debug(LOG_EXIT, "findProviders", result);
+		return result;
+	}
+	
+	public Resource findResource(OsgiIdentityRequirement requirement) {
+		logger.debug(LOG_ENTRY, "findResource", requirement);
+		Collection<Capability> capabilities = findProviders(requirement);
+		Resource result = null;
+		if (!capabilities.isEmpty())
+			result = capabilities.iterator().next().getResource();
+		logger.debug(LOG_EXIT, "findResource", result);
+		return result;
+	}
+
+	@Override
+	public Map<Resource, Wiring> getWirings() {
+		logger.debug(LOG_ENTRY, "getWirings");
+		Map<Resource, Wiring> result = new HashMap<Resource, Wiring>();
+		BundleContext bundleContext = Activator.getInstance().getBundleContext().getBundle(0).getBundleContext();
+		for (Bundle bundle : bundleContext.getBundles()) {
+			BundleRevision revision = bundle.adapt(BundleRevision.class);
+			Wiring wiring = revision.getWiring();
+			if (wiring != null) {
+				result.put(
+						revision, 
+						revision.getWiring());
+			}
+		}
+		logger.debug(LOG_EXIT, "getWirings", result);
+		return result;
+	}
+	
+	public boolean isContentResource(Resource resource) {
+		logger.debug(LOG_ENTRY, "isContentResource", resource);
+		boolean result = resources.contains(resource);
+		logger.debug(LOG_EXIT, "isContentResource", result);
+		return result;
+	}
+
+	@Override
+	public boolean isEffective(Requirement requirement) {
+		logger.debug(LOG_ENTRY, "isEffective", requirement);
+		boolean result = true;
+		logger.debug(LOG_EXIT, "isEffective", result);
+		return true;
+	}
+	
+	private void findConstituentProviders(Requirement requirement, Collection<Capability> capabilities) {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "findConstituentProviders", new Object[]{requirement, capabilities});
+		Subsystem subsystem = this.subsystem;
+		logger.debug("Navigating up the parent hierarchy...");
+		while (!subsystem.getParents().isEmpty()) {
+			subsystem = subsystem.getParents().iterator().next();
+			logger.debug("Next parent is: {}", subsystem);
+		}
+		findConstituentProviders(subsystem, requirement, capabilities);
+		logger.debug(LOG_EXIT, "findConstituentProviders");
+	}
+	
+	private void findConstituentProviders(Subsystem subsystem, Requirement requirement, Collection<Capability> capabilities) {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "findConstituentProviders", new Object[]{subsystem, requirement, capabilities});
+		for (Resource resource : subsystem.getConstituents()) {
+			logger.debug("Evaluating resource: {}", resource);
+			for (Capability capability : resource.getCapabilities(requirement.getNamespace())) {
+				logger.debug("Evaluating capability: {}", capability);
+				if (ResourceHelper.matches(requirement, capability)) {
+					logger.debug("Adding capability: {}", capability);
+					capabilities.add(capability);
+				}
+			}
+		}
+		findConstituentProviders(subsystem.getChildren(), requirement, capabilities);
+		logger.debug(LOG_EXIT, "findConstituentProviders");
+	}
+	
+	private void findConstituentProviders(Collection<Subsystem> children, Requirement requirement, Collection<Capability> capabilities) {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "findConstituentProviders", new Object[]{children, requirement, capabilities});
+		for (Subsystem child : children) {
+			logger.debug("Evaluating child subsystem: {}", child);
+			findConstituentProviders(child, requirement, capabilities);
+		}
+	}
+	
+	private void findArchiveProviders(Collection<Capability> capabilities, Requirement requirement, boolean content) {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "findArchiveProviders", new Object[]{capabilities, requirement, content});
+		AriesSubsystem subsystem = this.subsystem;
+		logger.debug("Navigating up the parent hierarchy...");
+		while (!subsystem.getParents().isEmpty()) {
+			subsystem = (AriesSubsystem)subsystem.getParents().iterator().next();
+			logger.debug("Next parent is: {}", subsystem);
+		}
+		findArchiveProviders(capabilities, requirement, subsystem, content);
+		logger.debug(LOG_EXIT, "findArchiveProviders");
+	}
+	
+	private void findArchiveProviders(Collection<Capability> capabilities, Requirement requirement, AriesSubsystem subsystem, boolean content) {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "findArchiveProviders", new Object[]{capabilities, requirement, subsystem, content});
+		for (Capability capability : subsystem.getArchive().findProviders(requirement)) {
+			logger.debug("Adding capability: {}", capability);
+			capabilities.add(capability);
+			if (content) {
+				Resource resource = capability.getResource();
+				logger.debug("Adding content resource: {}", resource);
+				resources.add(resource);
+			}
+		}
+		findArchiveProviders(capabilities, requirement, subsystem.getChildren(), content);
+		logger.debug(LOG_EXIT, "findArchiveProviders");
+	}
+	
+	private void findArchiveProviders(Collection<Capability> capabilities, Requirement requirement, Collection<Subsystem> children, boolean content) {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "findArchiveProviders", new Object[]{capabilities, requirement, children, content});
+		for (Subsystem child : children) {
+			logger.debug("Evaluating child subsystem: {}", child);
+			findArchiveProviders(capabilities, requirement, (AriesSubsystem)child, content);
+		}
+		logger.debug(LOG_EXIT, "findArchiveProviders");
+	}
+	
+	private void findRepositoryServiceProviders(Collection<Capability> capabilities, Requirement requirement, boolean content) {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "findRepositoryServiceProviders", new Object[]{capabilities, requirement, content});
+		Collection<Repository> repositories = Activator.getInstance().getServiceProvider().getServices(Repository.class);
+		for (Repository repository : repositories) {
+			logger.debug("Evaluating repository: {}", repository);
+			for (Capability capability : repository.findProviders(requirement)) {
+				logger.debug("Adding capability: {}", capability);
+				capabilities.add(capability);
+				if (content) {
+					Resource resource = capability.getResource();
+					logger.debug("Adding content resource: {}", resource);
+					resources.add(resource);
+				}
+			}
+		}
+		logger.debug(LOG_EXIT, "findRepositoryServiceProviders");
+	}
+}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemResolver.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemResolver.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemResolver.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/SubsystemResolver.java Wed Feb  8 13:54:41 2012
@@ -13,6 +13,9 @@
  */
 package org.apache.aries.subsystem.core.obr;
 
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -21,25 +24,31 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.aries.subsystem.core.internal.Activator;
-import org.apache.aries.subsystem.core.internal.OsgiIdentityRequirement;
-import org.apache.aries.subsystem.core.obr.felix.FelixResourceAdapter;
 import org.apache.aries.subsystem.core.obr.felix.OsgiResourceAdapter;
 import org.apache.felix.bundlerepository.Reason;
+import org.apache.felix.bundlerepository.RepositoryAdmin;
 import org.osgi.framework.resource.Capability;
 import org.osgi.framework.resource.Requirement;
 import org.osgi.framework.resource.Resource;
 import org.osgi.framework.resource.Wire;
+import org.osgi.framework.resource.Wiring;
 import org.osgi.service.resolver.Environment;
 import org.osgi.service.resolver.ResolutionException;
 import org.osgi.service.resolver.Resolver;
 import org.osgi.service.subsystem.SubsystemException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class SubsystemResolver implements Resolver {
+	private static final Logger logger = LoggerFactory.getLogger(SubsystemResolver.class);
+	
 	private static void addCapabilities(Collection<Capability> capabilities, Environment environment, Requirement requirement) {
 		Collection<Capability> caps = environment.findProviders(requirement);
 		if (caps.isEmpty())
 			return;
 		Capability capability = caps.iterator().next();
+		if (capabilities.contains(capability))
+			return;
 		capabilities.add(capability);
 		addCapabilities(capabilities, environment, capability.getResource().getRequirements(null));
 	}
@@ -51,7 +60,9 @@ public class SubsystemResolver implement
 	}
 
 	@Override
-	public Map<Resource, List<Wire>> resolve(Environment environment, Collection<Resource> mandatory, Collection<Resource> optional) throws ResolutionException {
+	public Map<Resource, List<Wire>> resolve(Environment environment, Collection<? extends Resource> mandatory, Collection<?  extends Resource> optional) throws ResolutionException {
+		if (logger.isDebugEnabled())
+			logger.debug(LOG_ENTRY, "resolve", new Object[]{environment, mandatory, optional});
 		Collection<Capability> capabilities = new ArrayList<Capability>();
 		/*
 		 * TODO Until an implementation of Resolver comes along, need to find as many resources with capabilities satisfying as
@@ -71,30 +82,31 @@ public class SubsystemResolver implement
 		for (Capability capability : capabilities) {
 			resources.add(capability.getResource());
 		}
-		org.apache.felix.bundlerepository.Resolver resolver = Activator.getRepositoryAdmin().resolver();
+		org.apache.felix.bundlerepository.Resolver resolver = Activator.getInstance().getServiceProvider().getService(RepositoryAdmin.class).resolver();
         for (Resource resource : resources) {
             resolver.add(new OsgiResourceAdapter(resource));
         }
-        if (resolver.resolve()) {
-        	/* 
-        	 * TODO For now, these need to go back through the environment in order to be sure the URL is available.
-        	 * This is because RepositoryAdmin is not going through the environment as part of pulling in transitive
-        	 * dependencies. Once a "real" Resolver is available, this will no longer be necessary.
-        	 */
-        	for (org.apache.felix.bundlerepository.Resource resource : resolver.getRequiredResources()) {
-        		Resource r = new FelixResourceAdapter(resource);
-        		// Make the environment aware of the resource and its URL.
-        		environment.findProviders(new OsgiIdentityRequirement(r, true));
-            	resources.add(r);
-        	}
-        	for (org.apache.felix.bundlerepository.Resource resource : resolver.getOptionalResources()) {
-        		Resource r = new FelixResourceAdapter(resource);
-        		// Make the environment aware of the resource and its URL.
-        		environment.findProviders(new OsgiIdentityRequirement(r, true));
-            	resources.add(r);
-        	}
-        }
-        else {
+//        if (resolver.resolve()) {
+//        	/* 
+//        	 * TODO For now, these need to go back through the environment in order to be sure the URL is available.
+//        	 * This is because RepositoryAdmin is not going through the environment as part of pulling in transitive
+//        	 * dependencies. Once a "real" Resolver is available, this will no longer be necessary.
+//        	 */
+//        	for (org.apache.felix.bundlerepository.Resource resource : resolver.getRequiredResources()) {
+//        		Resource r = new FelixResourceAdapter(resource);
+//        		// Make the environment aware of the resource and its URL.
+//        		environment.findProviders(new OsgiIdentityRequirement(r, true));
+//            	resources.add(r);
+//        	}
+//        	for (org.apache.felix.bundlerepository.Resource resource : resolver.getOptionalResources()) {
+//        		Resource r = new FelixResourceAdapter(resource);
+//        		// Make the environment aware of the resource and its URL.
+//        		environment.findProviders(new OsgiIdentityRequirement(r, true));
+//            	resources.add(r);
+//        	}
+//        }
+//        else {
+        if (!resolver.resolve()) {
             Reason[] reasons = resolver.getUnsatisfiedRequirements();
             StringBuilder builder = new StringBuilder("Failed to resolve subsystem").append(System.getProperty("line.separator"));
             for (Reason reason : reasons)
@@ -111,6 +123,7 @@ public class SubsystemResolver implement
 		for (Resource resource : resources) {
 			result.put(resource, Collections.EMPTY_LIST);
 		}
+		logger.debug(LOG_EXIT, "resolve", result);
 		return result;
 	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixCapabilityAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixCapabilityAdapter.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixCapabilityAdapter.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixCapabilityAdapter.java Wed Feb  8 13:54:41 2012
@@ -16,19 +16,17 @@ package org.apache.aries.subsystem.core.
 import java.util.Collections;
 import java.util.Map;
 
-import org.osgi.framework.resource.Capability;
+import org.apache.aries.subsystem.core.resource.AbstractCapability;
 import org.osgi.framework.resource.Resource;
 import org.osgi.framework.wiring.BundleRevision;
 
-public class FelixCapabilityAdapter implements Capability {
+public class FelixCapabilityAdapter extends AbstractCapability {
 	private final org.apache.felix.bundlerepository.Capability capability;
 	private final Resource resource;
 	
 	public FelixCapabilityAdapter(org.apache.felix.bundlerepository.Capability capability, Resource resource) {
 		if (capability == null)
 			throw new NullPointerException("Missing required parameter: capability");
-		if (resource == null)
-			throw new NullPointerException("Missing required parameter: resource");
 		this.capability = capability;
 		this.resource = resource;
 	}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixRepositoryAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixRepositoryAdapter.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixRepositoryAdapter.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixRepositoryAdapter.java Wed Feb  8 13:54:41 2012
@@ -13,55 +13,142 @@
  */
 package org.apache.aries.subsystem.core.obr.felix;
 
-import java.net.URI;
-import java.net.URL;
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
 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.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.apache.aries.subsystem.core.ResourceHelper;
+import org.apache.aries.subsystem.core.internal.OsgiIdentityCapability;
+import org.osgi.framework.Constants;
 import org.osgi.framework.resource.Capability;
 import org.osgi.framework.resource.Requirement;
 import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.ResourceConstants;
 import org.osgi.service.repository.Repository;
-import org.osgi.service.subsystem.SubsystemException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class FelixRepositoryAdapter implements Repository {
+	private static class IdentityRequirementFilter {
+		private static final String REGEX = "\\(osgi.identity=([^\\)]*)\\)";
+		private static final Pattern PATTERN = Pattern.compile(REGEX);
+		
+		private final String symbolicName;
+		
+		public IdentityRequirementFilter(String filter) {
+			Matcher matcher = PATTERN.matcher(filter);
+			if (!matcher.find())
+				throw new IllegalArgumentException("Could not find pattern '" + REGEX + "' in filter string '" + filter + "'");
+			symbolicName = matcher.group(1);
+		}
+		
+		public String getSymbolicName() {
+			return symbolicName;
+		}
+	}
+	
+	private static final Logger logger = LoggerFactory.getLogger(FelixRepositoryAdapter.class);
+	
+	private final Map<String, Collection<Capability>> identityIndex = Collections.synchronizedMap(new HashMap<String, Collection<Capability>>());
 	private final org.apache.felix.bundlerepository.Repository repository;
 	
+	private long lastUpdated = 0;
+	
 	public FelixRepositoryAdapter(org.apache.felix.bundlerepository.Repository repository) {
+		if (repository == null)
+			throw new NullPointerException("Missing required parameter: repository");
 		this.repository = repository;
 	}
 	
 	@Override
-	public Collection<Capability> findProviders(Requirement requirement) throws NullPointerException {
-		org.apache.felix.bundlerepository.Resource[] resources = repository.getResources();
-		ArrayList<Capability> result = new ArrayList<Capability>(resources.length);
-		for (final org.apache.felix.bundlerepository.Resource resource : resources) {
-			Resource r = new FelixResourceAdapter(resource);
-			for (Capability capability : r.getCapabilities(requirement.getNamespace()))
-				if (requirement.matches(capability))
-					result.add(capability);
+	public Collection<Capability> findProviders(Requirement requirement) {
+		logger.debug(LOG_ENTRY, "findProviders", requirement);
+		update();
+		List<Capability> result = Collections.emptyList();
+		if (ResourceConstants.IDENTITY_NAMESPACE.equals(requirement.getNamespace())) {
+			String symbolicName = new IdentityRequirementFilter(requirement.getDirectives().get(Constants.FILTER_DIRECTIVE)).getSymbolicName();
+			logger.debug("Looking for symbolic name {}", symbolicName);
+			Collection<Capability> capabilities = identityIndex.get(symbolicName);
+			if (capabilities != null) {
+				result = new ArrayList<Capability>(capabilities.size());
+				for (Capability capability : capabilities) {
+					if (ResourceHelper.matches(requirement, capability)) {
+						result.add(capability);
+					}
+				}
+				((ArrayList<Capability>)result).trimToSize();
+			}
 		}
-		result.trimToSize();
+		else {
+			org.apache.felix.bundlerepository.Resource[] resources = repository.getResources();
+			if (resources != null && resources.length != 0) {
+				result = new ArrayList<Capability>(resources.length);
+				for (final org.apache.felix.bundlerepository.Resource resource : resources) {
+					Resource r = new FelixResourceAdapter(resource);
+					for (Capability capability : r.getCapabilities(requirement.getNamespace()))
+						if (ResourceHelper.matches(requirement, capability))
+							result.add(capability);
+				}
+				((ArrayList<Capability>)result).trimToSize();
+			}
+		}
+		logger.debug(LOG_EXIT, "findProviders", result);
 		return result;
 	}
-
+	
 	@Override
-	public URL getContent(Resource resource) {
-		for (final org.apache.felix.bundlerepository.Resource r : repository.getResources()) {
-			final Resource sr = new FelixResourceAdapter(r);
-			if (ResourceHelper.getTypeAttribute(resource).equals(ResourceHelper.getTypeAttribute(sr)))
-				if (ResourceHelper.getSymbolicNameAttribute(resource).equals(ResourceHelper.getSymbolicNameAttribute(sr)))
-					if (ResourceHelper.getVersionAttribute(resource).equals(ResourceHelper.getVersionAttribute(sr))) {
-						try {
-							return new URI(r.getURI()).toURL();
-						}
-						catch (Exception e) {
-							// TODO Is this really what we want to do?
-							throw new SubsystemException(e);
+	public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
+		logger.debug(LOG_ENTRY, "findProviders", requirements);
+		Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>(requirements.size());
+		for (Requirement requirement : requirements)
+			result.put(requirement, findProviders(requirement));
+				logger.debug(LOG_EXIT, "findProviders", result);
+		return result;
+	}
+	
+	private synchronized void update() {
+		logger.debug(LOG_ENTRY, "update");
+		long lastModified = repository.getLastModified();
+		logger.debug("The repository adaptor was last updated at {}. The repository was last modified at {}", lastUpdated, lastModified);
+		if (lastModified > lastUpdated) {
+			logger.debug("Updating the adapter with the modified repository contents...");
+			lastUpdated = lastModified;
+			synchronized (identityIndex) {
+				identityIndex.clear();
+				org.apache.felix.bundlerepository.Resource[] resources = repository.getResources();
+				logger.debug("There are {} resources to evaluate", resources == null ? 0 : resources.length);
+				if (resources != null && resources.length != 0) {
+					for (org.apache.felix.bundlerepository.Resource resource : resources) {
+						logger.debug("Evaluating resource {}", resource);
+						String symbolicName = resource.getSymbolicName();
+						Collection<Capability> capabilities = identityIndex.get(symbolicName);
+						if (capabilities == null) {
+							capabilities = new HashSet<Capability>();
+							identityIndex.put(symbolicName, capabilities);
 						}
+						OsgiIdentityCapability capability = 
+								new OsgiIdentityCapability(
+									new FelixResourceAdapter(resource),
+									symbolicName,
+									resource.getVersion(),
+									// TODO Assuming all resources are bundles. Need to support 
+									// type fragment as well, but how do we know?
+									ResourceConstants.IDENTITY_TYPE_BUNDLE);
+						logger.debug("Indexing capability {}", capability);
+						capabilities.add(capability);
 					}
+				}
+			}
 		}
-		return null;
+		logger.debug(LOG_EXIT, "update");
 	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixResourceAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixResourceAdapter.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixResourceAdapter.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/FelixResourceAdapter.java Wed Feb  8 13:54:41 2012
@@ -13,6 +13,9 @@
  */
 package org.apache.aries.subsystem.core.obr.felix;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -24,8 +27,9 @@ import org.osgi.framework.resource.Requi
 import org.osgi.framework.resource.Resource;
 import org.osgi.framework.resource.ResourceConstants;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.service.repository.RepositoryContent;
 
-public class FelixResourceAdapter implements Resource {
+public class FelixResourceAdapter implements Resource, RepositoryContent {
 	private static String toFelixNamespace(String namespace) {
 		if (BundleRevision.BUNDLE_NAMESPACE.equals(namespace))
 			return org.apache.felix.bundlerepository.Capability.BUNDLE;
@@ -91,6 +95,11 @@ public class FelixResourceAdapter implem
 		result.trimToSize();
 		return result;
 	}
+	
+	@Override
+	public InputStream getContent() throws IOException {
+		return new URL(resource.getURI()).openStream();
+	}
 
 	public List<Requirement> getRequirements(String namespace) {
 		namespace = toFelixNamespace(namespace);

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiCapabilityAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiCapabilityAdapter.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiCapabilityAdapter.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiCapabilityAdapter.java Wed Feb  8 13:54:41 2012
@@ -30,6 +30,11 @@ public class OsgiCapabilityAdapter imple
 			throw new NullPointerException("Missing required parameter: capability");
 		this.capability = capability;
 	}
+	
+	@Override
+	public boolean equals(Object o) {
+		return capability.equals(o);
+	}
 
 	public String getName() {
 		String namespace = capability.getNamespace();
@@ -61,4 +66,9 @@ public class OsgiCapabilityAdapter imple
 		result.put(getName(), result.get(capability.getNamespace()));
 		return result;
 	}
+	
+	@Override
+	public int hashCode() {
+		return capability.hashCode();
+	}
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiRequirementAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiRequirementAdapter.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiRequirementAdapter.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/OsgiRequirementAdapter.java Wed Feb  8 13:54:41 2012
@@ -13,12 +13,20 @@
  */
 package org.apache.aries.subsystem.core.obr.felix;
 
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import org.apache.aries.subsystem.core.ResourceHelper;
 import org.apache.felix.bundlerepository.Capability;
 import org.apache.felix.bundlerepository.Requirement;
 import org.osgi.framework.Constants;
 import org.osgi.framework.wiring.BundleRevision;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class OsgiRequirementAdapter implements Requirement {
+	private static final Logger logger = LoggerFactory.getLogger(OsgiRequirementAdapter.class);
+	
 	private final org.osgi.framework.resource.Requirement requirement;
 	
 	public OsgiRequirementAdapter(org.osgi.framework.resource.Requirement requirement) {
@@ -60,7 +68,10 @@ public class OsgiRequirementAdapter impl
 	}
 
 	public boolean isSatisfied(Capability capability) {
-		return requirement.matches(new FelixCapabilityAdapter(capability, requirement.getResource()));
+		logger.debug(LOG_ENTRY, "isSatisfied", capability);
+		boolean result = ResourceHelper.matches(requirement, new FelixCapabilityAdapter(capability, null));
+		logger.debug(LOG_EXIT, "isSatisfied", result);
+		return result;
 	}
 
 }

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/RepositoryAdminRepository.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/RepositoryAdminRepository.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/RepositoryAdminRepository.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/obr/felix/RepositoryAdminRepository.java Wed Feb  8 13:54:41 2012
@@ -13,43 +13,80 @@
  */
 package org.apache.aries.subsystem.core.obr.felix;
 
-import java.net.URL;
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.felix.bundlerepository.RepositoryAdmin;
+import org.apache.felix.bundlerepository.Resource;
 import org.osgi.framework.resource.Capability;
 import org.osgi.framework.resource.Requirement;
-import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.ResourceConstants;
 import org.osgi.service.repository.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class RepositoryAdminRepository implements Repository {
+	private static final Logger logger = LoggerFactory.getLogger(RepositoryAdminRepository.class);
+	
+	private Collection<Repository> repositories = new ArrayList<Repository>();
 	private final RepositoryAdmin repositoryAdmin;
 	
 	public RepositoryAdminRepository(RepositoryAdmin repositoryAdmin) {
+		org.apache.felix.bundlerepository.Repository[] repositories = repositoryAdmin.listRepositories();
+		for (org.apache.felix.bundlerepository.Repository repository : repositories) {
+			FelixRepositoryAdapter r = new FelixRepositoryAdapter(repository);
+			this.repositories.add(r);
+		}
 		this.repositoryAdmin = repositoryAdmin;
 	}
 	
 	@Override
 	public Collection<Capability> findProviders(Requirement requirement) {
-		org.apache.felix.bundlerepository.Repository[] repositories = repositoryAdmin.listRepositories();
-		ArrayList<Capability> result = new ArrayList<Capability>();
-		for (org.apache.felix.bundlerepository.Repository repository : repositories) {
-			FelixRepositoryAdapter r = new FelixRepositoryAdapter(repository);
-			result.addAll(r.findProviders(requirement));
+		logger.debug(LOG_ENTRY, "findProviders", requirement);
+		Collection<Capability> result = Collections.emptyList();
+		if (ResourceConstants.IDENTITY_NAMESPACE.equals(requirement.getNamespace())) {
+			result = new ArrayList<Capability>();
+			for (Repository repository : repositories) {
+				result.addAll(repository.findProviders(requirement));
+			}
+			return result;
 		}
+		else {
+			Resource[] resources = repositoryAdmin.discoverResources(
+					new org.apache.felix.bundlerepository.Requirement[]{
+							new OsgiRequirementAdapter(requirement)});
+			logger.debug("Found {} resources with capabilities satisfying {}", resources == null ? 0 : resources.length, requirement);
+			if (resources != null  && resources.length != 0) {
+				result = new ArrayList<Capability>(result.size());
+				OsgiRequirementAdapter adapter = new OsgiRequirementAdapter(requirement);
+				for (Resource resource : resources) {
+					logger.debug("Evaluating resource {}", resource);
+					for (org.apache.felix.bundlerepository.Capability capability : resource.getCapabilities()) {
+						logger.debug("Evaluating capability {}", capability);
+						if (adapter.isSatisfied(capability)) {
+							logger.debug("Adding capability {}", capability);
+							result.add(new FelixCapabilityAdapter(capability, new FelixResourceAdapter(resource)));
+						}
+					}
+				}
+			}
+		}
+		logger.debug(LOG_EXIT, "findProviders", result);
 		return result;
-	}
 
+	}
+	
 	@Override
-	public URL getContent(Resource resource) {
-		org.apache.felix.bundlerepository.Repository[] repositories = repositoryAdmin.listRepositories();
-		for (org.apache.felix.bundlerepository.Repository repository : repositories) {
-			FelixRepositoryAdapter r = new FelixRepositoryAdapter(repository);
-			URL url = r.getContent(resource);
-			if (url != null)
-				return url;
-		}
-		return null;
+	public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
+		Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>(requirements.size());
+		for (Requirement requirement : requirements)
+			result.put(requirement, findProviders(requirement));
+		return result;
 	}
 }

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractCapability.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractCapability.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractCapability.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractCapability.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,38 @@
+package org.apache.aries.subsystem.core.resource;
+
+import org.osgi.framework.resource.Capability;
+
+public abstract class AbstractCapability implements Capability {
+	@Override
+	public boolean equals(Object o) {
+		if (o == this)
+			return true;
+		if (!(o instanceof Capability))
+			return false;
+		Capability c = (Capability)o;
+		return c.getNamespace().equals(getNamespace())
+				&& c.getAttributes().equals(getAttributes())
+				&& c.getDirectives().equals(getDirectives())
+				&& c.getResource().equals(getResource());
+	}
+	
+	@Override
+	public int hashCode() {
+		int result = 17;
+		result = 31 * result + getNamespace().hashCode();
+		result = 31 * result + getAttributes().hashCode();
+		result = 31 * result + getDirectives().hashCode();
+		result = 31 * result + getResource().hashCode();
+		return result;
+	}
+	
+	@Override
+	public String toString() {
+		return new StringBuffer().append("[Capability: ")
+				.append("namespace=").append(getNamespace())
+				.append(", attributes=").append(getAttributes())
+				.append(", directives=").append(getDirectives())
+				.append(", resource=").append(getResource()).append(']')
+				.toString();
+	}
+}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractRequirement.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractRequirement.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractRequirement.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/AbstractRequirement.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,41 @@
+package org.apache.aries.subsystem.core.resource;
+
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+
+public abstract class AbstractRequirement implements Requirement {
+	@Override
+	public boolean equals(Object o) {
+		if (o == this)
+			return true;
+		if (!(o instanceof Requirement))
+			return false;
+		Requirement c = (Requirement)o;
+		return c.getNamespace().equals(getNamespace())
+				&& c.getAttributes().equals(getAttributes())
+				&& c.getDirectives().equals(getDirectives())
+				&& c.getResource() != null ? c.getResource().equals(
+				getResource()) : getResource() == null;
+	}
+	
+	@Override
+	public int hashCode() {
+		int result = 17;
+		result = 31 * result + getNamespace().hashCode();
+		result = 31 * result + getAttributes().hashCode();
+		result = 31 * result + getDirectives().hashCode();
+		result = 31 * result
+				+ (getResource() == null ? 0 : getResource().hashCode());
+		return result;
+	}
+	
+	@Override
+	public String toString() {
+		return new StringBuffer().append("[Requirement: ")
+				.append("namespace=").append(getNamespace())
+				.append(", attributes=").append(getAttributes())
+				.append(", directives=").append(getDirectives())
+				.append(", resource=").append(getResource()).append(']')
+				.toString();
+	}
+}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BasicCapability.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BasicCapability.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BasicCapability.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BasicCapability.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,51 @@
+package org.apache.aries.subsystem.core.resource;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.resource.Resource;
+
+public class BasicCapability extends AbstractCapability {
+	private final Map<String, Object> attributes;
+	private final Map<String, String> directives;
+	private final Resource resource;
+	private final String namespace;
+	
+	public BasicCapability(String namespace, Map<String, Object> attributes, Map<String, String> directives, Resource resource) {
+		if (namespace == null)
+			throw new NullPointerException();
+		this.namespace = namespace;
+		if (attributes == null)
+			this.attributes = Collections.emptyMap();
+		else
+			this.attributes = Collections.unmodifiableMap(new HashMap<String, Object>(attributes));
+		if (directives == null)
+			this.directives = Collections.emptyMap();
+		else
+			this.directives = Collections.unmodifiableMap(new HashMap<String, String>(directives));
+		if (resource == null)
+			throw new NullPointerException();
+		this.resource = resource;
+	}
+
+	@Override
+	public Map<String, Object> getAttributes() {
+		return attributes;
+	}
+
+	@Override
+	public Map<String, String> getDirectives() {
+		return directives;
+	}
+
+	@Override
+	public String getNamespace() {
+		return namespace;
+	}
+
+	@Override
+	public Resource getResource() {
+		return resource;
+	}
+}

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BundleResource.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BundleResource.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BundleResource.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/BundleResource.java Wed Feb  8 13:54:41 2012
@@ -28,8 +28,9 @@ import org.apache.aries.subsystem.core.i
 import org.osgi.framework.resource.Capability;
 import org.osgi.framework.resource.Requirement;
 import org.osgi.framework.resource.Resource;
+import org.osgi.service.repository.RepositoryContent;
 
-public class BundleResource implements Resource {
+public class BundleResource implements Resource, RepositoryContent {
 	public static BundleResource newInstance(URL content) throws IOException {
 		BundleResource result = new BundleResource(content);
 		result.capabilities.add(new OsgiIdentityCapability(result, result.manifest));
@@ -37,11 +38,13 @@ public class BundleResource implements R
 	}
 	
 	private final List<Capability> capabilities = new ArrayList<Capability>();
+	private final URL content;
 	private final BundleManifest manifest;
 	private final List<Requirement> requirements = new ArrayList<Requirement>();
 	
-	private BundleResource(InputStream content) throws IOException {
-		JarInputStream jis = new JarInputStream(content);
+	private BundleResource(URL content) throws IOException {
+		this.content = content;
+		JarInputStream jis = new JarInputStream(content.openStream());
 		try {
 			Manifest manifest = jis.getManifest();
 			if (manifest == null)
@@ -64,10 +67,6 @@ public class BundleResource implements R
 		}
 	}
 	
-	private BundleResource(URL content) throws IOException {
-		this(content.openStream());
-	}
-	
 	private BundleResource(String content) throws IOException {
 		/*
 		 * TODO
@@ -93,6 +92,11 @@ public class BundleResource implements R
 		}
 		return result;
 	}
+	
+	@Override
+	public InputStream getContent() throws IOException {
+		return content.openStream();
+	}
 
 	public List<Requirement> getRequirements(String namespace) {
 		/* Requirements

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemDirectoryResource.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemDirectoryResource.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemDirectoryResource.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemDirectoryResource.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,66 @@
+package org.apache.aries.subsystem.core.resource;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.Manifest;
+
+import org.apache.aries.subsystem.core.archive.SubsystemSymbolicNameHeader;
+import org.apache.aries.subsystem.core.internal.OsgiIdentityCapability;
+import org.apache.aries.util.filesystem.FileSystem;
+import org.apache.aries.util.filesystem.IDirectory;
+import org.apache.aries.util.manifest.ManifestProcessor;
+import org.osgi.framework.Version;
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.ResourceConstants;
+import org.osgi.service.repository.RepositoryContent;
+import org.osgi.service.subsystem.SubsystemConstants;
+
+public class SubsystemDirectoryResource implements Resource, RepositoryContent {
+	private final List<Capability> capabilities;
+	private final IDirectory directory;
+	
+	public SubsystemDirectoryResource(File content) throws IOException {
+		this(FileSystem.getFSRoot(content));
+	}
+	
+	public SubsystemDirectoryResource(IDirectory content) throws IOException {
+		if (!content.isDirectory())
+			throw new IllegalArgumentException("The content must represent a directory: " + content);
+		this.directory = content;
+		Manifest manifest = ManifestProcessor.obtainManifestFromAppDir(content, "OSGI-INF/DEPLOYMENT.MF");
+		if (manifest == null)
+			manifest = ManifestProcessor.obtainManifestFromAppDir(content, "OSGI-INF/SUBSYSTEM.MF");
+		String symbolicName = new SubsystemSymbolicNameHeader(manifest
+				.getMainAttributes().getValue(
+						SubsystemConstants.SUBSYSTEM_SYMBOLICNAME))
+				.getSymbolicName();
+		Version version = Version.parseVersion(manifest.getMainAttributes()
+				.getValue(SubsystemConstants.SUBSYSTEM_VERSION));
+		List<Capability> capabilities = new ArrayList<Capability>(1);
+		capabilities.add(new OsgiIdentityCapability(this, symbolicName, version, SubsystemConstants.IDENTITY_TYPE_SUBSYSTEM));
+		this.capabilities = Collections.unmodifiableList(capabilities);
+	}
+	
+	@Override
+	public List<Capability> getCapabilities(String namespace) {
+		if (namespace == null || ResourceConstants.IDENTITY_NAMESPACE.equals(namespace))
+			return capabilities;
+		return Collections.emptyList();
+	}
+
+	@Override
+	public InputStream getContent() throws IOException {
+		return directory.open();
+	}
+
+	@Override
+	public List<Requirement> getRequirements(String namespace) {
+		return Collections.emptyList();
+	}
+}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemFileResource.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemFileResource.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemFileResource.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemFileResource.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,88 @@
+package org.apache.aries.subsystem.core.resource;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipInputStream;
+
+import org.apache.aries.subsystem.core.archive.SubsystemSymbolicNameHeader;
+import org.apache.aries.subsystem.core.internal.OsgiIdentityCapability;
+import org.apache.aries.util.filesystem.FileSystem;
+import org.apache.aries.util.filesystem.IDirectory;
+import org.apache.aries.util.manifest.ManifestProcessor;
+import org.osgi.framework.Version;
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.ResourceConstants;
+import org.osgi.service.repository.RepositoryContent;
+import org.osgi.service.subsystem.SubsystemConstants;
+
+public class SubsystemFileResource implements Resource, RepositoryContent {
+	private static final String REGEX = "([^@])(?:@(.*))?.ssa";
+	private static final Pattern PATTERN = Pattern.compile(REGEX);
+	
+	private final List<Capability> capabilities;
+	private final IDirectory directory;
+	private final File file;
+	
+	public SubsystemFileResource(File content) throws IOException {
+		file = content;
+		directory = FileSystem.getFSRoot(content);
+		Manifest manifest = ManifestProcessor.obtainManifestFromAppDir(directory, "OSGI-INF/DEPLOYMENT.MF");
+		if (manifest == null)
+			manifest = ManifestProcessor.obtainManifestFromAppDir(directory, "OSGI-INF/SUBSYSTEM.MF");
+		String symbolicName = null;
+		Version version = Version.emptyVersion;
+		if (manifest != null) {
+			String value = manifest.getMainAttributes().getValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME);
+			if (value != null)
+				symbolicName = new SubsystemSymbolicNameHeader(value).getSymbolicName();
+			value = manifest.getMainAttributes().getValue(SubsystemConstants.SUBSYSTEM_VERSION);
+			if (value != null)
+				version = Version.parseVersion(value);
+		}
+		Matcher matcher = PATTERN.matcher(content.getName());;
+		if (symbolicName == null) {
+			if (!matcher.matches())
+				throw new IllegalArgumentException("No symbolic name");
+			symbolicName = new SubsystemSymbolicNameHeader(matcher.group(1)).getSymbolicName();
+		}
+		if (version == Version.emptyVersion && matcher.matches()) {
+			String group = matcher.group(2);
+			if (group != null)
+				version = Version.parseVersion(group);
+		}
+		List<Capability> capabilities = new ArrayList<Capability>(1);
+		capabilities.add(new OsgiIdentityCapability(this, symbolicName, version, SubsystemConstants.IDENTITY_TYPE_SUBSYSTEM));
+		this.capabilities = Collections.unmodifiableList(capabilities);
+	}
+	
+	@Override
+	public List<Capability> getCapabilities(String namespace) {
+		if (namespace == null || ResourceConstants.IDENTITY_NAMESPACE.equals(namespace))
+			return capabilities;
+		return Collections.emptyList();
+	}
+
+	@Override
+	public InputStream getContent() throws IOException {
+		return new FileInputStream(file);
+	}
+	
+	public String getLocation() {
+		return file.getAbsolutePath();
+	}
+
+	@Override
+	public List<Requirement> getRequirements(String namespace) {
+		return Collections.emptyList();
+	}
+}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemStreamResource.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemStreamResource.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemStreamResource.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/resource/SubsystemStreamResource.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,94 @@
+package org.apache.aries.subsystem.core.resource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.Manifest;
+
+import org.apache.aries.subsystem.core.archive.SubsystemSymbolicNameHeader;
+import org.apache.aries.subsystem.core.internal.OsgiIdentityCapability;
+import org.apache.aries.subsystem.core.internal.SubsystemUri;
+import org.apache.aries.util.filesystem.FileSystem;
+import org.apache.aries.util.filesystem.ICloseableDirectory;
+import org.apache.aries.util.io.IOUtils;
+import org.apache.aries.util.manifest.ManifestProcessor;
+import org.osgi.framework.Version;
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.ResourceConstants;
+import org.osgi.service.repository.RepositoryContent;
+import org.osgi.service.subsystem.SubsystemConstants;
+
+public class SubsystemStreamResource implements Resource, RepositoryContent {
+	private final List<Capability> capabilities;
+	private final ICloseableDirectory directory;
+	
+	public SubsystemStreamResource(String location, InputStream content) throws IOException, URISyntaxException {
+		SubsystemUri uri = null;
+		try {
+			if (location.startsWith("subsystem://"))
+				uri = new SubsystemUri(location);
+			if (content == null) {
+				if (uri != null)
+					content = uri.getURL().openStream();
+				else
+					content = new URL(location).openStream();
+			}
+			directory = FileSystem.getFSRoot(content);
+			if (directory == null)
+				throw new IOException("Unable to parse content of " + location);
+		}
+		finally {
+			IOUtils.close(content);
+		}
+		Manifest manifest = ManifestProcessor.obtainManifestFromAppDir(directory, "OSGI-INF/DEPLOYMENT.MF");
+		if (manifest == null)
+			manifest = ManifestProcessor.obtainManifestFromAppDir(directory, "OSGI-INF/SUBSYSTEM.MF");
+		String symbolicName = null;
+		Version version = Version.emptyVersion;
+		if (manifest != null) {
+			String value = manifest.getMainAttributes().getValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME);
+			if (value != null)
+				symbolicName = new SubsystemSymbolicNameHeader(value).getSymbolicName();
+			value = manifest.getMainAttributes().getValue(SubsystemConstants.SUBSYSTEM_VERSION);
+			if (value != null)
+				version = Version.parseVersion(value);
+		}
+		if (symbolicName == null) {
+			if (uri == null)
+				throw new IllegalArgumentException("No symbolic name");
+			symbolicName = uri.getSymbolicName();
+		}
+		if (version == Version.emptyVersion && uri != null)
+			version = uri.getVersion();
+		List<Capability> capabilities = new ArrayList<Capability>(1);
+		capabilities.add(new OsgiIdentityCapability(this, symbolicName, version, SubsystemConstants.IDENTITY_TYPE_SUBSYSTEM));
+		this.capabilities = Collections.unmodifiableList(capabilities);
+	}
+	
+	public void close() {
+		IOUtils.close(directory);
+	}
+	
+	@Override
+	public List<Capability> getCapabilities(String namespace) {
+		if (namespace == null || ResourceConstants.IDENTITY_NAMESPACE.equals(namespace))
+			return capabilities;
+		return Collections.emptyList();
+	}
+
+	@Override
+	public InputStream getContent() throws IOException {
+		return directory.open();
+	}
+
+	@Override
+	public List<Requirement> getRequirements(String namespace) {
+		return Collections.emptyList();
+	}
+}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixCapability.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixCapability.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixCapability.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixCapability.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver;
+
+import java.util.List;
+
+public interface FelixCapability
+{
+    List<String> getUses();
+}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixEnvironment.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixEnvironment.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixEnvironment.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixEnvironment.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver;
+
+import org.osgi.framework.resource.Resource;
+import org.osgi.service.resolver.Environment;
+import org.osgi.service.resolver.ResolutionException;
+
+public interface FelixEnvironment extends Environment
+{
+    void checkExecutionEnvironment(Resource resource) throws ResolutionException;
+    void checkNativeLibraries(Resource resource) throws ResolutionException;
+}
\ No newline at end of file

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixResolver.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixResolver.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixResolver.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/FelixResolver.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import org.osgi.framework.resource.Capability;
+import org.osgi.framework.resource.Requirement;
+import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.Wire;
+import org.osgi.service.resolver.Resolver;
+
+public interface FelixResolver extends Resolver
+{
+    Map<Resource, List<Wire>> resolve(
+        FelixEnvironment env,
+        Collection<? extends Resource> mandatoryRevisions,
+        Collection<? extends Resource> optionalRevisions,
+        Collection<? extends Resource> ondemandFragments);
+    Map<Resource, List<Wire>> resolve(
+        FelixEnvironment env,
+        Resource resource,
+        Requirement dynReq,
+        SortedSet<Capability> cands,
+        Collection<? extends Resource> ondemandFragments);
+}
\ No newline at end of file

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/Logger.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/Logger.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/Logger.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/Logger.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver;
+
+public interface Logger
+{
+    static final int LOG_ERROR = 1;
+    static final int LOG_WARNING = 2;
+    static final int LOG_INFO = 3;
+    static final int LOG_DEBUG = 4;
+
+    void log(int level, String msg);
+
+    void log(int level, String msg, Throwable throwable);
+}
\ No newline at end of file

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Activator.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Activator.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Activator.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/felix/resolver/impl/Activator.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver.impl;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator
+{
+    public void start(BundleContext bc) throws Exception
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public void stop(BundleContext bc) throws Exception
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
\ No newline at end of file