You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2010/01/14 18:49:27 UTC

svn commit: r899324 - /felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/CapabilitySet.java

Author: rickhall
Date: Thu Jan 14 17:49:27 2010
New Revision: 899324

URL: http://svn.apache.org/viewvc?rev=899324&view=rev
Log:
Add more type support to filter matching.

Modified:
    felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/CapabilitySet.java

Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/CapabilitySet.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/CapabilitySet.java?rev=899324&r1=899323&r2=899324&view=diff
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/CapabilitySet.java (original)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/CapabilitySet.java Thu Jan 14 17:49:27 2010
@@ -18,13 +18,13 @@
  */
 package org.apache.felix.resolver.cs;
 
+import java.util.Collection;
 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 org.apache.felix.resolver.Version;
 
 public class CapabilitySet
 {
@@ -156,30 +156,13 @@
                 {
                     Capability cap = it.next();
                     Attribute attr = cap.getAttribute(sf.getName());
-                    Comparable value = (Comparable)
-                        ((attr == null) ? null : cap.getAttribute(sf.getName()).getValue());
-                    if (value != null)
+                    if (attr != null)
                     {
-                        switch (sf.getOperation())
+                        Object lhs = attr.getValue();
+                        Object rhs = coerceType(lhs, (String) sf.getValue());
+                        if (compare(lhs, rhs, sf.getOperation()))
                         {
-                            case SimpleFilter.EQ:
-                                if (value.compareTo(coerceType(value, (String) sf.getValue())) == 0)
-                                {
-                                    matches.add(cap);
-                                }
-                                break;
-                            case SimpleFilter.LTE:
-                                if (value.compareTo(coerceType(value, (String) sf.getValue())) <= 0)
-                                {
-                                    matches.add(cap);
-                                }
-                                break;
-                            case SimpleFilter.GTE:
-                                if (value.compareTo(coerceType(value, (String) sf.getValue())) >= 0)
-                                {
-                                    matches.add(cap);
-                                }
-                                break;
+                            matches.add(cap);
                         }
                     }
                 }
@@ -261,49 +244,6 @@
         return matched && matchMandatory(cap, sf);
     }
 
-    private static final Class[] STRING_CLASS = new Class[] { String.class };
-
-    private static Object coerceType(Comparable lhs, String rhs)
-    {
-        if (lhs instanceof String)
-        {
-            return rhs;
-        }
-
-        // Here we know that the LHS is a comparable object, so
-        // try to create an object for the RHS by using a constructor
-        // that will take the RHS string as a parameter.
-        Comparable rhsComparable = null;
-        try
-        {
-            // We are expecting to be able to construct a comparable
-            // instance from the RHS string by passing it into the
-            // constructor of the corresponing comparable class. The
-            // Character class is a special case, since its constructor
-            // does not take a string, so handle it separately.
-            if (lhs instanceof Character)
-            {
-                rhsComparable = new Character(rhs.charAt(0));
-            }
-            else
-            {
-                rhsComparable = (Comparable) lhs.getClass()
-                    .getConstructor(STRING_CLASS)
-                        .newInstance(new Object[] { rhs });
-            }
-        }
-        catch (Exception ex)
-        {
-            throw new RuntimeException(
-                "Could not instantiate class "
-                    + lhs.getClass().getName()
-                    + " with constructor String parameter "
-                    + rhs + " " + ex);
-        }
-
-        return rhsComparable;
-    }
-
     private static Set<Capability> matchMandatory(Set<Capability> caps, SimpleFilter sf)
     {
         for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
@@ -353,4 +293,210 @@
         }
         return false;
     }
+
+    private static final Class[] STRING_CLASS = new Class[] { String.class };
+
+    private static boolean compare(Object lhs, Object rhs, int op)
+    {
+        // If the type is comparable, then we can just return the
+        // result immediately.
+        if (lhs instanceof Comparable)
+        {
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                    return (((Comparable) lhs).compareTo(rhs) == 0);
+                case SimpleFilter.GTE :
+                    return (((Comparable) lhs).compareTo(rhs) >= 0);
+                case SimpleFilter.LTE :
+                    return (((Comparable) lhs).compareTo(rhs) <= 0);
+//                case SimpleFilter.APPROX :
+//                    return compareToApprox(((Comparable) lhs), rhs);
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+        // Booleans do not implement comparable, so special case them.
+        else if (lhs instanceof Boolean)
+        {
+            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, call compare() on each element of the array until
+        // a match is found.
+        else if (lhs.getClass().isArray())
+        {
+            // If this is an array of primitives, then convert
+            // the entire array to an array of the associated
+            // primitive wrapper class instances.
+            if (lhs.getClass().getComponentType().isPrimitive())
+            {
+                lhs = convertPrimitiveArray(lhs);
+            }
+
+            // Now call compare on each element of array.
+            Object[] array = (Object[]) lhs;
+            for (int i = 0; i < array.length; i++)
+            {
+                if (compare(array[i], rhs, op))
+                {
+                    return true;
+                }
+            }
+        }
+        // If LHS is a collection, then call compare() on each element
+        // of the collection until a match is found.
+        else if (lhs instanceof Collection)
+        {
+            for (Iterator iter = ((Collection) lhs).iterator(); iter.hasNext(); )
+            {
+                if (compare(iter.next(), rhs, op))
+                {
+                    return true;
+                }
+            }
+        }
+
+        // Since we cannot identify the LHS type, then we can only perform
+        // equality comparison.
+        return lhs.equals(rhs);
+    }
+
+    private static Object coerceType(Object lhs, String rhsString)
+    {
+        // 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
+            {
+                rhs = lhs.getClass()
+                    .getConstructor(STRING_CLASS)
+                        .newInstance(new Object[] { rhsString });
+            }
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(
+                "Could not instantiate class "
+                    + lhs.getClass().getName()
+                    + " using 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 Object[] convertPrimitiveArray(Object array)
+    {
+        Class clazz = array.getClass().getComponentType();
+
+        if (clazz == Boolean.TYPE)
+        {
+            boolean[] src = (boolean[]) array;
+            array = new Boolean[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = (src[i] ? Boolean.TRUE : Boolean.FALSE);
+            }
+        }
+        else if (clazz == Character.TYPE)
+        {
+            char[] src = (char[]) array;
+            array = new Character[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = new Character(src[i]);
+            }
+        }
+        else if (clazz == Byte.TYPE)
+        {
+            byte[] src = (byte[]) array;
+            array = new Byte[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = new Byte(src[i]);
+            }
+        }
+        else if (clazz == Short.TYPE)
+        {
+            byte[] src = (byte[]) array;
+            array = new Byte[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = new Byte(src[i]);
+            }
+        }
+        else if (clazz == Integer.TYPE)
+        {
+            int[] src = (int[]) array;
+            array = new Integer[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = new Integer(src[i]);
+            }
+        }
+        else if (clazz == Long.TYPE)
+        {
+            long[] src = (long[]) array;
+            array = new Long[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = new Long(src[i]);
+            }
+        }
+        else if (clazz == Float.TYPE)
+        {
+            float[] src = (float[]) array;
+            array = new Float[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = new Float(src[i]);
+            }
+        }
+        else if (clazz == Double.TYPE)
+        {
+            double[] src = (double[]) array;
+            array = new Double[src.length];
+            for (int i = 0; i < src.length; i++)
+            {
+                ((Object[]) array)[i] = new Double(src[i]);
+            }
+        }
+
+        return (Object[]) array;
+    }
 }
\ No newline at end of file