package org.geotools.data.efeature.query;
import java.util.Date;
import org.eclipse.emf.query.conditions.DataTypeCondition;
import org.geotools.data.efeature.adapters.DateAdapter;
/**
* A <code>Condition</code> object that tests for {@link Date} arguments. The arguments being
* evaluated are adapted to a <code>Date</code> first using a <code>DateAdapter</code> and then
* compared to the initialization value of this <code>DateCondition</code>. It evaluates to
* <code>true</code> when the values are equal or if the value is within the range of supplied
* lower-bound and upper-bound.
* <p>
* This implementation is based on the {@link NumberCondition} source code by Christian W. Damus
* (cdamus), IBM.
* </p>
*
* @author kengu
*
*/
public class DateCondition extends DataTypeCondition<Date> {
/** The numeric {@literal =} operator. */
public static RelationalOperator EQUAL_TO = RelationalOperator.EQUAL_TO;
/** The numeric {@literal !=} operator. */
public static RelationalOperator NOT_EQUAL_TO = RelationalOperator.NOT_EQUAL_TO;
/** The numeric {@literal <} operator. */
public static RelationalOperator LESS_THAN = RelationalOperator.LESS_THAN;
/** The numeric {@literal <=} operator. */
public static RelationalOperator LESS_THAN_OR_EQUAL_TO = RelationalOperator.LESS_THAN_OR_EQUAL_TO;
/** The numeric {@literal >} operator. */
public static RelationalOperator GREATER_THAN = RelationalOperator.GREATER_THAN;
/** The numeric {@literal >=} operator. */
public static RelationalOperator GREATER_THAN_OR_EQUAL_TO = RelationalOperator.GREATER_THAN_OR_EQUAL_TO;
/** The numeric "between" operator. */
public static RelationalOperator BETWEEN = RelationalOperator.BETWEEN;
/** The numeric "outside" operator. */
public static RelationalOperator OUTSIDE = RelationalOperator.OUTSIDE;
/** The upper bound of a range condition. */
protected Date upperBound;
/** Whether the upper bound is inclusive. */
protected boolean upperInclusive;
/** The lower bound of a range condition. */
protected Date lowerBound;
/** Whether the lower bound is inclusive. */
protected boolean lowerInclusive;
/** The operator of a relational condition. */
protected RelationalOperator operator;
/**
* Initializes me with a single date against which to test input values, assuming that they will
* be {@link Date} objects. I am, by default, an {@linkplain #EQUAL_TO equality} test.
*
* @param date - the {@link Date} object to match against input values
*
* @since 1.2
*/
public DateCondition(Date date) {
this(date, EQUAL_TO, DateAdapter.DEFAULT);
}
/**
* Initializes me with a single date against which to test input values, and an adapter to
* convert those inputs to {@link Date} objects. I am, by default, an {@linkplain #EQUAL_TO
* equality} test.
*
* @param date - the {@link Date} object to match against input values
* @param adapter - converts input values to {@link Date} objects
*
* @since 1.2
*/
public DateCondition(Date date, DateAdapter adapter) {
this(date, EQUAL_TO, adapter);
}
/**
* Initializes me with a {@link Date} object against which to test input values and a relational
* operator to apply in comparisons. I assume that inputs are {@link Date} objects.
*
* @param date - the {@link Date} object to match against input values
* @param operator - the relational operator to test
*
* @since 1.2
*/
public DateCondition(Date date, RelationalOperator operator) {
this(date, operator, DateAdapter.DEFAULT);
}
/**
* Initializes me with a {@link Date} object against which to test input values, a relational
* operator to apply in comparisons, and an adapter to convert those inputs to {@link Date}
* objects.
*
* @param date - the {@link Date} object to match against input values
* @param operator - the relational operator to test
* @param adapter - converts input values to {@link Date} objects
*
* @since 1.2
*/
public DateCondition(Date date, RelationalOperator operator, DateAdapter adapter) {
super(date, adapter);
switch (operator) {
case EQUAL_TO:
this.lowerBound = date;
this.lowerInclusive = true;
this.upperBound = date;
this.upperInclusive = true;
break;
case NOT_EQUAL_TO:
this.lowerBound = date;
this.lowerInclusive = false;
this.upperBound = date;
this.upperInclusive = false;
break;
case LESS_THAN:
this.upperBound = date;
this.upperInclusive = false;
break;
case LESS_THAN_OR_EQUAL_TO:
this.upperBound = date;
this.upperInclusive = true;
break;
case GREATER_THAN:
this.lowerBound = date;
this.lowerInclusive = false;
break;
case GREATER_THAN_OR_EQUAL_TO:
this.lowerBound = date;
this.lowerInclusive = true;
break;
}
this.operator = operator;
}
/**
* Initializes me with upper and lower bounds against which to test input values, assuming that
* they will be {@link Date} objects. I am, by default, a {@linkplain #BETWEEN between} test.
* @param between TODO
* @param lowerBound - the lower bound to test
* @param upperBound - the upper bound to test
*
* @since 1.2
*/
public DateCondition(boolean between, Date lowerBound, Date upperBound) {
this(between, lowerBound, true, upperBound, true, DateAdapter.DEFAULT);
}
/**
* Initializes me with upper and lower bounds against which to test input values, and an adapter
* to convert those inputs to {@link Date} objects.
* @param between - if <code>true</code>, use the {@link #BETWEEN} operator. Otherwise use the {@link #OUTSIDE} operator
* @param lowerBound - the lower bound to test
* @param upperBound - the upper bound to test
* @param adapter - converts input values to {@link Date} objects
*
* @since 1.2
*/
public DateCondition(boolean between, Date lowerBound, Date upperBound, DateAdapter adapter) {
this(between, lowerBound, true, upperBound, true, adapter);
}
/**
* Initializes me with upper and lower bounds against which to test input values, assuming that
* they will be {@link Date} objects. I am, by default, a {@linkplain #BETWEEN between} test.
* @param between - if <code>true</code>, use the {@link #BETWEEN} operator. Otherwise use the {@link #OUTSIDE} operator
* @param lowerBound - the lower bound to test
* @param lowerInclusive - whether the lower bound is inclusive
* @param upperBound - the upper bound to test
* @param upperInclusive - whether the upper bound is inclusive
*
* @since 1.2
*/
public DateCondition(boolean between, Date lowerBound, boolean lowerInclusive,
Date upperBound, boolean upperInclusive) {
this(between, lowerBound, lowerInclusive, upperBound, upperInclusive, DateAdapter.DEFAULT);
}
/**
* Initializes me with upper and lower bounds against which to test input values, and an adapter
* to convert those inputs to {@link Date} objects.
* @param between - if <code>true</code>, use the {@link #BETWEEN} operator. Otherwise use the {@link #OUTSIDE} operator
* @param lowerBound - the lower bound to test
* @param lowerInclusive - whether the lower bound is inclusive
* @param upperBound - the upper bound to test
* @param upperInclusive - whether the upper bound is inclusive
* @param adapter - to convert input values to {@link Date} objects
*
* @since 1.2
*/
public DateCondition(boolean between, Date lowerBound, boolean lowerInclusive,
Date upperBound, boolean upperInclusive, DateAdapter adapter) {
super(lowerBound, adapter);
this.lowerBound = lowerBound;
this.lowerInclusive = lowerInclusive;
this.upperBound = upperBound;
this.upperInclusive = upperInclusive;
this.operator = between ? BETWEEN : OUTSIDE;
}
/**
* Obtains a condition checking for values equal to the specified {@link Date}.
*
* @param date - a {@link Date} to check for
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition equals(Date date) {
return new DateCondition(date, EQUAL_TO);
}
/**
* Obtains a condition checking for values not equal to the specified {@link Date}.
*
* @param date - a {@link Date} to check for
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition notEquals(Date date) {
return new DateCondition(date, NOT_EQUAL_TO);
}
/**
* Obtains a condition checking for values less than the specified <tt>date</tt>.
*
* @param date - a {@link Date} to check for
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition lessThan(Date date) {
return new DateCondition(date, LESS_THAN);
}
/**
* Obtains a condition checking for values less than or equal to the specified <tt>date</tt>.
*
* @param date - a {@link Date} to check for
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition lessThanOrEquals(Date date) {
return new DateCondition(date, LESS_THAN_OR_EQUAL_TO);
}
/**
* Obtains a condition checking for values greater than the specified <tt>date</tt>.
*
* @param date - a {@link Date} to check for
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition greaterThan(Date date) {
return new DateCondition(date, GREATER_THAN);
}
/**
* Obtains a condition checking for values greater than or equal to the specified <tt>date</tt>.
*
* @param date - a {@link Date} to check for
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition greaterThanOrEquals(Date date) {
return new DateCondition(date, GREATER_THAN_OR_EQUAL_TO);
}
/**
* Obtains a condition checking for values in the range to the specified <tt>lowerBound</tt> and
* <tt>upperBound</tt> (inclusive).
*
* @param lowerBound the lower bound of numbers to check for (inclusive)
* @param upperBound the upper bound of numbers to check for (inclusive)
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition between(Date lowerBound, Date upperBound) {
return between(lowerBound, true, upperBound, true);
}
/**
* Obtains a condition checking for values in the range to the specified <tt>lowerBound</tt> and
* <tt>upperBound</tt>.
*
* @param lowerBound the lower bound of numbers to check for
* @param lowerInclusive whether the lower bound is inclusive
* @param upperBound the upper bound of numbers to check for
* @param upperInclusive whether the upper bound is inclusive
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition between(Date lowerBound, boolean lowerInclusive, Date upperBound,
boolean upperInclusive) {
return new DateCondition(true, lowerBound, lowerInclusive, upperBound, upperInclusive);
}
/**
* Obtains a condition checking for values in the range to the specified <tt>lowerBound</tt> and
* <tt>upperBound</tt> (inclusive).
*
* @param lowerBound the lower bound of numbers to check for (inclusive)
* @param upperBound the upper bound of numbers to check for (inclusive)
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition outside(Date lowerBound, Date upperBound) {
return outside(lowerBound, true, upperBound, true);
}
/**
* Obtains a condition checking for values in the range to the specified <tt>lowerBound</tt> and
* <tt>upperBound</tt>.
*
* @param lowerBound the lower bound of numbers to check for
* @param lowerInclusive whether the lower bound is inclusive
* @param upperBound the upper bound of numbers to check for
* @param upperInclusive whether the upper bound is inclusive
* @return a condition that does the checking
*
* @since 1.2
*/
public static DateCondition outside(Date lowerBound, boolean lowerInclusive, Date upperBound,
boolean upperInclusive) {
return new DateCondition(false, lowerBound, lowerInclusive, upperBound, upperInclusive);
}
/**
* Tests if the argument's value equals/in-range the initialization date(s)
*
* @param date The <code>Short</code> object whose value will be used in testing
* @return true if values are equal/in-range, false otherwise
*/
public boolean isSatisfied(Date date) {
return isSatisfied(date.getTime());
}
/**
* Tests if the argument's value equals/in-range the initialization date(s)
*
* @param date The short value which will be used in testing
* @return true if values are equal/in-range, false otherwise
*/
public boolean isSatisfied(long date) {
return (date >= lowerBound.getTime()) && (date <= upperBound.getTime());
}
@Override
public boolean isSatisfied(Object object) {
return operator.isSatisfied(this, adapter.adapt(object));
}
/**
* The relational operator that a {@link NumberCondition} applies to test input values against
* its own value or, in the case of {@link #BETWEEN}, its upper and lower bounds.
*
* @since 1.2
*/
public static enum RelationalOperator {
EQUAL_TO {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.value.compareTo(date) == 0);
};
},
NOT_EQUAL_TO {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.value.compareTo(date) != 0);
};
},
LESS_THAN {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.value.compareTo(date) > 0);
};
},
LESS_THAN_OR_EQUAL_TO {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.value.compareTo(date) >= 0);
};
},
GREATER_THAN {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.value.compareTo(date) < 0);
};
},
GREATER_THAN_OR_EQUAL_TO {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.value.compareTo(date) <= 0);
};
},
BETWEEN {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.lowerInclusive ? (cond.lowerBound.compareTo(date) <= 0)
: (cond.lowerBound.compareTo(date) < 0))
&& (cond.upperInclusive ? (cond.upperBound.compareTo(date) >= 0)
: (cond.upperBound.compareTo(date) > 0));
};
},
OUTSIDE {
@Override
boolean isSatisfied(DateCondition cond, Date date) {
return (cond.lowerInclusive ? (cond.lowerBound.compareTo(date) >= 0)
: (cond.lowerBound.compareTo(date) > 0))
|| (cond.upperInclusive ? (cond.upperBound.compareTo(date) <= 0)
: (cond.upperBound.compareTo(date) < 0));
};
};
/**
* Tests the specified condition against an input value.
*
* @param cond - the {@link Date} condition to test against
* @param date - the input value
*
* @return the result of my specific test
*/
abstract boolean isSatisfied(DateCondition cond, Date date);
}
}