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 2015/09/02 17:26:45 UTC

svn commit: r1700842 [1/3] - in /aries/trunk/subsystem: subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/ subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ subsystem-itests/src/test/java/org/apache/aries/s...

Author: jwross
Date: Wed Sep  2 15:26:45 2015
New Revision: 1700842

URL: http://svn.apache.org/r1700842
Log:
ARIES-1392 Provide a more efficient implementation of a system repository.

While running the same test case developed as part of ARIES-1357, profiling continually showed a bottleneck surrounding the system repository. A more efficient implementation has been provided using code copied over from the Apache Felix (http://felix.apache.org/) project.

http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java?view=log
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java?view=log
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java?view=log
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/StringComparator.java?view=log

These classes were copied to the org.apache.aries.subsystem.core.capabilityset package with some modifications. A new repository implementation called CapabilitySetRepository was created using these classes from the Felix project. This repository will index the standard namespaces along with their associated namespace attributes. It will also create additional capability sets as necessary when encountering custom namespaces.

The system repository now delegates to CapabilitySetRepository. In addition, the system repository now tracks both bundles and subsystem services. Capabilities are added to the repository as they appear and removed when they go away. Bundle revisions are wrapped with BundleRevisionResource in order to account for service capabilities.

Other changes resulting from this optimization are listed below. They were necessary and appropriate because either (a) BundleRevisionResource became part of the normal flow when delivered from the system repository, or (b) computing service capabilities for the system repository requires searching for blueprint.xml files in the bundle which causes the framework to attempt a resolution.

(1) BundleResourceInstaller must now check for BundleRevisionResource in addition to BundleRevision when installing a bundle.
(2) BundleRevisionResource now provides access to the wrapped BundleRevision.
(3) ResolveContext must now check for BundleRevisionResource in addition to BundleResource when identifying the region of an already installed resource.
(4) SubsystemResolverHook will now prevent bundles not referenced by any subsystems from resolving. A non-referenced bundle is one that is being installed as part of a subsystem installation before it has been added as a reference.
(5) Utils now includes BundleRevisionResource, in addition to BasicSubsystem and BundleRevision, as a shared resource, which is essentially any resource that has already been installed and being referenced by a new subsystem.
(6) RootSubsystemTest was modified to allow for the RESOLVED state when ensuring the bundle has not been started. Frameworks are allowed to attempt to resolve bundles as needed, and subsystems no longer prevent resolution after entering the installed state, which is the case in this test.

Added:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySet.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySetRepository.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/SecureAction.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/SimpleFilter.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/StringComparator.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SystemRepositoryManager.java
Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceInstaller.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleRevisionResource.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResolveContext.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResolverHook.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SystemRepository.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Utils.java
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/RootSubsystemTest.java

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySet.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySet.java?rev=1700842&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySet.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySet.java Wed Sep  2 15:26:45 2015
@@ -0,0 +1,668 @@
+/*
+ * 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.aries.subsystem.core.capabilityset;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+import org.osgi.framework.Version;
+import org.osgi.framework.VersionRange;
+import org.osgi.framework.namespace.AbstractWiringNamespace;
+import org.osgi.resource.Capability;
+
+public class CapabilitySet
+{
+    private final SortedMap<String, Map<Object, Set<Capability>>> m_indices; // Should also be concurrent!
+    private final Set<Capability> m_capSet = Collections.newSetFromMap(new ConcurrentHashMap<Capability, Boolean>());
+    private final static SecureAction m_secureAction = new SecureAction();
+
+//    public void dump()
+//    {
+//        for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+//        {
+//            boolean header1 = false;
+//            for (Entry<Object, Set<Capability>> entry2 : entry.getValue().entrySet())
+//            {
+//                boolean header2 = false;
+//                for (Capability cap : entry2.getValue())
+//                {
+//                    if (cap.getRevision().getBundle().getBundleId() != 0)
+//                    {
+//                        if (!header1)
+//                        {
+//                            System.out.println(entry.getKey() + ":");
+//                            header1 = true;
+//                        }
+//                        if (!header2)
+//                        {
+//                            System.out.println("   " + entry2.getKey());
+//                            header2 = true;
+//                        }
+//                        System.out.println("      " + cap);
+//                    }
+//                }
+//            }
+//        }
+//    }
+
+    public CapabilitySet(final List<String> indexProps, final boolean caseSensitive)
+    {
+        m_indices = (caseSensitive)
+            ? new ConcurrentSkipListMap<String, Map<Object, Set<Capability>>>()
+            : new ConcurrentSkipListMap<String, Map<Object, Set<Capability>>>(
+                StringComparator.COMPARATOR);
+        for (int i = 0; (indexProps != null) && (i < indexProps.size()); i++)
+        {
+            m_indices.put(
+                indexProps.get(i), new ConcurrentHashMap<Object, Set<Capability>>());
+        }
+    }
+
+    public void addCapability(final Capability cap)
+    {
+        m_capSet.add(cap);
+
+        // Index capability.
+        for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+        {
+            Object value = cap.getAttributes().get(entry.getKey());
+            if (value != null)
+            {
+                if (value.getClass().isArray())
+                {
+                    value = convertArrayToList(value);
+                }
+
+                ConcurrentMap<Object, Set<Capability>> index =
+                        (ConcurrentMap<Object, Set<Capability>>) entry.getValue();
+
+                if (value instanceof Collection)
+                {
+                    Collection c = (Collection) value;
+                    for (Object o : c)
+                    {
+                        indexCapability(index, cap, o);
+                    }
+                }
+                else
+                {
+                    indexCapability(index, cap, value);
+                }
+            }
+        }
+    }
+
+    private void indexCapability(
+        ConcurrentMap<Object, Set<Capability>> index, Capability cap, Object capValue)
+    {
+        Set<Capability> caps = Collections.newSetFromMap(new ConcurrentHashMap<Capability, Boolean>());
+        Set<Capability> prevval = index.putIfAbsent(capValue, caps);
+        if (prevval != null)
+            caps = prevval;
+        caps.add(cap);
+    }
+
+    public void removeCapability(final Capability cap)
+    {
+        if (m_capSet.remove(cap))
+        {
+            for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+            {
+                Object value = cap.getAttributes().get(entry.getKey());
+                if (value != null)
+                {
+                    if (value.getClass().isArray())
+                    {
+                        value = convertArrayToList(value);
+                    }
+
+                    Map<Object, Set<Capability>> index = entry.getValue();
+
+                    if (value instanceof Collection)
+                    {
+                        Collection c = (Collection) value;
+                        for (Object o : c)
+                        {
+                            deindexCapability(index, cap, o);
+                        }
+                    }
+                    else
+                    {
+                        deindexCapability(index, cap, value);
+                    }
+                }
+            }
+        }
+    }
+
+    private void deindexCapability(
+        Map<Object, Set<Capability>> index, Capability cap, Object value)
+    {
+        Set<Capability> caps = index.get(value);
+        if (caps != null)
+        {
+            caps.remove(cap);
+            if (caps.isEmpty())
+            {
+                index.remove(value);
+            }
+        }
+    }
+
+    public Set<Capability> match(final SimpleFilter sf, final boolean obeyMandatory)
+    {
+        final Set<Capability> matches = match(m_capSet, sf);
+        return (obeyMandatory)
+            ? matchMandatory(matches, sf)
+            : matches;
+    }
+
+    private Set<Capability> match(Set<Capability> caps, final SimpleFilter sf)
+    {
+        Set<Capability> matches = Collections.newSetFromMap(new ConcurrentHashMap<Capability, Boolean>());
+
+        if (sf.getOperation() == SimpleFilter.MATCH_ALL)
+        {
+            matches.addAll(caps);
+        }
+        else if (sf.getOperation() == SimpleFilter.AND)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For AND we calculate the intersection of each subfilter.
+            // We can short-circuit the AND operation if there are no
+            // remaining capabilities.
+            final List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; (caps.size() > 0) && (i < sfs.size()); i++)
+            {
+                matches = match(caps, sfs.get(i));
+                caps = matches;
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.OR)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.addAll(match(caps, sfs.get(i)));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.NOT)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            matches.addAll(caps);
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.removeAll(match(caps, sfs.get(i)));
+            }
+        }
+        else
+        {
+            Map<Object, Set<Capability>> index = m_indices.get(sf.getName());
+            if ((sf.getOperation() == SimpleFilter.EQ) && (index != null))
+            {
+                Set<Capability> existingCaps = index.get(sf.getValue());
+                if (existingCaps != null)
+                {
+                    matches.addAll(existingCaps);
+                    if (caps != m_capSet)
+                    {
+                        matches.retainAll(caps);
+                    }
+                }
+            }
+            else
+            {
+                for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+                {
+                    Capability cap = it.next();
+                    Object lhs = cap.getAttributes().get(sf.getName());
+                    if (lhs != null)
+                    {
+                        if (compare(lhs, sf.getValue(), sf.getOperation()))
+                        {
+                            matches.add(cap);
+                        }
+                    }
+                }
+            }
+        }
+
+        return matches;
+    }
+
+//    public static boolean matches(Capability cap, SimpleFilter sf)
+//    {
+//        return matchesInternal(cap, sf) && matchMandatory(cap, sf);
+//    }
+
+//    private static boolean matchesInternal(Capability cap, SimpleFilter sf)
+//    {
+//        boolean matched = true;
+//
+//        if (sf.getOperation() == SimpleFilter.MATCH_ALL)
+//        {
+//            matched = true;
+//        }
+//        else if (sf.getOperation() == SimpleFilter.AND)
+//        {
+//            // Evaluate each subfilter against the remaining capabilities.
+//            // For AND we calculate the intersection of each subfilter.
+//            // We can short-circuit the AND operation if there are no
+//            // remaining capabilities.
+//            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+//            for (int i = 0; matched && (i < sfs.size()); i++)
+//            {
+//                matched = matchesInternal(cap, sfs.get(i));
+//            }
+//        }
+//        else if (sf.getOperation() == SimpleFilter.OR)
+//        {
+//            // Evaluate each subfilter against the remaining capabilities.
+//            // For OR we calculate the union of each subfilter.
+//            matched = false;
+//            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+//            for (int i = 0; !matched && (i < sfs.size()); i++)
+//            {
+//                matched = matchesInternal(cap, sfs.get(i));
+//            }
+//        }
+//        else if (sf.getOperation() == SimpleFilter.NOT)
+//        {
+//            // Evaluate each subfilter against the remaining capabilities.
+//            // For OR we calculate the union of each subfilter.
+//            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+//            for (int i = 0; i < sfs.size(); i++)
+//            {
+//                matched = !(matchesInternal(cap, sfs.get(i)));
+//            }
+//        }
+//        else
+//        {
+//            matched = false;
+//            Object lhs = cap.getAttributes().get(sf.getName());
+//            if (lhs != null)
+//            {
+//                matched = compare(lhs, sf.getValue(), sf.getOperation());
+//            }
+//        }
+//
+//        return matched;
+//    }
+
+    private static Set<Capability> matchMandatory(
+        Set<Capability> caps, SimpleFilter sf)
+    {
+        for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+        {
+            Capability cap = it.next();
+            if (!matchMandatory(cap, sf))
+            {
+                it.remove();
+            }
+        }
+        return caps;
+    }
+
+    private static boolean matchMandatory(Capability cap, SimpleFilter sf)
+    {
+        String mandatoryDirective = cap.getDirectives().get(AbstractWiringNamespace.CAPABILITY_MANDATORY_DIRECTIVE);
+        if (mandatoryDirective == null) {
+            // There are no mandatory attributes to check.
+            return true;
+        }
+        List<String> mandatoryAttributes = Arrays.asList(mandatoryDirective.split(","));
+        
+        Map<String, Object> attrs = cap.getAttributes();
+        for (Entry<String, Object> entry : attrs.entrySet())
+        {
+            if (mandatoryAttributes.contains(entry.getKey())
+                && !matchMandatoryAttrbute(entry.getKey(), sf))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean matchMandatoryAttrbute(String attrName, SimpleFilter sf)
+    {
+        if ((sf.getName() != null) && sf.getName().equals(attrName))
+        {
+            return true;
+        }
+        else if (sf.getOperation() == SimpleFilter.AND)
+        {
+            List list = (List) sf.getValue();
+            for (int i = 0; i < list.size(); i++)
+            {
+                SimpleFilter sf2 = (SimpleFilter) list.get(i);
+                if ((sf2.getName() != null)
+                    && sf2.getName().equals(attrName))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static final Class<?>[] STRING_CLASS = new Class[] { String.class };
+    private static final String VALUE_OF_METHOD_NAME = "valueOf";
+
+    private static boolean compare(Object lhs, Object rhsUnknown, int op)
+    {
+        if (lhs == null)
+        {
+            return false;
+        }
+
+        // If this is a PRESENT operation, then just return true immediately
+        // since we wouldn't be here if the attribute wasn't present.
+        if (op == SimpleFilter.PRESENT)
+        {
+            return true;
+        }
+
+        //Need a special case here when lhs is a Version and rhs is a VersionRange
+        //Version is comparable so we need to check this first
+        if(lhs instanceof Version && op == SimpleFilter.EQ)
+        {
+            Object rhs = null;
+            try
+            {
+                rhs = coerceType(lhs, (String) rhsUnknown);
+            }
+            catch (Exception ex)
+            {
+                //Do nothing will check later if rhs is null
+            }
+
+            if(rhs != null && rhs instanceof VersionRange)
+            {
+                return ((VersionRange)rhs).includes((Version)lhs);
+            }
+        }
+
+        // If the type is comparable, then we can just return the
+        // result immediately.
+        if (lhs instanceof Comparable)
+        {
+            // Spec says SUBSTRING is false for all types other than string.
+            if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
+            {
+                return false;
+            }
+
+            Object rhs;
+            if (op == SimpleFilter.SUBSTRING)
+            {
+                rhs = rhsUnknown;
+            }
+            else
+            {
+                try
+                {
+                    rhs = coerceType(lhs, (String) rhsUnknown);
+                }
+                catch (Exception ex)
+                {
+                    return false;
+                }
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                    try
+                    {
+                        return (((Comparable) lhs).compareTo(rhs) == 0);
+                    }
+                    catch (Exception ex)
+                    {
+                        return false;
+                    }
+                case SimpleFilter.GTE :
+                    try
+                    {
+                        return (((Comparable) lhs).compareTo(rhs) >= 0);
+                    }
+                    catch (Exception ex)
+                    {
+                        return false;
+                    }
+                case SimpleFilter.LTE :
+                    try
+                    {
+                        return (((Comparable) lhs).compareTo(rhs) <= 0);
+                    }
+                    catch (Exception ex)
+                    {
+                        return false;
+                    }
+                case SimpleFilter.APPROX :
+                    return compareApproximate(lhs, rhs);
+                case SimpleFilter.SUBSTRING :
+                    return SimpleFilter.compareSubstring((List<String>) rhs, (String) lhs);
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+        // Booleans do not implement comparable, so special case them.
+        else if (lhs instanceof Boolean)
+        {
+            Object rhs;
+            try
+            {
+                rhs = coerceType(lhs, (String) rhsUnknown);
+            }
+            catch (Exception ex)
+            {
+                return false;
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                case SimpleFilter.GTE :
+                case SimpleFilter.LTE :
+                case SimpleFilter.APPROX :
+                    return (lhs.equals(rhs));
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+
+        // If the LHS is not a comparable or boolean, check if it is an
+        // array. If so, convert it to a list so we can treat it as a
+        // collection.
+        if (lhs.getClass().isArray())
+        {
+            lhs = convertArrayToList(lhs);
+        }
+
+        // If LHS is a collection, then call compare() on each element
+        // of the collection until a match is found.
+        if (lhs instanceof Collection)
+        {
+            for (Iterator iter = ((Collection) lhs).iterator(); iter.hasNext(); )
+            {
+                if (compare(iter.next(), rhsUnknown, op))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        // Spec says SUBSTRING is false for all types other than string.
+        if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
+        {
+            return false;
+        }
+
+        // Since we cannot identify the LHS type, then we can only perform
+        // equality comparison.
+        try
+        {
+            return lhs.equals(coerceType(lhs, (String) rhsUnknown));
+        }
+        catch (Exception ex)
+        {
+            return false;
+        }
+    }
+
+    private static boolean compareApproximate(Object lhs, Object rhs)
+    {
+        if (rhs instanceof String)
+        {
+            return removeWhitespace((String) lhs)
+                .equalsIgnoreCase(removeWhitespace((String) rhs));
+        }
+        else if (rhs instanceof Character)
+        {
+            return Character.toLowerCase(((Character) lhs))
+                == Character.toLowerCase(((Character) rhs));
+        }
+        return lhs.equals(rhs);
+    }
+
+    private static String removeWhitespace(String s)
+    {
+        StringBuffer sb = new StringBuffer(s.length());
+        for (int i = 0; i < s.length(); i++)
+        {
+            if (!Character.isWhitespace(s.charAt(i)))
+            {
+                sb.append(s.charAt(i));
+            }
+        }
+        return sb.toString();
+    }
+
+    private static Object coerceType(Object lhs, String rhsString) throws Exception
+    {
+        // If the LHS expects a string, then we can just return
+        // the RHS since it is a string.
+        if (lhs.getClass() == rhsString.getClass())
+        {
+            return rhsString;
+        }
+
+        // Try to convert the RHS type to the LHS type by using
+        // the string constructor of the LHS class, if it has one.
+        Object rhs = null;
+        try
+        {
+            // The Character class is a special case, since its constructor
+            // does not take a string, so handle it separately.
+            if (lhs instanceof Character)
+            {
+                rhs = new Character(rhsString.charAt(0));
+            }
+            else if(lhs instanceof Version && rhsString.indexOf(',') >= 0)
+            {
+                rhs = VersionRange.valueOf(rhsString);
+            }
+            else
+            {
+                // Spec says we should trim number types.
+                if ((lhs instanceof Number) || (lhs instanceof Boolean))
+                {
+                    rhsString = rhsString.trim();
+                }
+
+                try
+                {
+                    // Try to find a suitable static valueOf method
+                    Method valueOfMethod = m_secureAction.getDeclaredMethod(
+                        lhs.getClass(), VALUE_OF_METHOD_NAME, STRING_CLASS);
+                    if (valueOfMethod.getReturnType().isAssignableFrom(lhs.getClass())
+                        && ((valueOfMethod.getModifiers() & Modifier.STATIC) > 0))
+                    {
+                        m_secureAction.setAccesssible(valueOfMethod);
+                        rhs = valueOfMethod.invoke(null, new Object[] { rhsString });
+                    }
+                }
+                catch (Exception ex)
+                {
+                    // Static valueOf fails, try the next conversion mechanism
+                }
+
+                if (rhs == null)
+                {
+                    Constructor ctor = m_secureAction.getConstructor(lhs.getClass(), STRING_CLASS);
+                    m_secureAction.setAccesssible(ctor);
+                    rhs = ctor.newInstance(new Object[] { rhsString });
+                }
+            }
+        }
+        catch (Exception ex)
+        {
+            throw new Exception(
+                "Could not instantiate class "
+                    + lhs.getClass().getName()
+                    + " from string constructor with argument '"
+                    + rhsString + "' because " + ex);
+        }
+
+        return rhs;
+    }
+
+    /**
+     * This is an ugly utility method to convert an array of primitives
+     * to an array of primitive wrapper objects. This method simplifies
+     * processing LDAP filters since the special case of primitive arrays
+     * can be ignored.
+     * @param array An array of primitive types.
+     * @return An corresponding array using pritive wrapper objects.
+    **/
+    private static List convertArrayToList(Object array)
+    {
+        int len = Array.getLength(array);
+        List list = new ArrayList(len);
+        for (int i = 0; i < len; i++)
+        {
+            list.add(Array.get(array, i));
+        }
+        return list;
+    }
+}

Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySetRepository.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySetRepository.java?rev=1700842&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySetRepository.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/capabilityset/CapabilitySetRepository.java Wed Sep  2 15:26:45 2015
@@ -0,0 +1,121 @@
+/*
+ * 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.aries.subsystem.core.capabilityset;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.aries.subsystem.core.repository.Repository;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.ExecutionEnvironmentNamespace;
+import org.osgi.framework.namespace.HostNamespace;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.namespace.NativeNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.namespace.service.ServiceNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+public class CapabilitySetRepository implements Repository {
+    private final Map<String, CapabilitySet> namespace2capabilitySet;
+
+    public CapabilitySetRepository() {
+        namespace2capabilitySet = Collections.synchronizedMap(new HashMap<String, CapabilitySet>());
+        namespace2capabilitySet.put(
+                IdentityNamespace.IDENTITY_NAMESPACE, 
+                new CapabilitySet(Arrays.asList(IdentityNamespace.IDENTITY_NAMESPACE), true));
+        namespace2capabilitySet.put(
+                NativeNamespace.NATIVE_NAMESPACE, 
+                new CapabilitySet(Arrays.asList(NativeNamespace.NATIVE_NAMESPACE), true));
+        namespace2capabilitySet.put(
+                ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE, 
+                new CapabilitySet(Arrays.asList(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE), true));
+        namespace2capabilitySet.put(
+                BundleNamespace.BUNDLE_NAMESPACE, 
+                new CapabilitySet(Arrays.asList(BundleNamespace.BUNDLE_NAMESPACE), true));
+        namespace2capabilitySet.put(
+                HostNamespace.HOST_NAMESPACE, 
+                new CapabilitySet(Arrays.asList(HostNamespace.HOST_NAMESPACE), true));
+        namespace2capabilitySet.put(
+                PackageNamespace.PACKAGE_NAMESPACE, 
+                new CapabilitySet(Arrays.asList(PackageNamespace.PACKAGE_NAMESPACE), true));
+        namespace2capabilitySet.put(
+                ServiceNamespace.SERVICE_NAMESPACE, 
+                new CapabilitySet(Arrays.asList(ServiceNamespace.CAPABILITY_OBJECTCLASS_ATTRIBUTE), true));
+    }
+    
+    public void addResource(Resource resource) {
+        for (Capability capability : resource.getCapabilities(null)) {
+            String namespace = capability.getNamespace();
+            CapabilitySet capabilitySet;
+            synchronized (namespace2capabilitySet) {
+                capabilitySet = namespace2capabilitySet.get(namespace);
+                if (capabilitySet == null) {
+                    capabilitySet = new CapabilitySet(Arrays.asList(namespace), true);
+                    namespace2capabilitySet.put(namespace, capabilitySet);
+                }
+            }
+            // TODO Examine CapabilitySet for thread safety.
+            capabilitySet.addCapability(capability);
+        }
+    }
+
+    @Override
+    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) {
+            String filterDirective = requirement.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
+            SimpleFilter simpleFilter;
+            if (filterDirective == null) {
+                simpleFilter = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+            }
+            else {
+                simpleFilter = SimpleFilter.parse(filterDirective);
+            }
+            String namespace = requirement.getNamespace();
+            CapabilitySet capabilitySet = namespace2capabilitySet.get(namespace);
+            if (capabilitySet != null) {
+                Set<Capability> capabilities = capabilitySet.match(
+                        simpleFilter, 
+                        PackageNamespace.PACKAGE_NAMESPACE.equals(namespace)
+                                || BundleNamespace.BUNDLE_NAMESPACE.equals(namespace)
+                                || HostNamespace.HOST_NAMESPACE.equals(namespace));
+                result.put(requirement, capabilities);
+            }
+        }
+        return result;
+    }
+    
+    public void removeResource(Resource resource) {
+        for (Capability capability : resource.getCapabilities(null)) {
+            CapabilitySet capabilitySet = namespace2capabilitySet.get(capability.getNamespace());
+            if (capabilitySet == null) {
+                continue;
+            }
+            // TODO Examine CapabilitySet for thread safety.
+            capabilitySet.removeCapability(capability);
+        }
+    }
+}