FELIX-2110: The resolver should be able to resolve for some requirements in addition to resources

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@912353 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
index 4209595..3ee0d5f 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
@@ -33,6 +33,7 @@
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.obr.Repository;
 import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Requirement;
 import org.osgi.service.obr.Resolver;
 import org.osgi.service.obr.Resource;
 
@@ -163,6 +164,21 @@
         return resources;
     }
 
+    public Requirement requirement(String name, String filter) {
+        RequirementImpl req = new RequirementImpl();
+        req.setName(name);
+        if (filter != null)
+        {
+            req.setFilter(filter);
+        }
+        return req;
+    }
+
+    public Filter filter(String filter) throws InvalidSyntaxException
+    {
+        return new FilterImpl(filter);
+    }
+
     private void initialize()
     {
         m_initialized = true;
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
index 6b58621..5f6dd3d 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
@@ -34,6 +34,7 @@
     private final Logger m_logger;
     private final LocalRepositoryImpl m_local;
     private final Set m_addedSet = new HashSet();
+    private final Set m_addedRequirementSet = new HashSet();
     private final Set m_failedSet = new HashSet();
     private final Set m_resolveSet = new HashSet();
     private final Set m_requiredSet = new HashSet();
@@ -49,7 +50,7 @@
         m_context = context;
         m_admin = admin;
         m_logger = logger;
-        m_local = admin.getLocalRepository();
+        m_local = admin.getLocalRepository();        
         String s = context.getProperty(PREFER_LOCAL);
         if (s != null)
         {
@@ -63,6 +64,22 @@
         m_addedSet.add(resource);
     }
 
+    public synchronized Resource[] getAddedResources()
+    {
+        return (Resource[]) m_addedSet.toArray(new Resource[m_addedSet.size()]);
+    }
+
+    public synchronized void add(Requirement requirement)
+    {
+        m_resolved = false;
+        m_addedRequirementSet.add(requirement);
+    }
+
+    public synchronized Requirement[] getAddedRequirements()
+    {
+        return (Requirement[]) m_addedRequirementSet.toArray(new Requirement[m_addedRequirementSet.size()]);
+    }
+
     public synchronized Requirement[] getUnsatisfiedRequirements()
     {
         if (m_resolved)
@@ -114,11 +131,6 @@
         throw new IllegalStateException("The resources have not been resolved.");
     }
 
-    public synchronized Resource[] getAddedResources()
-    {
-        return (Resource[]) m_addedSet.toArray(new Resource[m_addedSet.size()]);
-    }
-
     public synchronized boolean resolve()
     {
         // time of the resolution process start
@@ -135,6 +147,20 @@
 
         boolean result = true;
 
+        // Add a fake resource if needed
+        if (!m_addedRequirementSet.isEmpty())
+        {
+            ResourceImpl fake = new ResourceImpl();
+            for (Iterator iter = m_addedRequirementSet.iterator(); iter.hasNext(); )
+            {
+                fake.addRequire((Requirement) iter.next());
+            }
+            if (!resolve(fake))
+            {
+                result = false;
+            }
+        }
+
         // Loop through each resource in added list and resolve.
         for (Iterator iter = m_addedSet.iterator(); iter.hasNext(); )
         {
diff --git a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/ResolverImplTest.java b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/ResolverImplTest.java
index 293ef34..65bcca1 100644
--- a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/ResolverImplTest.java
+++ b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/ResolverImplTest.java
@@ -53,6 +53,16 @@
 
     }
 
+    public void testResolveReq() throws Exception 
+    {
+        RepositoryAdminImpl repoAdmin = createRepositoryAdmin();
+        repoAdmin.addRepository(getClass().getResource("/repo_for_resolvertest.xml"));
+
+        Resolver resolver = repoAdmin.resolver();
+        resolver.add(repoAdmin.requirement("package", "(package=org.apache.felix.test.osgi)"));
+        assertTrue(resolver.resolve());
+    }
+
     public static void main(String[] args) throws Exception {
 
         new ResolverImplTest().testReferral1();
diff --git a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/RepositoryAdmin.java b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/RepositoryAdmin.java
index 7468871..29fad00 100644
--- a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/RepositoryAdmin.java
+++ b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/RepositoryAdmin.java
@@ -23,6 +23,9 @@
 
 import java.net.URL;
 
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
 /**
  * Provides centralized access to the distributed repository.
  * 
@@ -75,7 +78,6 @@
     /**
      * Create a resolver.
      * 
-     * @param resource
      * @return
      */
     Resolver resolver();
@@ -100,5 +102,22 @@
      */
     Repository[] listRepositories();
 
-    Resource getResource(String respositoryId);
+    Resource getResource(String repositoryId);
+
+    /**
+     * Create a simple requirement to be used for selection
+     * @param name
+     * @param filter
+     * @return
+     */
+    Requirement requirement(String name, String filter) throws InvalidSyntaxException;
+
+    /**
+     * Create an extender filter supporting the SUBSET, SUPERSET and other extensions
+     *
+     * @param filter the string filter
+     * @return
+     */
+    Filter filter(String filter) throws InvalidSyntaxException;
+
 }
\ No newline at end of file
diff --git a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resolver.java b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resolver.java
index 629159b..a8a552d 100644
--- a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resolver.java
+++ b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resolver.java
@@ -24,8 +24,42 @@
 public interface Resolver
 {
 
+    /**
+     * Add the following resource to the resolution.
+     *
+     * The resource will be part of the output and all its requirements
+     * will be satisfied.
+     *
+     * It has the same effect has adding a requirement that will match
+     * this resource by symbolicname and version.
+     *
+     * The current resolution will be lost after adding a resource.
+     *
+     * @param resource the resource to add
+     */
     void add(Resource resource);
 
+    /**
+     * Returns the list of resources that have been added to the resolution
+     * @return
+     */
+    Resource[] getAddedResources();
+
+    /**
+     * Add the following requirement to the resolution
+     *
+     * The current resolution will be lost after adding a requirement.
+     *
+     * @param requirement the requirement to add
+     */
+    void add(Requirement requirement);
+
+    /**
+     * Returns the list of requirements that have been added to the resolution
+     * @return
+     */
+    Requirement[] getAddedRequirements();
+
     Requirement[] getUnsatisfiedRequirements();
 
     Resource[] getOptionalResources();
@@ -36,8 +70,6 @@
 
     Resource[] getRequiredResources();
 
-    Resource[] getAddedResources();
-
     boolean resolve();
 
     void deploy(boolean start);