Browse Source

#6286 Container filtering improvements: initial version of the Compare filter(s) with limited unit tests

svn changeset:17816/svn branch:6.6
tags/6.7.0.beta1
Henri Sara 13 years ago
parent
commit
084206d65d

+ 316
- 0
src/com/vaadin/data/util/filter/Compare.java View File

@@ -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;
}
}

+ 140
- 0
tests/src/com/vaadin/tests/server/container/filter/CompareFilterTest.java View File

@@ -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());
}
}

Loading…
Cancel
Save