001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) Copyright IBM Corporation, 2005-2007. All rights reserved.
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: */
017: package org.geotools.data.db2;
018:
019: import com.vividsolutions.jts.geom.Envelope;
020: import com.vividsolutions.jts.geom.Geometry;
021:
022: import org.geotools.data.DataSourceException;
023: import org.geotools.data.Query;
024: import org.geotools.data.Transaction;
025: import org.geotools.data.jdbc.JDBCDataStore;
026: import org.geotools.data.jdbc.JDBCFeatureSource;
027: import org.geotools.data.jdbc.SQLBuilder;
028: import org.geotools.factory.CommonFactoryFinder;
029: import org.geotools.feature.AttributeType;
030: import org.geotools.feature.FeatureType;
031: import org.geotools.feature.GeometryAttributeType;
032: import org.geotools.filter.AttributeExpression;
033: import org.geotools.filter.DefaultExpression;
034: import org.geotools.filter.FilterFactory;
035: import org.geotools.filter.FilterFactoryFinder;
036: import org.geotools.filter.GeometryFilter;
037: import org.geotools.filter.SQLEncoderException;
038: import org.geotools.geometry.jts.ReferencedEnvelope;
039: import org.opengis.filter.Filter;
040: import org.opengis.filter.FilterFactory2;
041: import org.opengis.filter.expression.Literal;
042: import org.opengis.filter.expression.PropertyName;
043: import org.opengis.filter.spatial.BBOX;
044: import org.opengis.filter.spatial.BinarySpatialOperator;
045: import org.opengis.filter.spatial.Intersects;
046: import org.opengis.referencing.crs.CoordinateReferenceSystem;
047: import java.io.IOException;
048: import java.sql.Connection;
049: import java.sql.ResultSet;
050: import java.sql.SQLException;
051: import java.sql.Statement;
052: import java.util.logging.Logger;
053:
054: /**
055: * DB2 Feature Source implementation. Overrides functionality in
056: * JDBCFeatureSource to provide more efficient or more appropriate DB2-specific
057: * implementation.
058: *
059: * @author David Adler - IBM Corporation
060: * @source $URL:
061: * @source $URL:
062: * http://svn.geotools.org/geotools/trunk/gt/modules/unsupported/db2/src/main/java/org/geotools/data/db2/DB2FeatureSource.java $
063: */
064: public class DB2FeatureSource extends JDBCFeatureSource {
065:
066: private static final Logger LOGGER = org.geotools.util.logging.Logging
067: .getLogger("org.geotools.data.db2");
068:
069: /**
070: * Constructs a feature source based on a DB2 data store for a specified
071: * feature type.
072: *
073: * @param dataStore
074: * @param featureType
075: */
076: public DB2FeatureSource(DB2DataStore dataStore,
077: FeatureType featureType) {
078: super (dataStore, featureType);
079:
080: }
081:
082: /**
083: * Closes everything associated with a query, the ResultSet, Statement and
084: * Connection.
085: *
086: * @param rs
087: * the ResultSet
088: * @param stmt
089: * the Statement
090: * @param conn
091: * the Connection
092: * @param transaction
093: * the Transaction
094: * @param e
095: * the SQLException, if any, or null
096: */
097: protected void closeAll(ResultSet rs, Statement stmt,
098: Connection conn, Transaction transaction, SQLException e) {
099: close(rs);
100: close(stmt);
101: close(conn, transaction, e);
102: }
103:
104: /**
105: * Gets the bounds of the feature using the specified query.
106: *
107: * @param query
108: * a query object.
109: *
110: * @return the envelope representing the bounds of the features.
111: *
112: * @throws IOException
113: * if there was an encoder problem.
114: * @throws DataSourceException
115: * if there was an error executing the query to get the bounds.
116: */
117: public Envelope getBounds(Query query) throws IOException {
118: Envelope env = new Envelope();
119: CoordinateReferenceSystem crs = null;
120: LOGGER.fine("Query: " + query.toString());
121:
122: if (getSchema() != null) {
123: String typeName = getSchema().getTypeName();
124: GeometryAttributeType geomType = getSchema()
125: .getDefaultGeometry();
126:
127: if (geomType != null) {
128: Filter filter = query.getFilter();
129: Class filterClass = filter.getClass();
130:
131: if (filterClass == Intersects.class
132: || filterClass == BBOX.class) {
133: filter = fixNullGeomFilter(filter);
134: }
135: if (filter != Filter.EXCLUDE) {
136: String sqlStmt = null;
137: try {
138: DB2SQLBuilder builder = (DB2SQLBuilder) ((DB2DataStore) this
139: .getDataStore())
140: .getSqlBuilder(typeName);
141: LOGGER.fine("Filter: " + filter.toString());
142: sqlStmt = builder.buildSQLBoundsQuery(typeName,
143: geomType, filter);
144: } catch (SQLEncoderException e) {
145: throw new IOException("SQLEncoderException: "
146: + e);
147: }
148:
149: Connection conn = null;
150: Transaction transaction = null;
151: Statement statement = null;
152: ResultSet results = null;
153:
154: try {
155: conn = getConnection();
156: transaction = getTransaction();
157: statement = conn.createStatement();
158: results = statement.executeQuery(sqlStmt);
159: if (results.next()) {
160: double minx = results.getDouble(1);
161: double miny = results.getDouble(2);
162: double maxx = results.getDouble(3);
163: double maxy = results.getDouble(4);
164: env = new Envelope(minx, maxx, miny, maxy);
165: } else {
166: env = new Envelope();
167: }
168: } catch (SQLException e) {
169: closeAll(results, statement, conn, transaction,
170: e);
171: System.out.println(e);
172: throw new DataSourceException(
173: "Could not get bounds "
174: + query.getHandle(), e);
175: }
176:
177: closeAll(results, statement, conn, transaction,
178: null);
179: }
180:
181: crs = geomType.getCoordinateSystem();
182: env = new ReferencedEnvelope(env, crs);
183: }
184: }
185:
186: LOGGER.fine("Bounds: " + env.toString());
187:
188: return env;
189: }
190:
191: /*
192: * Sometimes getBounds gets a filter with no geometry column - we substitute
193: * the default geometry column, if one can be found.
194: */
195: private Filter fixNullGeomFilter(Filter inFilter) {
196: BinarySpatialOperator operator = (BinarySpatialOperator) inFilter;
197: Filter filter = (Filter) inFilter;
198: Class filterClass = inFilter.getClass();
199: double xmin = 0, ymin = 0, xmax = 0, ymax = 0;
200: if (operator.getExpression1() == null) {
201: String attName = null;
202: GeometryAttributeType dg = getSchema().getDefaultGeometry();
203: if (dg != null)
204: attName = dg.getName();
205: if (attName != null) {
206: FilterFactory2 ff = (FilterFactory2) CommonFactoryFinder
207: .getFilterFactory(null);
208: if (filterClass == Intersects.class) {
209: Intersects intersects = (Intersects) inFilter;
210: Literal geomLiteral = (Literal) intersects
211: .getExpression2();
212: Geometry geom = (Geometry) geomLiteral.getValue();
213: Envelope envelope = geom.getEnvelopeInternal();
214: xmin = envelope.getMinX();
215: ymin = envelope.getMinY();
216: xmax = envelope.getMaxX();
217: ymax = envelope.getMaxY();
218: PropertyName name = ff.property(attName);
219: filter = ff.intersects(name, geomLiteral);
220: } else if (filterClass == BBOX.class) {
221: BBOX bbox = (BBOX) inFilter;
222: xmin = bbox.getMinX();
223: ymin = bbox.getMinY();
224: xmax = bbox.getMaxX();
225: ymax = bbox.getMaxY();
226: }
227: filter = ff.bbox(attName, xmin, ymin, xmax, ymax, "");
228: }
229: }
230: return filter;
231: }
232: }
|