/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.filter.text.commons;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import org.opengis.filter.BinaryComparisonOperator;
import org.opengis.filter.BinaryLogicOperator;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.Not;
import org.opengis.filter.PropertyIsBetween;
import org.opengis.filter.PropertyIsLike;
import org.opengis.filter.PropertyIsNull;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.BinarySpatialOperator;
import org.opengis.filter.spatial.DWithin;
import org.opengis.filter.spatial.DistanceBufferOperator;
import org.opengis.filter.temporal.BinaryTemporalOperator;
import org.opengis.filter.temporal.During;
import org.opengis.temporal.Period;
/**
*
* The method of this utility class allows to build the CQL/ECQL predicate associated
* to a {@link Filter}.
*
* <p>
* Warning: This component is not published. It is part of module implementation.
* Client module should not use this feature.
* </p>
*
* @author Mauricio Pazos
*
*
* @source $URL$
*/
public final class FilterToTextUtil {
private final static Logger LOGGER = Logger.getLogger(FilterToTextUtil.class.getName());
private FilterToTextUtil(){
// utility class
}
/**
* Process the possibly user supplied extraData parameter into a StringBuilder.
* @param extraData
* @return
*/
static public StringBuilder asStringBuilder( Object extraData){
if( extraData instanceof StringBuilder){
return (StringBuilder) extraData;
}
return new StringBuilder();
}
public static Object buildInclude(Object extraData) {
StringBuilder output = FilterToTextUtil.asStringBuilder(extraData);
output.append("1 = 1");
return output;
}
public static Object buildExclude(Object extraData) {
StringBuilder output = FilterToTextUtil.asStringBuilder(extraData);
output.append("1 = 0");
return output;
}
/**
* builds: left predicate AND right predicate
*/
public static Object buildBinaryLogicalOperator(final String operator, FilterVisitor visitor, BinaryLogicOperator filter, Object extraData) {
LOGGER.finer("exporting And filter");
StringBuilder output = asStringBuilder(extraData);
List<Filter> children = filter.getChildren();
if (children != null) {
output.append("(");
for (Iterator<Filter> i = children.iterator(); i.hasNext();) {
Filter child = i.next();
child.accept(visitor, output);
if (i.hasNext()) {
output.append(" ").append(operator).append(" ");
}
}
output.append(")");
}
return output;
}
public static Object buildBetween(PropertyIsBetween filter, Object extraData) {
LOGGER.finer("exporting PropertyIsBetween");
ExpressionVisitor exprVisitor = new ExpressionToText();
StringBuilder output = asStringBuilder(extraData);
PropertyName propertyName = (PropertyName) filter.getExpression();
propertyName.accept(exprVisitor, output);
output.append(" BETWEEN ");
filter.getLowerBoundary().accept(exprVisitor, output);
output.append(" AND ");
filter.getUpperBoundary().accept(exprVisitor, output);
return output;
}
public static Object buildNot(FilterVisitor filterToCQL, Not filter, Object extraData) {
StringBuilder output = asStringBuilder(extraData);
output.append( "NOT (");
filter.getFilter().accept(filterToCQL, output );
output.append( ")");
return output;
}
/**
* Builds a comparison predicate inserting the operato1 or operator2 taking into
* account the PropertyName position in the comparison filter.
*
* @param filter
* @param extraData
* @param operator an operator
* @return SringBuffer
*/
static public Object buildComparison(
BinaryComparisonOperator filter,
Object extraData,
String operator) {
StringBuilder output = asStringBuilder(extraData);
ExpressionToText visitor = new ExpressionToText();
Expression expr = filter.getExpression1();
expr.accept(visitor, output);
output.append(" ").append(operator).append(" ");
filter.getExpression2().accept(visitor, output);
return output;
}
public static Object buildIsLike(PropertyIsLike filter, Object extraData) {
StringBuilder output = asStringBuilder(extraData);
final String pattern = filter.getLiteral();
Expression expr = filter.getExpression();
expr.accept(new ExpressionToText(), output);
if(filter.isMatchingCase()){
output.append(" LIKE ");
} else {
output.append(" ILIKE ");
}
output.append("'");
output.append(pattern);
output.append("'");
return output;
}
public static Object buildIsNull(PropertyIsNull filter, Object extraData) {
StringBuilder output = asStringBuilder(extraData);
PropertyName propertyName = (PropertyName) filter.getExpression();
propertyName.accept(new ExpressionToText(), output);
output.append(" IS NULL");
return output;
}
public static Object buildBBOX(BBOX filter, Object extraData) {
StringBuilder output = asStringBuilder(extraData);
output.append( "BBOX(");
output.append( filter.getPropertyName() );
output.append( ", ");
output.append( filter.getMinX() );
output.append( ",");
output.append( filter.getMinY() );
output.append( ",");
output.append( filter.getMaxX() );
output.append( ",");
output.append( filter.getMaxY() );
output.append( ")");
return output;
}
public static Object buildDistanceBufferOperation(final String geoOperation, DistanceBufferOperator filter, Object extraData){
LOGGER.finer("exporting " + geoOperation);
StringBuilder output = asStringBuilder(extraData);
output.append(geoOperation).append("(");
Expression expr = filter.getExpression1();
ExpressionToText visitor = new ExpressionToText();
expr.accept(visitor, output);
output.append(", ");
filter.getExpression2().accept(visitor, output);
output.append(")");
return output;
}
public static Object buildDWithin(DWithin filter, Object extraData) {
LOGGER.finer("exporting DWITHIN");
StringBuilder output = asStringBuilder(extraData);
output.append("DWITHIN(");
PropertyName propertyName = (PropertyName) filter.getExpression1();
ExpressionToText visitor = new ExpressionToText();
propertyName.accept(visitor, output);
output.append(", ");
filter.getExpression2().accept(visitor, output);
output.append(", ");
output.append( filter.getDistance() );
output.append(", ");
output.append( filter.getDistanceUnits() );
output.append(")");
return output;
}
public static Object buildBinarySpatialOperator(
final String spatialOperator,
final BinarySpatialOperator filter,
Object extraData) {
LOGGER.finer("exporting " + spatialOperator);
StringBuilder output = asStringBuilder(extraData);
output.append(spatialOperator).append("(");
Expression expr = filter.getExpression1();
ExpressionToText visitor = new ExpressionToText();
expr.accept(visitor, output);
output.append(", ");
filter.getExpression2().accept(visitor, output);
output.append(")");
return output;
}
public static Object buildBinaryTemporalOperator(final String temporalOperator, BinaryTemporalOperator filter, Object extraData) {
LOGGER.finer("exporting " + temporalOperator);
StringBuilder output = asStringBuilder(extraData);
PropertyName propertyName = (PropertyName) filter.getExpression1();
ExpressionToText visitor = new ExpressionToText();
propertyName.accept(visitor, output);
output.append(" ").append(temporalOperator).append(" ");
Literal expr2 = (Literal) filter.getExpression2();
expr2.accept(visitor, output);
return output;
}
public static Object buildDuring(During during, Object extraData) {
LOGGER.finer("exporting DURING" );
StringBuilder output = asStringBuilder(extraData);
PropertyName propertyName = (PropertyName) during.getExpression1();
ExpressionToText visitor = new ExpressionToText();
propertyName.accept(visitor, output);
output.append(" DURING ");
Literal expr2 = (Literal) during.getExpression2();
Period period = (Period) expr2.getValue();
String strBeginningData = dateToCQLDate( period.getBeginning().getPosition().getDate() );
String strEndingDate = dateToCQLDate( period.getEnding().getPosition().getDate() );
output.append(strBeginningData).append("/").append(strEndingDate);
return output;
}
private static String dateToCQLDate(Date date){
StringBuilder cqlDate = new StringBuilder();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
// builds the string date
int years = cal.get(Calendar.YEAR);
String strYear = String.format("%04d", years);
cqlDate.append(strYear).append("-");
int month = cal.get(Calendar.MONTH)+1;
String strMonth = String.format("%02d", month);
cqlDate.append(strMonth).append("-");
int day = cal.get(Calendar.DAY_OF_MONTH);
String strDay = String.format("%02d", day);
cqlDate.append(strDay);
// builds the string time
cqlDate.append("T");
int hour = cal.get(Calendar.HOUR);
String strHour = String.format("%02d", hour);
cqlDate.append(strHour).append(":");
int minute = cal.get(Calendar.MINUTE);
String strMinute = String.format("%02d", minute);
cqlDate.append(strMinute).append(":");
int second = cal.get(Calendar.SECOND);
String strSecond = String.format("%02d", second);
cqlDate.append(strSecond).append("Z"); // TODO it is a bug in the cql specification. Zulu zone shouldn't be only one of various possibles zone times.
return cqlDate.toString();
}
}