]> source.dussan.org Git - vaadin-framework.git/commitdiff
#6286 Container filtering improvements: initial version of the Compare filter(s)...
authorHenri Sara <henri.sara@itmill.com>
Wed, 16 Mar 2011 13:49:34 +0000 (13:49 +0000)
committerHenri Sara <henri.sara@itmill.com>
Wed, 16 Mar 2011 13:49:34 +0000 (13:49 +0000)
svn changeset:17816/svn branch:6.6

src/com/vaadin/data/util/filter/Compare.java [new file with mode: 0644]
tests/src/com/vaadin/tests/server/container/filter/CompareFilterTest.java [new file with mode: 0644]

diff --git a/src/com/vaadin/data/util/filter/Compare.java b/src/com/vaadin/data/util/filter/Compare.java
new file mode 100644 (file)
index 0000000..dc17b40
--- /dev/null
@@ -0,0 +1,316 @@
+package com.vaadin.data.util.filter;
+
+import com.vaadin.data.Container.Filter;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+
+/**
+ * Simple container filter comparing an item property value against a given
+ * constant value. Use the nested classes {@link Equal}, {@link Greater},
+ * {@link Less}, {@link GreaterOrEqual} and {@link LessOrEqual} instead of this
+ * class directly.
+ * 
+ * This filter also directly supports in-memory filtering.
+ * 
+ * The reference and actual values must implement {@link Comparable} and the
+ * class of the actual property value must be assignable from the class of the
+ * reference value.
+ * 
+ * @since 6.6
+ */
+public abstract class Compare implements Filter {
+
+    public enum Operation {
+        EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL
+    };
+
+    private final Object propertyId;
+    private final Operation operation;
+    private final Object value;
+
+    /**
+     * A {@link Compare} filter that accepts items for which the identified
+     * property value is equal to <code>value</code>.
+     * 
+     * For in-memory filters, equals() is used for the comparison. For other
+     * containers, the comparison implementation is container dependent and may
+     * use e.g. database comparison operations.
+     * 
+     * @since 6.6
+     */
+    public static final class Equal extends Compare {
+        /**
+         * Construct a filter that accepts items for which the identified
+         * property value is equal to <code>value</code>.
+         * 
+         * For in-memory filters, equals() is used for the comparison. For other
+         * containers, the comparison implementation is container dependent and
+         * may use e.g. database comparison operations.
+         * 
+         * @param propertyId
+         *            the identifier of the property whose value to compare
+         *            against value
+         * @param value
+         *            the value to compare against
+         */
+        public Equal(Object propertyId, Object value) {
+            super(propertyId, value, Operation.EQUAL);
+        }
+    }
+
+    /**
+     * A {@link Compare} filter that accepts items for which the identified
+     * property value is greater than <code>value</code>.
+     * 
+     * For in-memory filters, the values must implement {@link Comparable} and
+     * {@link Comparable#compareTo(Object)} is used for the comparison. For
+     * other containers, the comparison implementation is container dependent
+     * and may use e.g. database comparison operations.
+     * 
+     * @since 6.6
+     */
+    public static final class Greater extends Compare {
+        /**
+         * Construct a filter that accepts items for which the identified
+         * property value is greater than <code>value</code>.
+         * 
+         * For in-memory filters, the values must implement {@link Comparable}
+         * and {@link Comparable#compareTo(Object)} is used for the comparison.
+         * For other containers, the comparison implementation is container
+         * dependent and may use e.g. database comparison operations.
+         * 
+         * @param propertyId
+         *            the identifier of the property whose value to compare
+         *            against value
+         * @param value
+         *            the value to compare against
+         */
+        public Greater(Object propertyId, Object value) {
+            super(propertyId, value, Operation.GREATER);
+        }
+    }
+
+    /**
+     * A {@link Compare} filter that accepts items for which the identified
+     * property value is less than <code>value</code>.
+     * 
+     * For in-memory filters, the values must implement {@link Comparable} and
+     * {@link Comparable#compareTo(Object)} is used for the comparison. For
+     * other containers, the comparison implementation is container dependent
+     * and may use e.g. database comparison operations.
+     * 
+     * @since 6.6
+     */
+    public static final class Less extends Compare {
+        /**
+         * Construct a filter that accepts items for which the identified
+         * property value is less than <code>value</code>.
+         * 
+         * For in-memory filters, the values must implement {@link Comparable}
+         * and {@link Comparable#compareTo(Object)} is used for the comparison.
+         * For other containers, the comparison implementation is container
+         * dependent and may use e.g. database comparison operations.
+         * 
+         * @param propertyId
+         *            the identifier of the property whose value to compare
+         *            against value
+         * @param value
+         *            the value to compare against
+         */
+        public Less(Object propertyId, Object value) {
+            super(propertyId, value, Operation.LESS);
+        }
+    }
+
+    /**
+     * A {@link Compare} filter that accepts items for which the identified
+     * property value is greater than or equal to <code>value</code>.
+     * 
+     * For in-memory filters, the values must implement {@link Comparable} and
+     * {@link Comparable#compareTo(Object)} is used for the comparison. For
+     * other containers, the comparison implementation is container dependent
+     * and may use e.g. database comparison operations.
+     * 
+     * @since 6.6
+     */
+    public static final class GreaterOrEqual extends Compare {
+        /**
+         * Construct a filter that accepts items for which the identified
+         * property value is greater than or equal to <code>value</code>.
+         * 
+         * For in-memory filters, the values must implement {@link Comparable}
+         * and {@link Comparable#compareTo(Object)} is used for the comparison.
+         * For other containers, the comparison implementation is container
+         * dependent and may use e.g. database comparison operations.
+         * 
+         * @param propertyId
+         *            the identifier of the property whose value to compare
+         *            against value
+         * @param value
+         *            the value to compare against
+         */
+        public GreaterOrEqual(Object propertyId, Object value) {
+            super(propertyId, value, Operation.GREATER_OR_EQUAL);
+        }
+    }
+
+    /**
+     * A {@link Compare} filter that accepts items for which the identified
+     * property value is less than or equal to <code>value</code>.
+     * 
+     * For in-memory filters, the values must implement {@link Comparable} and
+     * {@link Comparable#compareTo(Object)} is used for the comparison. For
+     * other containers, the comparison implementation is container dependent
+     * and may use e.g. database comparison operations.
+     * 
+     * @since 6.6
+     */
+    public static final class LessOrEqual extends Compare {
+        /**
+         * Construct a filter that accepts items for which the identified
+         * property value is less than or equal to <code>value</code>.
+         * 
+         * For in-memory filters, the values must implement {@link Comparable}
+         * and {@link Comparable#compareTo(Object)} is used for the comparison.
+         * For other containers, the comparison implementation is container
+         * dependent and may use e.g. database comparison operations.
+         * 
+         * @param propertyId
+         *            the identifier of the property whose value to compare
+         *            against value
+         * @param value
+         *            the value to compare against
+         */
+        public LessOrEqual(Object propertyId, Object value) {
+            super(propertyId, value, Operation.LESS_OR_EQUAL);
+        }
+    }
+
+    /**
+     * Constructor for a {@link Compare} filter that compares the value of an
+     * item property with the given constant <code>value</code>.
+     * 
+     * This constructor is intended to be used by the nested static classes only
+     * ({@link Equal}, {@link Greater}, {@link Less}, {@link GreaterOrEqual},
+     * {@link LessOrEqual}).
+     * 
+     * For in-memory filtering, comparisons except EQUAL require that the values
+     * implement {@link Comparable} and {@link Comparable#compareTo(Object)} is
+     * used for the comparison. The equality comparison is performed using
+     * {@link Object#equals(Object)}.
+     * 
+     * For other containers, the comparison implementation is container
+     * dependent and may use e.g. database comparison operations. Therefore, the
+     * behavior of comparisons might differ in some cases between in-memory and
+     * other containers.
+     * 
+     * @param propertyId
+     *            the identifier of the property whose value to compare against
+     *            value
+     * @param value
+     *            the value to compare against
+     * @param operation
+     *            the comparison {@link Operation} to use
+     */
+    Compare(Object propertyId, Object value, Operation operation) {
+        this.propertyId = propertyId;
+        this.value = value;
+        this.operation = operation;
+    }
+
+    public boolean passesFilter(Object itemId, Item item) {
+        final Property p = item.getItemProperty(getPropertyId());
+        if (null == p) {
+            return false;
+        }
+        Object value = p.getValue();
+        switch (getOperation()) {
+        case EQUAL:
+            return (null == this.value) ? (null == value) : this.value
+                    .equals(value);
+        case GREATER:
+            return compareValue(value) > 0;
+        case LESS:
+            return compareValue(value) < 0;
+        case GREATER_OR_EQUAL:
+            return compareValue(value) >= 0;
+        case LESS_OR_EQUAL:
+            return compareValue(value) <= 0;
+        }
+        // all cases should have been processed above
+        return false;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected int compareValue(Object value1) {
+        if (null == value) {
+            return null == value1 ? 0 : -1;
+        } else if (null == value1) {
+            return 1;
+        } else if (getValue() instanceof Comparable
+                && value1.getClass().isAssignableFrom(getValue().getClass())) {
+            return -((Comparable) getValue()).compareTo(value1);
+        }
+        throw new IllegalArgumentException("Could not compare the arguments: "
+                + value1 + ", " + getValue());
+    }
+
+    public boolean appliesToProperty(Object propertyId) {
+        return getPropertyId().equals(propertyId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+
+        // Only objects of the same class can be equal
+        if (!getClass().equals(obj.getClass())) {
+            return false;
+        }
+        final Compare o = (Compare) obj;
+
+        // Checks the properties one by one
+        if (getPropertyId() != o.getPropertyId() && null != o.getPropertyId()
+                && !o.getPropertyId().equals(getPropertyId())) {
+            return false;
+        }
+        if (getOperation() != o.getOperation()) {
+            return false;
+        }
+        return (null == getValue()) ? null == o.getValue() : getValue().equals(
+                o.getValue());
+    }
+
+    @Override
+    public int hashCode() {
+        return (null != getPropertyId() ? getPropertyId().hashCode() : 0)
+                ^ (null != getValue() ? getValue().hashCode() : 0);
+    }
+
+    /**
+     * Returns the property id of the property to compare against the fixed
+     * value.
+     * 
+     * @return property id
+     */
+    public Object getPropertyId() {
+        return propertyId;
+    }
+
+    /**
+     * Returns the comparison operation.
+     * 
+     * @return {@link Operation}
+     */
+    public Operation getOperation() {
+        return operation;
+    }
+
+    /**
+     * Returns the value to compare the property against.
+     * 
+     * @return comparison reference value
+     */
+    public Object getValue() {
+        return value;
+    }
+}
diff --git a/tests/src/com/vaadin/tests/server/container/filter/CompareFilterTest.java b/tests/src/com/vaadin/tests/server/container/filter/CompareFilterTest.java
new file mode 100644 (file)
index 0000000..b206cb5
--- /dev/null
@@ -0,0 +1,140 @@
+package com.vaadin.tests.server.container.filter;
+
+import junit.framework.Assert;
+
+import com.vaadin.data.Container.Filter;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.ObjectProperty;
+import com.vaadin.data.util.PropertysetItem;
+import com.vaadin.data.util.filter.Compare.Equal;
+import com.vaadin.data.util.filter.Compare.Greater;
+import com.vaadin.data.util.filter.Compare.GreaterOrEqual;
+import com.vaadin.data.util.filter.Compare.Less;
+import com.vaadin.data.util.filter.Compare.LessOrEqual;
+
+public class CompareFilterTest extends AbstractFilterTest {
+
+    protected Item itemNull;
+    protected Item itemEmpty;
+    protected Item itemA;
+    protected Item itemB;
+    protected Item itemC;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        itemNull = new PropertysetItem();
+        itemNull.addItemProperty(PROPERTY1, new ObjectProperty<String>(null,
+                String.class));
+        itemEmpty = new PropertysetItem();
+        itemEmpty.addItemProperty(PROPERTY1, new ObjectProperty<String>("",
+                String.class));
+        itemA = new PropertysetItem();
+        itemA.addItemProperty(PROPERTY1, new ObjectProperty<String>("a",
+                String.class));
+        itemB = new PropertysetItem();
+        itemB.addItemProperty(PROPERTY1, new ObjectProperty<String>("b",
+                String.class));
+        itemC = new PropertysetItem();
+        itemC.addItemProperty(PROPERTY1, new ObjectProperty<String>("c",
+                String.class));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        itemNull = null;
+        itemEmpty = null;
+        itemA = null;
+        itemB = null;
+    }
+
+    public void testCompareString() {
+        Filter equalB = new Equal(PROPERTY1, "b");
+        Filter greaterB = new Greater(PROPERTY1, "b");
+        Filter lessB = new Less(PROPERTY1, "b");
+        Filter greaterEqualB = new GreaterOrEqual(PROPERTY1, "b");
+        Filter lessEqualB = new LessOrEqual(PROPERTY1, "b");
+
+        Assert.assertFalse(equalB.passesFilter(null, itemA));
+        Assert.assertTrue(equalB.passesFilter(null, itemB));
+        Assert.assertFalse(equalB.passesFilter(null, itemC));
+
+        Assert.assertFalse(greaterB.passesFilter(null, itemA));
+        Assert.assertFalse(greaterB.passesFilter(null, itemB));
+        Assert.assertTrue(greaterB.passesFilter(null, itemC));
+
+        Assert.assertTrue(lessB.passesFilter(null, itemA));
+        Assert.assertFalse(lessB.passesFilter(null, itemB));
+        Assert.assertFalse(lessB.passesFilter(null, itemC));
+
+        Assert.assertFalse(greaterEqualB.passesFilter(null, itemA));
+        Assert.assertTrue(greaterEqualB.passesFilter(null, itemB));
+        Assert.assertTrue(greaterEqualB.passesFilter(null, itemC));
+
+        Assert.assertTrue(lessEqualB.passesFilter(null, itemA));
+        Assert.assertTrue(lessEqualB.passesFilter(null, itemB));
+        Assert.assertFalse(lessEqualB.passesFilter(null, itemC));
+    }
+
+    // TODO more tests: null comparisons, different datatypes...
+
+    public void testCompareEqualsHashCode() {
+        // most checks with Equal filter, then only some with others
+        Filter equalNull = new Equal(PROPERTY1, null);
+        Filter equalNull2 = new Equal(PROPERTY1, null);
+        Filter equalNullProperty2 = new Equal(PROPERTY2, null);
+        Filter equalEmpty = new Equal(PROPERTY1, "");
+        Filter equalEmpty2 = new Equal(PROPERTY1, "");
+        Filter equalEmptyProperty2 = new Equal(PROPERTY2, "");
+        Filter equalA = new Equal(PROPERTY1, "a");
+        Filter equalA2 = new Equal(PROPERTY1, "a");
+        Filter equalAProperty2 = new Equal(PROPERTY2, "a");
+        Filter equalB = new Equal(PROPERTY1, "b");
+
+        Filter greaterNull = new Greater(PROPERTY1, null);
+        Filter greaterEmpty = new Greater(PROPERTY1, "");
+
+        Filter greaterA = new Greater(PROPERTY1, "a");
+        Filter lessA = new Less(PROPERTY1, "a");
+        Filter greaterEqualA = new GreaterOrEqual(PROPERTY1, "a");
+        Filter lessEqualA = new LessOrEqual(PROPERTY1, "a");
+
+        // equals()
+        Assert.assertEquals(equalNull, equalNull);
+        Assert.assertEquals(equalNull, equalNull2);
+        Assert.assertFalse(equalNull.equals(equalNullProperty2));
+        Assert.assertFalse(equalNull.equals(equalEmpty));
+        Assert.assertFalse(equalNull.equals(equalA));
+
+        Assert.assertEquals(equalEmpty, equalEmpty);
+        Assert.assertFalse(equalEmpty.equals(equalNull));
+        Assert.assertEquals(equalEmpty, equalEmpty2);
+        Assert.assertFalse(equalEmpty.equals(equalEmptyProperty2));
+        Assert.assertFalse(equalEmpty.equals(equalA));
+
+        Assert.assertEquals(equalA, equalA);
+        Assert.assertFalse(equalA.equals(equalNull));
+        Assert.assertFalse(equalA.equals(equalEmpty));
+        Assert.assertEquals(equalA, equalA2);
+        Assert.assertFalse(equalA.equals(equalAProperty2));
+        Assert.assertFalse(equalA.equals(equalB));
+
+        Assert.assertEquals(greaterA, greaterA);
+        Assert.assertFalse(greaterA.equals(lessA));
+        Assert.assertFalse(greaterA.equals(greaterEqualA));
+        Assert.assertFalse(greaterA.equals(lessEqualA));
+
+        Assert.assertFalse(greaterNull.equals(greaterEmpty));
+        Assert.assertFalse(greaterNull.equals(greaterA));
+        Assert.assertFalse(greaterEmpty.equals(greaterNull));
+        Assert.assertFalse(greaterEmpty.equals(greaterA));
+        Assert.assertFalse(greaterA.equals(greaterNull));
+        Assert.assertFalse(greaterA.equals(greaterEmpty));
+
+        // hashCode()
+        Assert.assertEquals(equalNull.hashCode(), equalNull2.hashCode());
+        Assert.assertEquals(equalEmpty.hashCode(), equalEmpty2.hashCode());
+        Assert.assertEquals(equalA.hashCode(), equalA2.hashCode());
+    }
+}