001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.filter;
017:
018: import java.io.IOException;
019: import java.util.logging.Logger;
020:
021: import com.vividsolutions.jts.geom.Geometry;
022: import com.vividsolutions.jts.io.WKTWriter;
023:
024: /**
025: * Encodes a filter into a SQL WHERE statement for HSQL. This class adds
026: * the ability to turn geometry filters into sql statements if they are
027: * bboxes.
028: * Based on the SQLEncoderMysql
029: *
030: * @author Chris Holmes, TOPP
031: * @author Debasish Sahu, debasish.sahu@rmsi.com
032: * @author Amr Alam
033: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/hsql/src/main/java/org/geotools/filter/SQLEncoderHsql.java $
034: */
035: public class SQLEncoderHsql extends SQLEncoder implements
036: org.geotools.filter.FilterVisitor {
037: /** Standard java logger */
038: private static Logger LOGGER = org.geotools.util.logging.Logging
039: .getLogger("org.geotools.filter");
040:
041: /** To write geometry so postgis can read it. */
042: private static WKTWriter wkt = new WKTWriter();
043:
044: /**
045: * The srid of the schema, so the bbox conforms. Could be better to have
046: * it in the bbox filter itself, but this works for now.
047: */
048: private int srid;
049:
050: /** The geometry attribute to use if none is specified. */
051: private String defaultGeom;
052:
053: /** The standard SQL multicharacter wild card. */
054: private static final String SQL_WILD_MULTI = "%";
055:
056: /** The standard SQL single character wild card. */
057: private static final String SQL_WILD_SINGLE = "_";
058: /** The escaped version of the multiple wildcard for the REGEXP pattern. */
059: private String escapedWildcardMulti = "\\.\\*";
060:
061: /** The escaped version of the single wildcard for the REGEXP pattern. */
062: private String escapedWildcardSingle = "\\.\\?";
063:
064: /**
065: * Empty constructor TODO: rethink empty constructor, as BBOXes _need_ an
066: * SRID, must make client set it somehow. Maybe detect when encode is
067: * called?
068: */
069: public SQLEncoderHsql() {
070: capabilities = createFilterCapabilities();
071: setSqlNameEscape("");
072: }
073:
074: public SQLEncoderHsql(int srid) {
075: this .srid = srid;
076: }
077:
078: /**
079: * @see org.geotools.filter.SQLEncoder#createFilterCapabilities()
080: */
081: protected FilterCapabilities createFilterCapabilities() {
082: FilterCapabilities capabilities = new FilterCapabilities();
083:
084: capabilities.addType(FilterCapabilities.LOGIC_OR);
085: capabilities.addType(FilterCapabilities.LOGIC_AND);
086: capabilities.addType(FilterCapabilities.LOGIC_NOT);
087: capabilities.addType(FilterCapabilities.COMPARE_EQUALS);
088: capabilities.addType(FilterCapabilities.COMPARE_NOT_EQUALS);
089: capabilities.addType(FilterCapabilities.COMPARE_LESS_THAN);
090: capabilities.addType(FilterCapabilities.COMPARE_GREATER_THAN);
091: capabilities
092: .addType(FilterCapabilities.COMPARE_LESS_THAN_EQUAL);
093: capabilities
094: .addType(FilterCapabilities.COMPARE_GREATER_THAN_EQUAL);
095: capabilities.addType(FilterCapabilities.NULL_CHECK);
096: capabilities.addType(FilterCapabilities.BETWEEN);
097: capabilities.addType(FilterCapabilities.NONE);
098: capabilities.addType(FilterCapabilities.ALL);
099: capabilities.addType(FilterCapabilities.SPATIAL_BBOX);
100: capabilities.addType(FilterCapabilities.FID);
101: capabilities.addType(FilterCapabilities.LIKE);
102:
103: return capabilities;
104: }
105:
106: /**
107: * Sets a spatial reference system ESPG number, so that the geometry can be
108: * properly encoded for postgis. If geotools starts actually creating
109: * geometries with valid srids then this method will no longer be needed.
110: *
111: * @param srid the integer code for the EPSG spatial reference system.
112: */
113: public void setSRID(int srid) {
114: this .srid = srid;
115: }
116:
117: /**
118: * Sets the default geometry, so that filters with null for one of their
119: * expressions can assume that the default geometry is intended.
120: *
121: * @param name the name of the default geometry Attribute.
122: *
123: * @task REVISIT: pass in a featureType so that geometries can figure out
124: * their own default geometry?
125: */
126: public void setDefaultGeometry(String name) {
127: //Do we really want clients to be using malformed filters?
128: //I mean, this is a useful method for unit tests, but shouldn't
129: //fully formed filters usually be used? Though I guess adding
130: //the option wouldn't hurt. -ch
131: this .defaultGeom = name;
132: }
133:
134: /**
135: * Turns a geometry filter into the postgis sql bbox statement.
136: *
137: * @param filter the geometry filter to be encoded.
138: *
139: * @throws RuntimeException for IO exception (need a better error)
140: */
141: public void visit(GeometryFilter filter) throws RuntimeException {
142: LOGGER.finer("exporting GeometryFilter");
143: System.out.println("exporting GeometryFilter");
144:
145: if (filter.getFilterType() == AbstractFilter.GEOMETRY_BBOX) {
146: DefaultExpression left = (DefaultExpression) filter
147: .getLeftGeometry();
148: DefaultExpression right = (DefaultExpression) filter
149: .getRightGeometry();
150:
151: // left and right have to be valid expressions
152: try {
153: // out.write("MBRIntersects(");
154: out.write("intersects(");
155: if (left == null) {
156: out.write(defaultGeom);
157: } else {
158: left.accept(this );
159: }
160: out.write(", ");
161: if (right == null) {
162: out.write(defaultGeom);
163: } else {
164: right.accept(this );
165: }
166: out.write(")");
167: } catch (java.io.IOException ioe) {
168: LOGGER.warning("Unable to export filter" + ioe);
169: }
170: } else {
171: LOGGER
172: .warning("exporting unknown filter type, only bbox supported");
173: throw new RuntimeException(
174: "Only BBox is currently supported");
175: }
176: }
177:
178: /**
179: * Checks to see if the literal is a geometry, and encodes it if it is, if
180: * not just sends to the parent class.
181: *
182: * @param expression
183: * the expression to visit and encode.
184: *
185: * @throws IOException
186: * for IO exception (need a better error)
187: */
188: public void visitLiteralGeometry(LiteralExpression expression)
189: throws IOException {
190: Geometry bbox = (Geometry) expression.getLiteral();
191: String geomText = wkt.write(bbox);
192: //out.write("GeometryFromText('" + geomText + "', " + srid + ")");
193: out.write("GeomFromWKT('" + geomText + "')");
194: }
195:
196: public void visit(LikeFilter filter) {
197: try {
198: String pattern = filter.getPattern();
199:
200: pattern = pattern.replaceAll(escapedWildcardMulti,
201: SQL_WILD_MULTI);
202: pattern = pattern.replaceAll(escapedWildcardSingle,
203: SQL_WILD_SINGLE);
204:
205: //pattern = pattern.replace('\\', ''); //get rid of java escapes.
206: out.write("UPPER(");
207: ((Expression) filter.getValue()).accept(this );
208: out.write(") LIKE ");
209: out.write("UPPER('" + pattern + "')");
210:
211: String esc = filter.getEscape();
212:
213: if (pattern.indexOf(esc) != -1) { //if it uses the escape char
214: out.write(" ESCAPE " + "'" + esc + "'"); //this needs testing
215: }
216:
217: //TODO figure out when to add ESCAPE clause, probably just for the
218: // '_' char.
219: } catch (java.io.IOException ioe) {
220: LOGGER.warning("Unable to export filter" + ioe);
221: }
222:
223: }
224: }
|