/*
* Geotools2 - OpenSource mapping toolkit
* http://geotools.org
* (C) 2002, Geotools Project Managment Committee (PMC)
*
* 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;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
/**
* Exports a filter as a OGC XML Filter document. This class is does not
* generate namespace compliant xml, even though it does print gml prefixes.
* It was also written before the 1.0 filter spec, so some of it may be not up
* to date.
*
* @author James Macgill, PSU
* @deprecated Use org.geotools.filter.FilterTransformer
*
* @task HACK: Logging errors, very bad! We need a filter visitor exception,
* or have visit methods throw illegal filter exceptions, or io
* exceptions.
* @task TODO: Support full header information for new XML file
* @task REVISIT: make filter utils class so that other encoders (like sql). It
* could also be nice to refactor common code from gml producer, as
* there is basically a GeometryProducer there.
* @task REVISIT: make namespace aware.
* @source $URL$
*/
public class XMLEncoder implements org.geotools.filter.FilterVisitor {
/** The logger for the filter module. */
private static final Logger LOGGER = Logger.getLogger("org.geotools.filter");
/** Map of comparison types to sql representation */
private static Map comparisions = new HashMap();
/** Map of spatial types to sql representation */
private static Map spatial = new HashMap();
/** Map of logical types to sql representation */
private static Map logical = new HashMap();
/** Map of expression types to sql representation */
private static Map expressions = new HashMap();
static {
comparisions.put(new Integer(AbstractFilter.COMPARE_EQUALS),
"PropertyIsEqualTo");
comparisions.put(new Integer(AbstractFilter.COMPARE_GREATER_THAN),
"PropertyIsGreaterThan");
comparisions.put(new Integer(AbstractFilter.COMPARE_GREATER_THAN_EQUAL),
"PropertyIsGreaterThanOrEqualTo");
comparisions.put(new Integer(AbstractFilter.COMPARE_LESS_THAN),
"PropertyIsLessThan");
comparisions.put(new Integer(AbstractFilter.COMPARE_LESS_THAN_EQUAL),
"PropertyIsLessThanOrEqualTo");
comparisions.put(new Integer(AbstractFilter.LIKE), "PropertyIsLike");
comparisions.put(new Integer(AbstractFilter.NULL), "PropertyIsNull");
comparisions.put(new Integer(AbstractFilter.BETWEEN),
"PropertyIsBetween");
expressions.put(new Integer(DefaultExpression.MATH_ADD), "Add");
expressions.put(new Integer(DefaultExpression.MATH_DIVIDE), "Div");
expressions.put(new Integer(DefaultExpression.MATH_MULTIPLY), "Mul");
expressions.put(new Integer(DefaultExpression.MATH_SUBTRACT), "Sub");
expressions.put(new Integer(DefaultExpression.FUNCTION), "Function");
//more to come
spatial.put(new Integer(AbstractFilter.GEOMETRY_EQUALS), "Equals");
spatial.put(new Integer(AbstractFilter.GEOMETRY_DISJOINT), "Disjoint");
spatial.put(new Integer(AbstractFilter.GEOMETRY_INTERSECTS),
"Intersects");
spatial.put(new Integer(AbstractFilter.GEOMETRY_TOUCHES), "Touches");
spatial.put(new Integer(AbstractFilter.GEOMETRY_CROSSES), "Crosses");
spatial.put(new Integer(AbstractFilter.GEOMETRY_WITHIN), "Within");
spatial.put(new Integer(AbstractFilter.GEOMETRY_CONTAINS), "Contains");
spatial.put(new Integer(AbstractFilter.GEOMETRY_OVERLAPS), "Overlaps");
spatial.put(new Integer(AbstractFilter.GEOMETRY_BEYOND), "Beyond");
spatial.put(new Integer(AbstractFilter.GEOMETRY_BBOX), "BBOX");
logical.put(new Integer(AbstractFilter.LOGIC_AND), "And");
logical.put(new Integer(AbstractFilter.LOGIC_OR), "Or");
logical.put(new Integer(AbstractFilter.LOGIC_NOT), "Not");
}
/** To write the xml representations of filters to */
private Writer out;
/**
* Constructor with writer to write filters to.
*
* @param out where to write the xml representation of filters.
*/
public XMLEncoder(Writer out) {
this.out = out;
}
/**
* Creates a new instance of XMLEncoder
*
* @param out The writer to write to.
* @param filter the filter to encode.
*/
public XMLEncoder(Writer out, Filter filter) {
this.out = out;
try {
encode(filter);
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
/**
* Encodes the filter to the current writer.
*
* @param filter the filter to encode.
*
* @throws java.io.IOException if there are problems writing to out.
*/
public void encode(Filter filter) throws java.io.IOException {
out.write("\n");
filter.accept(this);
out.write("\n");
}
/**
* Encodes the expression to the current writer.
*
* @param expression the expression to encode.
*/
public void encode(Expression expression) {
expression.accept(this);
}
/**
* This should never be called. This can only happen if a subclass of
* AbstractFilter failes to implement its own version of
* accept(FilterVisitor);
*
* @param filter The filter to visit
*/
public void visit(Filter filter) {
LOGGER.warning("exporting unknown filter type:"+filter.toString());
}
/**
* Writes the xml representation of a Between filter.
*
* @param filter the between filter to encode.
*/
public void visit(BetweenFilter filter) {
LOGGER.finer("exporting BetweenFilter");
Expression left = (Expression) filter.getLeftValue();
Expression right = (Expression) filter.getRightValue();
Expression mid = (Expression) filter.getMiddleValue();
LOGGER.finer("Filter type id is " + filter.getFilterType());
LOGGER.finer("Filter type text is "
+ comparisions.get(new Integer(filter.getFilterType())));
String type = (String) comparisions.get(new Integer(
filter.getFilterType()));
try {
out.write("<" + type + ">\n");
mid.accept(this);
out.write("\n");
left.accept(this);
out.write("\n\n");
right.accept(this);
out.write("\n");
out.write("" + type + ">\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
/**
* Writes the xml representation of a like filter.
*
* @param filter the like filter to encode.
*/
public void visit(LikeFilter filter) {
LOGGER.finer("exporting like filter");
try {
String wcm = filter.getWildcardMulti();
String wcs = filter.getWildcardSingle();
String esc = filter.getEscape();
out.write("\n");
((Expression) filter.getValue()).accept(this);
out.write("" + filter.getPattern() + "\n");
out.write("\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
/**
* Writes the xml representation of a logic filter.
*
* @param filter the logic filter to encode.
*/
public void visit(LogicFilter filter) {
LOGGER.finer("exporting LogicFilter");
filter.getFilterType();
String type = (String) logical.get(new Integer(filter.getFilterType()));
try {
out.write("<" + type + ">\n");
java.util.Iterator list = filter.getFilterIterator();
while (list.hasNext()) {
((AbstractFilter) list.next()).accept(this);
}
out.write("" + type + ">\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
/**
* Writes the xml representation of a compare filter.
*
* @param filter the compare filter to encode.
*/
public void visit(CompareFilter filter) {
LOGGER.finer("exporting ComparisonFilter");
Expression left = filter.getLeftValue();
Expression right = filter.getRightValue();
LOGGER.finer("Filter type id is " + filter.getFilterType());
LOGGER.finer("Filter type text is "
+ comparisions.get(new Integer(filter.getFilterType())));
String type = (String) comparisions.get(new Integer(
filter.getFilterType()));
try {
out.write("<" + type + ">\n");
LOGGER.fine("exporting left expression " + left);
left.accept(this);
LOGGER.fine("exporting right expression " + right);
right.accept(this);
out.write("" + type + ">\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
/**
* Writes the xml representation of a geometry filter.
*
* @param filter the geometry filter to encode.
*/
public void visit(GeometryFilter filter) {
LOGGER.finer("exporting GeometryFilter");
Expression left = filter.getLeftGeometry();
Expression right = filter.getRightGeometry();
String type = (String) spatial.get(new Integer(filter.getFilterType()));
try {
out.write("<" + type + ">\n");
left.accept(this);
right.accept(this);
out.write("" + type + ">\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
/**
* Writes the xml representation of a null filter.
*
* @param filter the null filter to encode.
*/
public void visit(NullFilter filter) {
LOGGER.finer("exporting NullFilter");
Expression expr = (Expression) filter.getNullCheckValue();
String type = (String) comparisions.get(new Integer(
filter.getFilterType()));
try {
out.write("<" + type + ">\n");
expr.accept(this);
out.write("" + type + ">\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
/**
* Writes the xml representation of a fid filter.
*
* @param filter the fid filter to encode.
*/
public void visit(FidFilter filter) {
LOGGER.finer("exporting FidFilter");
String[] fids = filter.getFids();
for (int i = 0; i < fids.length; i++) {
try {
out.write("");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export filter" + ioe);
}
}
}
/**
* Writes the xml representation of an Attribute expression.
*
* @param expression the attribute expression to encode.
*/
public void visit(AttributeExpression expression) {
LOGGER.finer("exporting ExpressionAttribute");
try {
out.write("" + expression.getAttributePath()
+ "\n");
} catch (java.io.IOException ioe) {
LOGGER.finer("Unable to export expresion: " + ioe);
}
}
/**
* This should never be called. This can only happen if a subclass of
* DefaultExpression fails to implement its own version of
* accept(FilterVisitor);
*
* @param expression the expression to encode.
*/
public void visit(Expression expression) {
LOGGER.warning("exporting unknown (default) expression");
}
/**
* Export the contents of a Literal Expresion
*
* @param expression the Literal to export
*
* @task TODO: Fully support GeometryExpressions so that they are writen as
* GML.
*/
public void visit(LiteralExpression expression) {
LOGGER.finer("exporting LiteralExpression");
try {
Object value = expression.getLiteral();
if (Geometry.class.isAssignableFrom(value.getClass())) {
GeometryEncoder encoder = new GeometryEncoder(out);
encoder.encode((Geometry) value);
} else {
out.write("" + value + "\n");
}
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export expresion" + ioe);
}
}
/**
* Writes the xml representation of a expression.
*
* @param expression the expression to encode.
*/
public void visit(MathExpression expression) {
LOGGER.finer("exporting Expression Math");
String type = (String) expressions.get(new Integer(expression.getType()));
try {
out.write("<" + type + ">\n");
((Expression) expression.getLeftValue()).accept(this);
((Expression) expression.getRightValue()).accept(this);
out.write("" + type + ">\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export expresion: " + ioe);
}
}
/**
* Writes the xml representation of a expression.
*
* @param expression the expression to encode.
*/
public void visit(FunctionExpression expression) {
LOGGER.finer("exporting Expression Math");
String type = (String) expressions.get(new Integer(expression.getType()));
try {
out.write("<" + type + " name = " + expression.getName() + ">\n");
Expression[] args = expression.getArgs();
for (int i = 0; i < args.length; i++) {
args[i].accept(this);
}
out.write("" + type + ">\n");
} catch (java.io.IOException ioe) {
LOGGER.warning("Unable to export expresion: " + ioe);
}
}
/**
* Encodes geometries for filters.
*
* @task REVISIT: combine with gml producer code if possible (may not be,
* but it should be investigated).
*/
static class GeometryEncoder {
/** HACK!?! The srs isn't always 4326, is it? */
private String srs = "epsg:4326";
/** The writer where the gml should print to. */
private PrintWriter out;
/**
* Constructor with writer to write to.
*
* @param out where to write the geometry.
*/
public GeometryEncoder(Writer out) {
this.out = new PrintWriter(out);
}
/**
* Constructor with writer to write to and srs.
*
* @param srs The spatial reference system id of the geometry.
* @param out where to write the geometry.
*/
public GeometryEncoder(String srs, Writer out) {
this.out = new PrintWriter(out);
this.srs = srs;
}
/**
* Encodes the geometry, delegating to the appropriate sub method.
*
* @param geom the geometry to encode.
*/
public void encode(Geometry geom) {
Class geomType = geom.getClass();
if (Point.class.isAssignableFrom(geomType)) {
encode((Point) geom);
} else if (LineString.class.isAssignableFrom(geomType)) {
encode((LineString) geom);
} else if (Polygon.class.isAssignableFrom(geomType)) {
encode((Polygon) geom);
} else if (MultiPoint.class.isAssignableFrom(geomType)) {
encode((MultiPoint) geom);
} else if (MultiLineString.class.isAssignableFrom(geomType)) {
encode((MultiLineString) geom);
} else if (MultiPolygon.class.isAssignableFrom(geomType)) {
encode((MultiPolygon) geom);
} else if (GeometryCollection.class.isAssignableFrom(geomType)) {
encode((GeometryCollection) geom);
}
}
/**
* Encodes the coordinates to gml
*
* @param coords the coordinates to encode.
*/
public void encode(Coordinate[] coords) {
out.print("");
for (int i = 0; i < coords.length; i++) {
out.print(coords[i].x + "," + coords[i].y);
out.print((i < (coords.length - 1)) ? " " : "");
}
out.println("");
}
/**
* Encodes the point to gml
*
* @param point the point to encode.
*/
public void encode(Point point) {
out.println("");
encode(point.getCoordinates());
out.println("");
}
/**
* Encodes the LineString to gml
*
* @param line the LineString to encode.
*/
public void encode(LineString line) {
out.println("");
encode(line.getCoordinates());
out.println("");
}
/**
* Encodes the Polygon to gml
*
* @param polygon the Polygon to encode.
*/
public void encode(Polygon polygon) {
out.println("");
out.println("");
encode(polygon.getExteriorRing());
out.println("");
for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
out.println("");
encode(polygon.getInteriorRingN(i));
out.println("");
}
out.println("");
}
/**
* Encodes the MultiPoint to gml
*
* @param mpoint the MultiPoint to encode.
*/
public void encode(MultiPoint mpoint) {
out.println("\n");
for (int i = 0; i < mpoint.getNumGeometries(); i++) {
encode((Point) mpoint.getGeometryN(i));
}
out.println("\n");
}
/**
* Encodes the MultiLineString to gml
*
* @param mline the MultiLineString to encode.
*/
public void encode(MultiLineString mline) {
out.println("\n");
for (int i = 0; i < mline.getNumGeometries(); i++) {
encode((LineString) mline.getGeometryN(i));
}
out.println("\n");
}
/**
* Encodes the MultiPolygon to gml
*
* @param mpolygon the MultiPolygon to encode.
*/
public void encode(MultiPolygon mpolygon) {
out.println("\n");
for (int i = 0; i < mpolygon.getNumGeometries(); i++) {
encode((Polygon) mpolygon.getGeometryN(i));
}
out.println("\n");
}
/**
* Encodes the Geometry Collection to gml
*
* @param geomcoll the collection to encode
*/
public void encode(GeometryCollection geomcoll) {
out.println("\n");
for (int i = 0; i < geomcoll.getNumGeometries(); i++) {
encode(geomcoll.getGeometryN(i));
}
out.println("\n");
}
}
}