From: Henri Sara Date: Wed, 16 Mar 2011 13:49:34 +0000 (+0000) Subject: #6286 Container filtering improvements: initial version of the Compare filter(s)... X-Git-Tag: 6.7.0.beta1~386 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=084206d65de71e25587bf1a555f4fe58ed6187e8;p=vaadin-framework.git #6286 Container filtering improvements: initial version of the Compare filter(s) with limited unit tests svn changeset:17816/svn branch:6.6 --- diff --git a/src/com/vaadin/data/util/filter/Compare.java b/src/com/vaadin/data/util/filter/Compare.java new file mode 100644 index 0000000000..dc17b40967 --- /dev/null +++ b/src/com/vaadin/data/util/filter/Compare.java @@ -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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 value. + * + * 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 index 0000000000..b206cb511b --- /dev/null +++ b/tests/src/com/vaadin/tests/server/container/filter/CompareFilterTest.java @@ -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(null, + String.class)); + itemEmpty = new PropertysetItem(); + itemEmpty.addItemProperty(PROPERTY1, new ObjectProperty("", + String.class)); + itemA = new PropertysetItem(); + itemA.addItemProperty(PROPERTY1, new ObjectProperty("a", + String.class)); + itemB = new PropertysetItem(); + itemB.addItemProperty(PROPERTY1, new ObjectProperty("b", + String.class)); + itemC = new PropertysetItem(); + itemC.addItemProperty(PROPERTY1, new ObjectProperty("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()); + } +}