FELIX-2106, FELIX-692: Control which repositories are used for a given resolver

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@915288 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundlerepository/pom.xml b/bundlerepository/pom.xml
index 058a13a..5f41be9 100644
--- a/bundlerepository/pom.xml
+++ b/bundlerepository/pom.xml
@@ -65,6 +65,11 @@
         <version>4.0.7</version>
         <optional>true</optional>
     </dependency>
+    <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymock</artifactId>
+        <version>2.4</version>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java
index 4614aba..093cdca 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java
@@ -19,25 +19,15 @@
 package org.apache.felix.bundlerepository;
 
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
 
 import org.osgi.framework.AllServiceListener;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
-import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceReference;
 import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.service.obr.Repository;
 import org.osgi.service.obr.Resource;
@@ -98,10 +88,15 @@
          * is synchronized on this instance to prevent data structure
          * corruption.
          */
-        
+
+        // Ignore system bundle
+        if (bundle.getBundleId() == 0)
+        {
+            return;
+        }
         try
         {
-            m_localResourceList.put(new Long(bundle.getBundleId()), new LocalResourceImpl(bundle, m_logger));
+            m_localResourceList.put(new Long(bundle.getBundleId()), new LocalResourceImpl(bundle));
         }
         catch (InvalidSyntaxException ex)
         {
@@ -149,6 +144,11 @@
         return (Resource[]) m_localResourceList.values().toArray(new Resource[m_localResourceList.size()]);
     }
 
+    public boolean isLocal()
+    {
+        return true;
+    }
+
     private void initialize()
     {
         // register for bundle and service events now
@@ -173,314 +173,4 @@
         }
     }
 
-    public static class LocalResourceImpl extends ResourceImpl
-    {
-        private Bundle m_bundle = null;
-
-        LocalResourceImpl(Bundle bundle, Logger logger) throws InvalidSyntaxException
-        {
-            this(null, bundle, logger);
-        }
-
-        LocalResourceImpl(ResourceImpl resource, Bundle bundle, Logger logger)
-            throws InvalidSyntaxException
-        {
-            super(resource);
-            m_bundle = bundle;
-            initialize();
-        }
-
-        public Bundle getBundle()
-        {
-            return m_bundle;
-        }
-
-        private void initialize() throws InvalidSyntaxException
-        {
-            Dictionary dict = m_bundle.getHeaders();
-
-            // Convert bundle manifest header attributes to resource properties.
-            convertAttributesToProperties(dict);
-
-            // Convert properties to bundle capability
-            convertAttributesToBundleCapability();
-
-            // Convert import package declarations into requirements.
-            convertImportPackageToRequirement(dict);
-
-            // Convert import service declarations into requirements.
-            convertImportServiceToRequirement(dict);
-
-            // Convert export package declarations into capabilities.
-            convertExportPackageToCapability(dict);
-
-            // Convert export service declarations and services into capabilities.
-            convertExportServiceToCapability(dict, m_bundle);
-
-            // For the system bundle, add a special platform capability.
-            if (m_bundle.getBundleId() == 0)
-            {
-                // set the execution environment(s) as Capability ee of the
-                // system bundle to resolve bundles with specifc requirements
-                String ee = m_bundle.getBundleContext().getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
-                if (ee != null)
-                {
-                    StringTokenizer tokener = new StringTokenizer(ee, ",");
-                    List eeList = new ArrayList();
-                    while (tokener.hasMoreTokens())
-                    {
-                        String eeName = tokener.nextToken().trim();
-                        if (eeName.length() > 0)
-                        {
-                            eeList.add(eeName);
-                        }
-                    }
-                    CapabilityImpl cap = new CapabilityImpl();
-                    cap.setName("ee");
-                    cap.addP("ee", eeList);
-                    addCapability(cap);
-                }
-                
-/* TODO: OBR - Fix system capabilities.
-                // Create a case-insensitive map.
-                Map map = new TreeMap(new Comparator() {
-                    public int compare(Object o1, Object o2)
-                    {
-                        return o1.toString().compareToIgnoreCase(o2.toString());
-                    }
-                });
-                map.put(
-                    Constants.FRAMEWORK_VERSION,
-                    m_context.getProperty(Constants.FRAMEWORK_VERSION));
-                map.put(
-                    Constants.FRAMEWORK_VENDOR,
-                    m_context.getProperty(Constants.FRAMEWORK_VENDOR));
-                map.put(
-                    Constants.FRAMEWORK_LANGUAGE,
-                    m_context.getProperty(Constants.FRAMEWORK_LANGUAGE));
-                map.put(
-                    Constants.FRAMEWORK_OS_NAME,
-                    m_context.getProperty(Constants.FRAMEWORK_OS_NAME));
-                map.put(
-                    Constants.FRAMEWORK_OS_VERSION,
-                    m_context.getProperty(Constants.FRAMEWORK_OS_VERSION));
-                map.put(
-                    Constants.FRAMEWORK_PROCESSOR,
-                    m_context.getProperty(Constants.FRAMEWORK_PROCESSOR));
-//                map.put(
-//                    FelixConstants.FELIX_VERSION_PROPERTY,
-//                    m_context.getProperty(FelixConstants.FELIX_VERSION_PROPERTY));
-                Map[] capMaps = (Map[]) bundleMap.get("capability");
-                if (capMaps == null)
-                {
-                    capMaps = new Map[] { map };
-                }
-                else
-                {
-                    Map[] newCaps = new Map[capMaps.length + 1];
-                    newCaps[0] = map;
-                    System.arraycopy(capMaps, 0, newCaps, 1, capMaps.length);
-                    capMaps = newCaps;
-                }
-                bundleMap.put("capability", capMaps);
-*/
-            }
-        }
-
-        private void convertAttributesToProperties(Dictionary dict)
-        {
-            for (Enumeration keys = dict.keys(); keys.hasMoreElements(); )
-            {
-                String key = (String) keys.nextElement();
-                if (key.equalsIgnoreCase(Constants.BUNDLE_SYMBOLICNAME))
-                {
-                    String sn = (String) dict.get(key);
-                    sn = sn.trim();
-                    int index = sn.indexOf(";singleton:=true");
-                    if (index != -1) {
-                        sn = sn.substring(0, index);
-                    }
-                    put(Resource.SYMBOLIC_NAME, sn);    
-                }
-                else if (key.equalsIgnoreCase(Constants.BUNDLE_NAME))
-                {
-                    put(Resource.PRESENTATION_NAME, (String) dict.get(key));
-                }
-                else if (key.equalsIgnoreCase(Constants.BUNDLE_VERSION))
-                {
-                    put(Resource.VERSION, (String) dict.get(key));
-                }
-                else if (key.equalsIgnoreCase("Bundle-Source"))
-                {
-                    put(Resource.SOURCE_URL, (String) dict.get(key));
-                }
-                else if (key.equalsIgnoreCase(Constants.BUNDLE_DESCRIPTION))
-                {
-                    put(Resource.DESCRIPTION, (String) dict.get(key));
-                }
-                else if (key.equalsIgnoreCase(Constants.BUNDLE_DOCURL))
-                {
-                    put(Resource.DOCUMENTATION_URL, (String) dict.get(key));
-                }
-                else if (key.equalsIgnoreCase(Constants.BUNDLE_COPYRIGHT))
-                {
-                    put(Resource.COPYRIGHT, (String) dict.get(key));
-                }
-                else if (key.equalsIgnoreCase("Bundle-License"))
-                {
-                    put(Resource.LICENSE_URL, (String) dict.get(key));
-                }
-            }
-        }
-
-        private void convertAttributesToBundleCapability()
-        {
-            CapabilityImpl cap = new CapabilityImpl();
-            cap.setName("bundle");
-            if (getPresentationName() != null) {
-                cap.addP(Resource.PRESENTATION_NAME, getPresentationName());
-            }
-            cap.addP(Resource.SYMBOLIC_NAME, getSymbolicName());
-            cap.addP(Resource.VERSION, getVersion());
-            addCapability(cap);
-        }
-
-        private void convertImportPackageToRequirement(Dictionary dict)
-            throws InvalidSyntaxException
-        {
-            String target = (String) dict.get(Constants.IMPORT_PACKAGE);
-            if (target != null)
-            {
-                R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
-                R4Import[] imports = new R4Import[pkgs.length];
-                for (int i = 0; i < pkgs.length; i++)
-                {
-                    imports[i] = new R4Import(pkgs[i]);
-                }
-
-                for (int impIdx = 0; impIdx < imports.length; impIdx++)
-                {
-                    RequirementImpl req = new RequirementImpl();
-                    req.setMultiple("false");
-                    req.setOptional(Boolean.toString(imports[impIdx].isOptional()));
-                    req.setName("package");
-                    req.addText("Import package " + imports[impIdx].toString());
-                    
-                    String low = imports[impIdx].isLowInclusive()
-                                ? "(version>=" + imports[impIdx].getVersion() + ")"
-                                : "(!(version<=" + imports[impIdx].getVersion() + "))";
-
-                    if (imports[impIdx].getVersionHigh() != null)
-                    {
-                        String high = imports[impIdx].isHighInclusive()
-                            ? "(version<=" + imports[impIdx].getVersionHigh() + ")"
-                            : "(!(version>=" + imports[impIdx].getVersionHigh() + "))";
-                        req.setFilter("(&(package="
-                            + imports[impIdx].getName() + ")"
-                            + low + high + ")");
-                    }
-                    else
-                    {
-                        req.setFilter(
-                            "(&(package="
-                            + imports[impIdx].getName() + ")"
-                            + low + ")");
-                    }
-
-                    addRequire(req);
-                }
-            }
-        }
-
-        private void convertImportServiceToRequirement(Dictionary dict)
-            throws InvalidSyntaxException
-        {
-            String target = (String) dict.get(Constants.IMPORT_SERVICE);
-            if (target != null)
-            {
-                R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
-                for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
-                {
-                    RequirementImpl req = new RequirementImpl();
-                    req.setMultiple("false");
-                    req.setName("service");
-                    req.addText("Import service " + pkgs[pkgIdx].toString());
-                    req.setFilter("(service="
-                        + pkgs[pkgIdx].getName() + ")");
-                    addRequire(req);
-                }
-            }
-        }
-
-        private void convertExportPackageToCapability(Dictionary dict)
-        {
-            String target = (String) dict.get(Constants.EXPORT_PACKAGE);
-            if (target != null)
-            {
-                R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
-                for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
-                {
-                    CapabilityImpl cap = new CapabilityImpl();
-                    cap.setName("package");
-                    cap.addP(new PropertyImpl("package", null, pkgs[pkgIdx].getName()));
-                    cap.addP(new PropertyImpl("version", "version", pkgs[pkgIdx].getVersion().toString()));
-                    for (int i = 0; i < pkgs[pkgIdx].getAttributes().length; i++)
-                    {
-                        R4Attribute attribute = pkgs[pkgIdx].getAttributes()[i];
-                        String key = attribute.getName();
-                        if (!key.equalsIgnoreCase("specification-version")
-                            && !key.equalsIgnoreCase("version"))
-                        {
-                            Object value = attribute.getValue();
-                            cap.addP(key, value);
-                        }
-                    }
-                    for (int i = 0; i < pkgs[pkgIdx].getDirectives().length; i++)
-                    {
-                        R4Directive directive = pkgs[pkgIdx].getDirectives()[i];
-                        String key = directive.getName() + ":";
-                        Object value = directive.getValue();
-                        cap.addP(key, value);
-                    }
-                    addCapability(cap);
-                }
-            }
-        }
-
-        private void convertExportServiceToCapability(Dictionary dict, Bundle bundle)
-        {
-            Set services = new HashSet();
-
-            // collect Export-Service
-            String target = (String) dict.get(Constants.EXPORT_SERVICE);
-            if (target != null)
-            {
-                R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
-                for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
-                {
-                    services.add(pkgs[pkgIdx].getName());
-                }
-            }
-
-            // add actual registered services
-            ServiceReference[] refs = bundle.getRegisteredServices();
-            for (int i = 0; refs != null && i < refs.length; i++)
-            {
-                String[] cls = (String[]) refs[i].getProperty(Constants.OBJECTCLASS);
-                for (int j = 0; cls != null && j < cls.length; j++)
-                {
-                    services.add(cls[j]);
-                }
-            }
-
-            // register capabilities for combined set
-            for (Iterator si = services.iterator(); si.hasNext();)
-            {
-                CapabilityImpl cap = new CapabilityImpl();
-                cap.setName("service");
-                cap.addP(new PropertyImpl("service", null, (String) si.next()));
-                addCapability(cap);
-            }
-        }
-    }
 }
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalResourceImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalResourceImpl.java
new file mode 100644
index 0000000..785efec
--- /dev/null
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalResourceImpl.java
@@ -0,0 +1,345 @@
+/*
+ * 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.bundlerepository;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.obr.Resource;
+
+public class LocalResourceImpl extends ResourceImpl
+{
+    private Bundle m_bundle = null;
+
+    LocalResourceImpl(Bundle bundle) throws InvalidSyntaxException
+    {
+        this(null, bundle);
+    }
+
+    LocalResourceImpl(ResourceImpl resource, Bundle bundle)
+        throws InvalidSyntaxException
+    {
+        super(resource);
+        m_bundle = bundle;
+        initialize();
+    }
+
+    public Bundle getBundle()
+    {
+        return m_bundle;
+    }
+
+    private void initialize() throws InvalidSyntaxException
+    {
+        Dictionary dict = m_bundle.getHeaders();
+
+        // Convert bundle manifest header attributes to resource properties.
+        convertAttributesToProperties(dict);
+
+        // Convert properties to bundle capability
+        convertAttributesToBundleCapability();
+
+        // Convert import package declarations into requirements.
+        convertImportPackageToRequirement(dict);
+
+        // Convert import service declarations into requirements.
+        convertImportServiceToRequirement(dict);
+
+        // Convert export package declarations into capabilities.
+        convertExportPackageToCapability(dict);
+
+        // Convert export service declarations and services into capabilities.
+        convertExportServiceToCapability(dict, m_bundle);
+
+        // For the system bundle, add a special platform capability.
+        if (m_bundle.getBundleId() == 0)
+        {
+            // set the execution environment(s) as Capability ee of the
+            // system bundle to resolve bundles with specifc requirements
+            String ee = m_bundle.getBundleContext().getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
+            if (ee != null)
+            {
+                StringTokenizer tokener = new StringTokenizer(ee, ",");
+                List eeList = new ArrayList();
+                while (tokener.hasMoreTokens())
+                {
+                    String eeName = tokener.nextToken().trim();
+                    if (eeName.length() > 0)
+                    {
+                        eeList.add(eeName);
+                    }
+                }
+                CapabilityImpl cap = new CapabilityImpl();
+                cap.setName("ee");
+                cap.addP("ee", eeList);
+                addCapability(cap);
+            }
+
+/* TODO: OBR - Fix system capabilities.
+            // Create a case-insensitive map.
+            Map map = new TreeMap(new Comparator() {
+                public int compare(Object o1, Object o2)
+                {
+                    return o1.toString().compareToIgnoreCase(o2.toString());
+                }
+            });
+            map.put(
+                Constants.FRAMEWORK_VERSION,
+                m_context.getProperty(Constants.FRAMEWORK_VERSION));
+            map.put(
+                Constants.FRAMEWORK_VENDOR,
+                m_context.getProperty(Constants.FRAMEWORK_VENDOR));
+            map.put(
+                Constants.FRAMEWORK_LANGUAGE,
+                m_context.getProperty(Constants.FRAMEWORK_LANGUAGE));
+            map.put(
+                Constants.FRAMEWORK_OS_NAME,
+                m_context.getProperty(Constants.FRAMEWORK_OS_NAME));
+            map.put(
+                Constants.FRAMEWORK_OS_VERSION,
+                m_context.getProperty(Constants.FRAMEWORK_OS_VERSION));
+            map.put(
+                Constants.FRAMEWORK_PROCESSOR,
+                m_context.getProperty(Constants.FRAMEWORK_PROCESSOR));
+//                map.put(
+//                    FelixConstants.FELIX_VERSION_PROPERTY,
+//                    m_context.getProperty(FelixConstants.FELIX_VERSION_PROPERTY));
+            Map[] capMaps = (Map[]) bundleMap.get("capability");
+            if (capMaps == null)
+            {
+                capMaps = new Map[] { map };
+            }
+            else
+            {
+                Map[] newCaps = new Map[capMaps.length + 1];
+                newCaps[0] = map;
+                System.arraycopy(capMaps, 0, newCaps, 1, capMaps.length);
+                capMaps = newCaps;
+            }
+            bundleMap.put("capability", capMaps);
+*/
+        }
+    }
+
+    private void convertAttributesToProperties(Dictionary dict)
+    {
+        for (Enumeration keys = dict.keys(); keys.hasMoreElements(); )
+        {
+            String key = (String) keys.nextElement();
+            if (key.equalsIgnoreCase(Constants.BUNDLE_SYMBOLICNAME))
+            {
+                String sn = (String) dict.get(key);
+                sn = sn.trim();
+                int index = sn.indexOf(";singleton:=true");
+                if (index != -1) {
+                    sn = sn.substring(0, index);
+                }
+                put(Resource.SYMBOLIC_NAME, sn);
+            }
+            else if (key.equalsIgnoreCase(Constants.BUNDLE_NAME))
+            {
+                put(Resource.PRESENTATION_NAME, (String) dict.get(key));
+            }
+            else if (key.equalsIgnoreCase(Constants.BUNDLE_VERSION))
+            {
+                put(Resource.VERSION, (String) dict.get(key));
+            }
+            else if (key.equalsIgnoreCase("Bundle-Source"))
+            {
+                put(Resource.SOURCE_URL, (String) dict.get(key));
+            }
+            else if (key.equalsIgnoreCase(Constants.BUNDLE_DESCRIPTION))
+            {
+                put(Resource.DESCRIPTION, (String) dict.get(key));
+            }
+            else if (key.equalsIgnoreCase(Constants.BUNDLE_DOCURL))
+            {
+                put(Resource.DOCUMENTATION_URL, (String) dict.get(key));
+            }
+            else if (key.equalsIgnoreCase(Constants.BUNDLE_COPYRIGHT))
+            {
+                put(Resource.COPYRIGHT, (String) dict.get(key));
+            }
+            else if (key.equalsIgnoreCase("Bundle-License"))
+            {
+                put(Resource.LICENSE_URL, (String) dict.get(key));
+            }
+        }
+    }
+
+    private void convertAttributesToBundleCapability()
+    {
+        CapabilityImpl cap = new CapabilityImpl();
+        cap.setName("bundle");
+        if (getPresentationName() != null) {
+            cap.addP(Resource.PRESENTATION_NAME, getPresentationName());
+        }
+        cap.addP(Resource.SYMBOLIC_NAME, getSymbolicName());
+        cap.addP(Resource.VERSION, getVersion());
+        addCapability(cap);
+    }
+
+    private void convertImportPackageToRequirement(Dictionary dict)
+        throws InvalidSyntaxException
+    {
+        String target = (String) dict.get(Constants.IMPORT_PACKAGE);
+        if (target != null)
+        {
+            R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
+            R4Import[] imports = new R4Import[pkgs.length];
+            for (int i = 0; i < pkgs.length; i++)
+            {
+                imports[i] = new R4Import(pkgs[i]);
+            }
+
+            for (int impIdx = 0; impIdx < imports.length; impIdx++)
+            {
+                RequirementImpl req = new RequirementImpl();
+                req.setMultiple("false");
+                req.setOptional(Boolean.toString(imports[impIdx].isOptional()));
+                req.setName("package");
+                req.addText("Import package " + imports[impIdx].toString());
+
+                String low = imports[impIdx].isLowInclusive()
+                            ? "(version>=" + imports[impIdx].getVersion() + ")"
+                            : "(!(version<=" + imports[impIdx].getVersion() + "))";
+
+                if (imports[impIdx].getVersionHigh() != null)
+                {
+                    String high = imports[impIdx].isHighInclusive()
+                        ? "(version<=" + imports[impIdx].getVersionHigh() + ")"
+                        : "(!(version>=" + imports[impIdx].getVersionHigh() + "))";
+                    req.setFilter("(&(package="
+                        + imports[impIdx].getName() + ")"
+                        + low + high + ")");
+                }
+                else
+                {
+                    req.setFilter(
+                        "(&(package="
+                        + imports[impIdx].getName() + ")"
+                        + low + ")");
+                }
+
+                addRequire(req);
+            }
+        }
+    }
+
+    private void convertImportServiceToRequirement(Dictionary dict)
+        throws InvalidSyntaxException
+    {
+        String target = (String) dict.get(Constants.IMPORT_SERVICE);
+        if (target != null)
+        {
+            R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
+            for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
+            {
+                RequirementImpl req = new RequirementImpl();
+                req.setMultiple("false");
+                req.setName("service");
+                req.addText("Import service " + pkgs[pkgIdx].toString());
+                req.setFilter("(service="
+                    + pkgs[pkgIdx].getName() + ")");
+                addRequire(req);
+            }
+        }
+    }
+
+    private void convertExportPackageToCapability(Dictionary dict)
+    {
+        String target = (String) dict.get(Constants.EXPORT_PACKAGE);
+        if (target != null)
+        {
+            R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
+            for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
+            {
+                CapabilityImpl cap = new CapabilityImpl();
+                cap.setName("package");
+                cap.addP(new PropertyImpl("package", null, pkgs[pkgIdx].getName()));
+                cap.addP(new PropertyImpl("version", "version", pkgs[pkgIdx].getVersion().toString()));
+                for (int i = 0; i < pkgs[pkgIdx].getAttributes().length; i++)
+                {
+                    R4Attribute attribute = pkgs[pkgIdx].getAttributes()[i];
+                    String key = attribute.getName();
+                    if (!key.equalsIgnoreCase("specification-version")
+                        && !key.equalsIgnoreCase("version"))
+                    {
+                        Object value = attribute.getValue();
+                        cap.addP(key, value);
+                    }
+                }
+                for (int i = 0; i < pkgs[pkgIdx].getDirectives().length; i++)
+                {
+                    R4Directive directive = pkgs[pkgIdx].getDirectives()[i];
+                    String key = directive.getName() + ":";
+                    Object value = directive.getValue();
+                    cap.addP(key, value);
+                }
+                addCapability(cap);
+            }
+        }
+    }
+
+    private void convertExportServiceToCapability(Dictionary dict, Bundle bundle)
+    {
+        Set services = new HashSet();
+
+        // collect Export-Service
+        String target = (String) dict.get(Constants.EXPORT_SERVICE);
+        if (target != null)
+        {
+            R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
+            for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
+            {
+                services.add(pkgs[pkgIdx].getName());
+            }
+        }
+
+        // add actual registered services
+        ServiceReference[] refs = bundle.getRegisteredServices();
+        for (int i = 0; refs != null && i < refs.length; i++)
+        {
+            String[] cls = (String[]) refs[i].getProperty(Constants.OBJECTCLASS);
+            for (int j = 0; cls != null && j < cls.length; j++)
+            {
+                services.add(cls[j]);
+            }
+        }
+
+        // register capabilities for combined set
+        for (Iterator si = services.iterator(); si.hasNext();)
+        {
+            CapabilityImpl cap = new CapabilityImpl();
+            cap.setName("service");
+            cap.addP(new PropertyImpl("service", null, (String) si.next()));
+            addCapability(cap);
+        }
+    }
+}
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Logger.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Logger.java
index b40630d..f8b8005 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Logger.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Logger.java
@@ -49,7 +49,7 @@
     /**
      * Constructor.
      *
-     * @param bundleContext bundle context
+     * @param context bundle context
      */
     Logger(BundleContext context)
     {
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 3b1f1da..7149e62 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
@@ -42,6 +42,7 @@
 {
     static BundleContext m_context = null;
     private final Logger m_logger;
+    private final SystemRepositoryImpl m_system;
     private final LocalRepositoryImpl m_local;
     private List m_urlList = new ArrayList();
     private Map m_repoMap = new HashMap();
@@ -57,14 +58,20 @@
     {
         m_context = context;
         m_logger = logger;
+        m_system = new SystemRepositoryImpl(context, logger);
         m_local = new LocalRepositoryImpl(context, logger);
     }
 
-    LocalRepositoryImpl getLocalRepository()
+    public Repository getLocalRepository()
     {
         return m_local;
     }
 
+    public Repository getSystemRepository()
+    {
+        return m_system;
+    }
+
     public void dispose()
     {
         m_local.dispose();
@@ -118,7 +125,22 @@
             initialize();
         }
 
-        return new ResolverImpl(m_context, this, m_logger);
+        List repositories = new ArrayList();
+        repositories.add(m_system);
+        repositories.add(m_local);
+        repositories.addAll(m_repoMap.values());
+
+        return resolver((Repository[]) repositories.toArray(new Repository[repositories.size()]));
+    }
+
+    public synchronized Resolver resolver(Repository[] repositories)
+    {
+        if (!m_initialized)
+        {
+            initialize();
+        }
+
+        return new ResolverImpl(m_context, repositories, m_logger);
     }
 
     public synchronized Resource[] discoverResources(String filterExpr)
@@ -231,6 +253,11 @@
         return new FilterImpl(filter);
     }
 
+    public Repository repository(URL url) throws Exception
+    {
+        return new RepositoryImpl(null, url, 0, m_logger);
+    }
+
     private void initialize()
     {
         m_initialized = true;
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
index 825bbac..f4e6c04 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
@@ -170,6 +170,11 @@
         }
     }
 
+    public boolean isLocal()
+    {
+        return false;
+    }
+
     /**
      * Default setter method when setting parsed data from the XML file,
      * which currently ignores everything.
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 79cc0c7..a8375fb 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
@@ -21,7 +21,6 @@
 import java.net.URL;
 import java.util.*;
 
-import org.apache.felix.bundlerepository.LocalRepositoryImpl.LocalResourceImpl;
 import org.osgi.framework.*;
 import org.osgi.service.obr.*;
 
@@ -30,9 +29,8 @@
     public static final String PREFER_LOCAL = "obr.resolver.preferLocal";
 
     private final BundleContext m_context;
-    private final RepositoryAdmin m_admin;
     private final Logger m_logger;
-    private final LocalRepositoryImpl m_local;
+    private final Repository[] m_repositories;
     private final Set m_addedSet = new HashSet();
     private final Set m_addedRequirementSet = new HashSet();
     private final Set m_failedSet = new HashSet();
@@ -45,12 +43,11 @@
     private long m_resolveTimeStamp;
     private boolean m_preferLocal = true;
 
-    public ResolverImpl(BundleContext context, RepositoryAdminImpl admin, Logger logger)
+    public ResolverImpl(BundleContext context, Repository[] repositories, Logger logger)
     {
         m_context = context;
-        m_admin = admin;
         m_logger = logger;
-        m_local = admin.getLocalRepository();        
+        m_repositories = repositories;
         String s = context.getProperty(PREFER_LOCAL);
         if (s != null)
         {
@@ -131,10 +128,34 @@
         throw new IllegalStateException("The resources have not been resolved.");
     }
 
+    private Resource[] getResources(boolean local)
+    {
+        List resources = new ArrayList();
+        for (int repoIdx = 0; (m_repositories != null) && (repoIdx < m_repositories.length); repoIdx++)
+        {
+            if (m_repositories[repoIdx].isLocal() == local)
+            {
+                resources.addAll(Arrays.asList(m_repositories[repoIdx].getResources()));
+            }
+        }
+        return (Resource[]) resources.toArray(new Resource[resources.size()]);
+    }
+
     public synchronized boolean resolve()
     {
+        // Find resources
+        Resource[] locals = getResources(true);
+        Resource[] remotes = getResources(false);
+
         // time of the resolution process start
-        m_resolveTimeStamp = m_local.getLastModified();
+        m_resolveTimeStamp = 0;
+        for (int repoIdx = 0; (m_repositories != null) && (repoIdx < m_repositories.length); repoIdx++)
+        {
+            if (m_repositories[repoIdx].isLocal())
+            {
+                m_resolveTimeStamp = Math.max(m_resolveTimeStamp, m_repositories[repoIdx].getLastModified());
+            }
+        }
 
         // Reset instance values.
         m_failedSet.clear();
@@ -155,7 +176,7 @@
             {
                 fake.addRequire((Requirement) iter.next());
             }
-            if (!resolve(fake))
+            if (!resolve(fake, locals, remotes))
             {
                 result = false;
             }
@@ -164,7 +185,7 @@
         // Loop through each resource in added list and resolve.
         for (Iterator iter = m_addedSet.iterator(); iter.hasNext(); )
         {
-            if (!resolve((Resource) iter.next()))
+            if (!resolve((Resource) iter.next(), locals, remotes))
             {
                 // If any resource does not resolve, then the
                 // entire result will be false.
@@ -173,18 +194,17 @@
         }
 
         // Clean up the resulting data structures.
-        List locals = Arrays.asList(m_local.getResources());
         m_requiredSet.removeAll(m_addedSet);
-        m_requiredSet.removeAll(locals);
+        m_requiredSet.removeAll(Arrays.asList(locals));
         m_optionalSet.removeAll(m_addedSet);
         m_optionalSet.removeAll(m_requiredSet);
-        m_optionalSet.removeAll(locals);
+        m_optionalSet.removeAll(Arrays.asList(locals));
 
         // Return final result.
         return result;
     }
 
-    private boolean resolve(Resource resource)
+    private boolean resolve(Resource resource, Resource[] locals, Resource[] remotes)
     {
         boolean result = true;
 
@@ -216,8 +236,8 @@
                     candidate = searchResolvingResources(reqs[reqIdx]);
                     if (candidate == null)
                     {
-                        List candidateCapabilities = searchLocalResources(reqs[reqIdx]);
-                        candidateCapabilities.addAll(searchRemoteResources(reqs[reqIdx]));
+                        List candidateCapabilities = searchResources(reqs[reqIdx], locals);
+                        candidateCapabilities.addAll(searchResources(reqs[reqIdx], remotes));
 
                         // Determine the best candidate available that
                         // can resolve.
@@ -226,7 +246,7 @@
                             Capability bestCapability = getBestCandidate(candidateCapabilities);
 
                             // Try to resolve the best resource.
-                            if (resolve(((CapabilityImpl) bestCapability).getResource()))
+                            if (resolve(((CapabilityImpl) bestCapability).getResource(), locals, remotes))
                             {
                                 candidate = ((CapabilityImpl) bestCapability).getResource();
                             }
@@ -262,7 +282,7 @@
                 {
 
                     // Try to resolve the candidate.
-                    if (resolve(candidate))
+                    if (resolve(candidate, locals, remotes))
                     {
                         // The resolved succeeded; record the candidate
                         // as either optional or required.
@@ -340,49 +360,16 @@
     }
 
     /**
-     * Returns a local resource meeting the given requirement
-     * @param req The requirement that the local resource must meet
-     * @return Returns the found local resource if available
-     */
-    private List searchLocalResources(Requirement req)
-    {
-        List matchingCapabilities = new ArrayList();
-        Resource[] resources = m_local.getResources();
-        for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
-        {
-            checkInterrupt();
-            // We don't need to look at resources we've already looked at.
-            if (!m_failedSet.contains(resources[resIdx])
-                && !m_resolveSet.contains(resources[resIdx]))
-            {
-                Capability[] caps = resources[resIdx].getCapabilities();
-                for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
-                {
-                    if (caps[capIdx].getName().equals(req.getName())
-                        && req.isSatisfied(caps[capIdx]))
-                    {
-                        matchingCapabilities.add(caps[capIdx]);
-                    }
-                }
-            }
-        }
-
-        return matchingCapabilities;
-    }
-
-    /**
-     * Searches for remote resources that do meet the given requirement
+     * Searches for resources that do meet the given requirement
      * @param req
-     * @return all remote resources meeting the given requirement
+     * @return all resources meeting the given requirement
      */
-    private List searchRemoteResources(Requirement req)
+    private List searchResources(Requirement req, Resource[] resources)
     {
         List matchingCapabilities = new ArrayList();
 
-        Repository[] repos = m_admin.listRepositories();
-        for (int repoIdx = 0; (repos != null) && (repoIdx < repos.length); repoIdx++)
+        for (int repoIdx = 0; (m_repositories != null) && (repoIdx < m_repositories.length); repoIdx++)
         {
-            Resource[] resources = repos[repoIdx].getResources();
             for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
             {
                 checkInterrupt();
@@ -499,9 +486,13 @@
         // the state can still change during the operation, but we will
         // be optimistic. This could also be made smarter so that it checks
         // to see if the local state changes overlap with the resolver.
-        if (m_resolveTimeStamp != m_local.getLastModified())
+        for (int repoIdx = 0; (m_repositories != null) && (repoIdx < m_repositories.length); repoIdx++)
         {
-            throw new IllegalStateException("Framework state has changed, must resolve again.");
+            if (m_repositories[repoIdx].isLocal()
+                    && m_repositories[repoIdx].getLastModified() > m_resolveTimeStamp)
+            {
+                throw new IllegalStateException("Framework state has changed, must resolve again.");
+            }
         }
 
         // Eliminate duplicates from target, required, optional resources.
@@ -535,7 +526,7 @@
             // For the resource being deployed, see if there is an older
             // version of the resource already installed that can potentially
             // be updated.
-            LocalRepositoryImpl.LocalResourceImpl localResource =
+            LocalResourceImpl localResource =
                 findUpdatableLocalResource(deployResources[i]);
             // If a potentially updatable older version was found,
             // then verify that updating the local resource will not
@@ -691,7 +682,7 @@
             // without breaking constraints of existing local resources.
             for (int i = 0; i < localResources.length; i++)
             {
-                if (isResourceUpdatable(localResources[i], resource, m_local.getResources()))
+                if (isResourceUpdatable(localResources[i], resource, localResources))
                 {
                     return (LocalResourceImpl) localResources[i];
                 }
@@ -707,7 +698,7 @@
      */
     private Resource[] findLocalResources(String symName)
     {
-        Resource[] localResources = m_local.getResources();
+        Resource[] localResources = getResources(true);
 
         List matchList = new ArrayList();
         for (int i = 0; i < localResources.length; i++)
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/SystemRepositoryImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/SystemRepositoryImpl.java
new file mode 100644
index 0000000..0ed0c56
--- /dev/null
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/SystemRepositoryImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.bundlerepository;
+
+import java.net.URL;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.obr.Repository;
+import org.osgi.service.obr.Resource;
+
+public class SystemRepositoryImpl implements Repository
+{
+
+    private final Logger m_logger;
+    private final long lastModified;
+    private final LocalResourceImpl systemBundleResource;
+
+    public SystemRepositoryImpl(BundleContext context, Logger logger)
+    {
+        m_logger = logger;
+        lastModified = System.currentTimeMillis();
+        try
+        {
+            systemBundleResource = new LocalResourceImpl(context.getBundle(0));
+        }
+        catch (InvalidSyntaxException ex)
+        {
+            // This should never happen since we are generating filters,
+            // but ignore the resource if it does occur.
+            m_logger.log(Logger.LOG_WARNING, ex.getMessage(), ex);
+            throw new IllegalStateException("Unexpected error", ex);
+        }
+    }
+
+    public URL getURL()
+    {
+        return null;
+    }
+
+    public Resource[] getResources()
+    {
+        return new Resource[] { systemBundleResource };
+    }
+
+    public String getName()
+    {
+        return "System Repository";
+    }
+
+    public long getLastModified()
+    {
+        return lastModified;
+    }
+
+    public boolean isLocal()
+    {
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/MockBundleContext.java b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/MockBundleContext.java
deleted file mode 100644
index 350f587..0000000
--- a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/MockBundleContext.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/* 
- * 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.bundlerepository;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.Dictionary;
-import java.util.Properties;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleListener;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkListener;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-
-public class MockBundleContext implements BundleContext
-{
-    private Properties props = new Properties();
-
-    public void setProperty(String key, String val)
-    {
-        props.setProperty(key, val);
-    }
-
-    public void addBundleListener(BundleListener arg0)
-    {
-    }
-
-    public void addFrameworkListener(FrameworkListener arg0)
-    {
-    }
-
-    public void addServiceListener(ServiceListener arg0)
-    {
-    }
-
-    public void addServiceListener(ServiceListener arg0, String arg1)
-    {
-    }
-
-    public Filter createFilter(String arg0)
-    {
-        // returns a match-all filter always
-        return new Filter()
-        {
-            public boolean matchCase(Dictionary arg0)
-            {
-                return true;
-            }
-
-            public boolean match(Dictionary arg0)
-            {
-                return true;
-            }
-
-            public boolean match(ServiceReference arg0)
-            {
-                return true;
-            }
-        };
-    }
-
-    public ServiceReference[] getAllServiceReferences(String arg0, String arg1)
-    {
-        return null;
-    }
-
-    public Bundle getBundle()
-    {
-        return null;
-    }
-
-    public Bundle getBundle(long arg0)
-    {
-        return null;
-    }
-
-    public Bundle[] getBundles()
-    {
-        return null;
-    }
-
-    public File getDataFile(String arg0)
-    {
-        return null;
-    }
-
-    public String getProperty(String name)
-    {
-        return props.getProperty(name);
-    }
-
-    public Object getService(ServiceReference arg0)
-    {
-        return null;
-    }
-
-    public ServiceReference getServiceReference(String arg0)
-    {
-        return null;
-    }
-
-    public ServiceReference[] getServiceReferences(String arg0, String arg1)
-    {
-        return null;
-    }
-
-    public Bundle installBundle(String arg0)
-    {
-        return null;
-    }
-
-    public Bundle installBundle(String arg0, InputStream arg1)
-    {
-        return null;
-    }
-
-    public ServiceRegistration registerService(String[] arg0, Object arg1, Dictionary arg2)
-    {
-        return null;
-    }
-
-    public ServiceRegistration registerService(String arg0, Object arg1, Dictionary arg2)
-    {
-        return null;
-    }
-
-    public void removeBundleListener(BundleListener arg0)
-    {
-    }
-
-    public void removeFrameworkListener(FrameworkListener arg0)
-    {
-    }
-
-    public void removeServiceListener(ServiceListener arg0)
-    {
-    }
-
-    public boolean ungetService(ServiceReference arg0)
-    {
-        return false;
-    }
-}
\ No newline at end of file
diff --git a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryAdminTest.java b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryAdminTest.java
index d08cdf1..40d6576 100644
--- a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryAdminTest.java
+++ b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryAdminTest.java
@@ -19,9 +19,17 @@
 package org.apache.felix.bundlerepository;
 
 import java.net.URL;
+import java.util.Hashtable;
 
 import junit.framework.TestCase;
-import org.osgi.framework.Filter;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.easymock.internal.matchers.Captures;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceListener;
 import org.osgi.service.obr.Repository;
 import org.osgi.service.obr.Resource;
 
@@ -43,13 +51,28 @@
         assertEquals(1, resources.length);
     }
 
-    private RepositoryAdminImpl createRepositoryAdmin()
+    private RepositoryAdminImpl createRepositoryAdmin() throws Exception
     {
-        final MockBundleContext bundleContext = new MockBundleContext() {
-            public Filter createFilter(String arg0) {
-                return new FilterImpl(arg0);
+        BundleContext bundleContext = (BundleContext) EasyMock.createMock(BundleContext.class);
+        Bundle systemBundle = (Bundle) EasyMock.createMock(Bundle.class);
+
+        EasyMock.expect(bundleContext.getProperty((String) EasyMock.anyObject())).andReturn(null).anyTimes();
+        EasyMock.expect(bundleContext.getBundle(0)).andReturn(systemBundle);
+        EasyMock.expect(systemBundle.getHeaders()).andReturn(new Hashtable());
+        EasyMock.expect(systemBundle.getRegisteredServices()).andReturn(null);
+        EasyMock.expect(new Long(systemBundle.getBundleId())).andReturn(new Long(0)).anyTimes();
+        EasyMock.expect(systemBundle.getBundleContext()).andReturn(bundleContext);
+        bundleContext.addBundleListener((BundleListener) EasyMock.anyObject());
+        bundleContext.addServiceListener((ServiceListener) EasyMock.anyObject());
+        EasyMock.expect(bundleContext.getBundles()).andReturn(new Bundle[] { systemBundle });
+        final Capture c = new Capture();
+        EasyMock.expect(bundleContext.createFilter((String) capture(c))).andAnswer(new IAnswer() {
+            public Object answer() throws Throwable {
+                return new FilterImpl((String) c.getValue());
             }
-        };
+        }).anyTimes();
+        EasyMock.replay(new Object[] { bundleContext, systemBundle });
+
         RepositoryAdminImpl repoAdmin = new RepositoryAdminImpl(bundleContext, new Logger(bundleContext));
 
         // force initialization && remove all initial repositories
@@ -61,4 +84,10 @@
 
         return repoAdmin;
     }
-}
\ No newline at end of file
+
+    static Object capture(Capture capture) {
+        EasyMock.reportMatcher(new Captures(capture));
+        return null;
+    }
+
+}
diff --git a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryImplTest.java b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryImplTest.java
index 38f02c8..38d6971 100644
--- a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryImplTest.java
+++ b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/RepositoryImplTest.java
@@ -19,8 +19,17 @@
 package org.apache.felix.bundlerepository;
 
 import java.net.URL;
+import java.util.Dictionary;
+import java.util.Hashtable;
 
 import junit.framework.TestCase;
+import org.easymock.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.obr.Repository;
 import org.osgi.service.obr.Resource;
 
@@ -80,9 +89,33 @@
         assertEquals("referral1_repository", res[0].getRepository().getName());
     }
 
-    private RepositoryAdminImpl createRepositoryAdmin()
+    private RepositoryAdminImpl createRepositoryAdmin() throws Exception
     {
-        final MockBundleContext bundleContext = new MockBundleContext();
+        BundleContext bundleContext = (BundleContext) EasyMock.createMock(BundleContext.class);
+        Bundle systemBundle = (Bundle) EasyMock.createMock(Bundle.class);
+
+        EasyMock.expect(bundleContext.getProperty((String) EasyMock.anyObject())).andReturn(null).anyTimes();
+        EasyMock.expect(bundleContext.getBundle(0)).andReturn(systemBundle);
+        EasyMock.expect(systemBundle.getHeaders()).andReturn(new Hashtable());
+        EasyMock.expect(systemBundle.getRegisteredServices()).andReturn(null);
+        EasyMock.expect(new Long(systemBundle.getBundleId())).andReturn(new Long(0)).anyTimes();
+        EasyMock.expect(systemBundle.getBundleContext()).andReturn(bundleContext);
+        bundleContext.addBundleListener((BundleListener) EasyMock.anyObject());
+        bundleContext.addServiceListener((ServiceListener) EasyMock.anyObject());
+        EasyMock.expect(bundleContext.getBundles()).andReturn(new Bundle[] { systemBundle });
+        EasyMock.expect(bundleContext.createFilter(null)).andReturn(new Filter() {
+            public boolean match(ServiceReference reference) {
+                return true;
+            }
+            public boolean match(Dictionary dictionary) {
+                return true;
+            }
+            public boolean matchCase(Dictionary dictionary) {
+                return true;
+            }
+        }).anyTimes();
+        EasyMock.replay(new Object[] { bundleContext, systemBundle });
+
         RepositoryAdminImpl repoAdmin = new RepositoryAdminImpl(bundleContext, new Logger(bundleContext));
 
         // force initialization && remove all initial repositories
@@ -94,4 +127,5 @@
 
         return repoAdmin;
     }
+
 }
\ No newline at end of file
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 e55288d..dd3a706 100644
--- a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/ResolverImplTest.java
+++ b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/ResolverImplTest.java
@@ -19,9 +19,18 @@
 package org.apache.felix.bundlerepository;
 
 import java.net.URL;
+import java.util.Hashtable;
 
 import junit.framework.TestCase;
 
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.easymock.internal.matchers.Captures;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceListener;
 import org.osgi.service.obr.InterruptedResolutionException;
 import org.osgi.service.obr.Repository;
 import org.osgi.service.obr.Requirement;
@@ -39,19 +48,11 @@
 
         Resolver resolver = repoAdmin.resolver();
 
-        Resource r = null;
-        //MockContext doesn't support filtering!
-        Resource[] discoverResources = repoAdmin.discoverResources("");
-        for (int i = 0; i < discoverResources.length; i++)
-        {
-            Resource resource = discoverResources[i];
-            if (resource.getSymbolicName().contains("org.apache.felix.test"))
-            {
-                r = resource;
-            }
-        }
+        Resource[] discoverResources = repoAdmin.discoverResources("(symbolicname=org.apache.felix.test*)");
+        assertNotNull(discoverResources);
+        assertEquals(1, discoverResources.length);
 
-        resolver.add(r);
+        resolver.add(discoverResources[0]);
         assertTrue(resolver.resolve());
     }
 
@@ -102,11 +103,30 @@
         new ResolverImplTest().testReferral1();
     }
 
-    private RepositoryAdminImpl createRepositoryAdmin()
+    private RepositoryAdminImpl createRepositoryAdmin() throws Exception
     {
-        final MockBundleContext bundleContext = new MockBundleContext();
-        bundleContext.setProperty(RepositoryAdminImpl.REPOSITORY_URL_PROP,
-                                  getClass().getResource("/referred.xml").toExternalForm());
+        BundleContext bundleContext = (BundleContext) EasyMock.createMock(BundleContext.class);
+        Bundle systemBundle = (Bundle) EasyMock.createMock(Bundle.class);
+
+        EasyMock.expect(bundleContext.getProperty(RepositoryAdminImpl.REPOSITORY_URL_PROP))
+                    .andReturn(getClass().getResource("/referred.xml").toExternalForm());
+        EasyMock.expect(bundleContext.getProperty((String) EasyMock.anyObject())).andReturn(null).anyTimes();
+        EasyMock.expect(bundleContext.getBundle(0)).andReturn(systemBundle);
+        EasyMock.expect(systemBundle.getHeaders()).andReturn(new Hashtable());
+        EasyMock.expect(systemBundle.getRegisteredServices()).andReturn(null);
+        EasyMock.expect(new Long(systemBundle.getBundleId())).andReturn(new Long(0)).anyTimes();
+        EasyMock.expect(systemBundle.getBundleContext()).andReturn(bundleContext);
+        bundleContext.addBundleListener((BundleListener) EasyMock.anyObject());
+        bundleContext.addServiceListener((ServiceListener) EasyMock.anyObject());
+        EasyMock.expect(bundleContext.getBundles()).andReturn(new Bundle[] { systemBundle });
+        final Capture c = new Capture();
+        EasyMock.expect(bundleContext.createFilter((String) capture(c))).andAnswer(new IAnswer() {
+            public Object answer() throws Throwable {
+                return new FilterImpl((String) c.getValue());
+            }
+        }).anyTimes();
+        EasyMock.replay(new Object[] { bundleContext, systemBundle });
+
         RepositoryAdminImpl repoAdmin = new RepositoryAdminImpl(bundleContext, new Logger(bundleContext));
 
         // force initialization && remove all initial repositories
@@ -118,4 +138,10 @@
 
         return repoAdmin;
     }
+
+    static Object capture(Capture capture) {
+        EasyMock.reportMatcher(new Captures(capture));
+        return null;
+    }
+
 }
\ No newline at end of file
diff --git a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/StaxParserTest.java b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/StaxParserTest.java
index b78e889..4232a60 100644
--- a/bundlerepository/src/test/java/org/apache/felix/bundlerepository/StaxParserTest.java
+++ b/bundlerepository/src/test/java/org/apache/felix/bundlerepository/StaxParserTest.java
@@ -19,8 +19,17 @@
 package org.apache.felix.bundlerepository;
 
 import java.net.URL;
+import java.util.Hashtable;
 
 import junit.framework.TestCase;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.easymock.internal.matchers.Captures;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceListener;
 import org.osgi.service.obr.Repository;
 import org.osgi.service.obr.Resolver;
 import org.osgi.service.obr.Resource;
@@ -35,20 +44,11 @@
 
         Resolver resolver = repoAdmin.resolver();
 
-        Resource r = null;
-        //MockContext doesn't support filtering!
-        Resource[] discoverResources = repoAdmin.discoverResources("");
-        for (int i = 0; i < discoverResources.length; i++)
-        {
-            Resource resource = discoverResources[i];
-            if (resource.getSymbolicName().contains("org.apache.felix.test"))
-            {
-                r = resource;
-            }
-        }
-        assertNotNull(r);
+        Resource[] discoverResources = repoAdmin.discoverResources("(symbolicname=org.apache.felix.test*)");
+        assertNotNull(discoverResources);
+        assertEquals(1, discoverResources.length);
 
-        resolver.add(r);
+        resolver.add(discoverResources[0]);
         assertTrue(resolver.resolve());
     }
 
@@ -116,13 +116,32 @@
         new StaxParserTest().testStaxParser();
     }
 
-    private RepositoryAdminImpl createRepositoryAdmin(Class repositoryParser)
+    private RepositoryAdminImpl createRepositoryAdmin(Class repositoryParser) throws Exception
     {
-        final MockBundleContext bundleContext = new MockBundleContext();
-        bundleContext.setProperty(RepositoryAdminImpl.REPOSITORY_URL_PROP,
-            getClass().getResource("/referral1_repository.xml").toExternalForm());
-        bundleContext.setProperty(RepositoryImpl.OBR_PARSER_CLASS,
-            repositoryParser.getName());
+        BundleContext bundleContext = (BundleContext) EasyMock.createMock(BundleContext.class);
+        Bundle systemBundle = (Bundle) EasyMock.createMock(Bundle.class);
+
+        EasyMock.expect(bundleContext.getProperty(RepositoryAdminImpl.REPOSITORY_URL_PROP))
+                    .andReturn(getClass().getResource("/referral1_repository.xml").toExternalForm());
+        EasyMock.expect(bundleContext.getProperty(RepositoryImpl.OBR_PARSER_CLASS))
+                    .andReturn(repositoryParser.getName());
+        EasyMock.expect(bundleContext.getProperty((String) EasyMock.anyObject())).andReturn(null).anyTimes();
+        EasyMock.expect(bundleContext.getBundle(0)).andReturn(systemBundle);
+        EasyMock.expect(systemBundle.getHeaders()).andReturn(new Hashtable());
+        EasyMock.expect(systemBundle.getRegisteredServices()).andReturn(null);
+        EasyMock.expect(new Long(systemBundle.getBundleId())).andReturn(new Long(0)).anyTimes();
+        EasyMock.expect(systemBundle.getBundleContext()).andReturn(bundleContext);
+        bundleContext.addBundleListener((BundleListener) EasyMock.anyObject());
+        bundleContext.addServiceListener((ServiceListener) EasyMock.anyObject());
+        EasyMock.expect(bundleContext.getBundles()).andReturn(new Bundle[] { systemBundle });
+        final Capture c = new Capture();
+        EasyMock.expect(bundleContext.createFilter((String) capture(c))).andAnswer(new IAnswer() {
+            public Object answer() throws Throwable {
+                return new FilterImpl((String) c.getValue());
+            }
+        }).anyTimes();
+        EasyMock.replay(new Object[] { bundleContext, systemBundle });
+
         RepositoryAdminImpl repoAdmin = new RepositoryAdminImpl(bundleContext, new Logger(bundleContext));
 
         // force initialization && remove all initial repositories
@@ -134,4 +153,10 @@
 
         return repoAdmin;
     }
+
+    static Object capture(Capture capture) {
+        EasyMock.reportMatcher(new Captures(capture));
+        return null;
+    }
+
 }
\ No newline at end of file
diff --git a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Repository.java b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Repository.java
index 30adeb9..172c5f2 100644
--- a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Repository.java
+++ b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Repository.java
@@ -42,7 +42,7 @@
     Resource[] getResources();
 
     /**
-     * Return the name of this reposotory.
+     * Return the name of this repository.
      * 
      * @return a non-null name
      */
@@ -50,4 +50,14 @@
 
     long getLastModified();
 
+    /**
+     * Returns whether this repository is a local one
+     * or not.
+     *
+     * Local repositories contains resources that are already available
+     * in the OSGi framework and thus will be preferred over other
+     * resources.
+     */
+    boolean isLocal();
+
 }
\ No newline at end of file
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 dc822d0..8b6b520 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
@@ -35,11 +35,11 @@
  * <li>Capabilities - Capabilities provide a named aspect: a bundle, a display,
  * memory, etc.</li>
  * <li>Requirements - A named filter expression. The filter must be satisfied
- * by one or more Capabilties with the given name. These capabilities can come
+ * by one or more Capabilities with the given name. These capabilities can come
  * from other resources or from the platform. If multiple resources provide the
  * requested capability, one is selected. (### what algorithm? ###)</li>
  * <li>Requests - Requests are like requirements, except that a request can be
- * fullfilled by 0..n resources. This feature can be used to link to resources
+ * fulfilled by 0..n resources. This feature can be used to link to resources
  * that are compatible with the given resource and provide extra functionality.
  * For example, a bundle could request all its known fragments. The UI
  * associated with the repository could list these as optional downloads.</li>
@@ -85,12 +85,20 @@
 
     /**
      * Create a resolver.
-     * 
+     *
      * @return
      */
     Resolver resolver();
 
     /**
+     * Create a resolver on the given repositories.
+     *
+     * @param repositories the list of repositories to use for the resolution
+     * @return
+     */
+    Resolver resolver(Repository[] repositories);
+
+    /**
      * Add a new repository to the federation.
      * 
      * The url must point to a repository XML file.
@@ -101,6 +109,14 @@
      */
     Repository addRepository(URL repository) throws Exception;
 
+    /**
+     * Remove a repository from the federation
+     *
+     * The url must point to a repository XML file.
+     *
+     * @param repository
+     * @return
+     */
     boolean removeRepository(URL repository);
 
     /**
@@ -110,6 +126,20 @@
      */
     Repository[] listRepositories();
 
+    /**
+     * Return the repository containing the system bundle
+     *
+     * @return
+     */
+    Repository getSystemRepository();
+
+    /**
+     * Return the repository containing locally installed resources
+     *
+     * @return
+     */
+    Repository getLocalRepository();
+
     Resource getResource(String repositoryId);
 
     /**
@@ -128,4 +158,12 @@
      */
     Filter filter(String filter) throws InvalidSyntaxException;
 
+    /**
+     * Create a repository from the specified URL.
+     * 
+     * @param repository
+     * @return
+     */
+    Repository repository(URL repository) throws Exception;
+
 }
\ No newline at end of file
diff --git a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resource.java b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resource.java
index 7064b75..274b533 100644
--- a/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resource.java
+++ b/org.osgi.service.obr/src/main/java/org/osgi/service/obr/Resource.java
@@ -85,4 +85,5 @@
     String[] getCategories();
 
     Repository getRepository();
+
 }
\ No newline at end of file