001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/io/datastore/sql/generic/GenericSQLDatastore.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstraße 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042: ---------------------------------------------------------------------------*/
043: package org.deegree.io.datastore.sql.generic;
044:
045: import java.io.BufferedReader;
046: import java.io.InputStream;
047: import java.io.InputStreamReader;
048: import java.io.Reader;
049: import java.io.StringReader;
050: import java.sql.Connection;
051: import java.sql.SQLException;
052:
053: import org.deegree.framework.log.ILogger;
054: import org.deegree.framework.log.LoggerFactory;
055: import org.deegree.framework.util.StringTools;
056: import org.deegree.i18n.Messages;
057: import org.deegree.io.JDBCConnection;
058: import org.deegree.io.datastore.Datastore;
059: import org.deegree.io.datastore.DatastoreException;
060: import org.deegree.io.datastore.schema.MappedFeatureType;
061: import org.deegree.io.datastore.sql.AbstractSQLDatastore;
062: import org.deegree.io.datastore.sql.QueryHandler;
063: import org.deegree.io.datastore.sql.SQLDatastoreConfiguration;
064: import org.deegree.io.datastore.sql.TableAliasGenerator;
065: import org.deegree.io.datastore.sql.VirtualContentProvider;
066: import org.deegree.io.datastore.sql.wherebuilder.WhereBuilder;
067: import org.deegree.model.crs.CRSFactory;
068: import org.deegree.model.crs.CoordinateSystem;
069: import org.deegree.model.feature.Feature;
070: import org.deegree.model.feature.FeatureCollection;
071: import org.deegree.model.filterencoding.Filter;
072: import org.deegree.model.filterencoding.FilterEvaluationException;
073: import org.deegree.model.spatialschema.GMLGeometryAdapter;
074: import org.deegree.model.spatialschema.Geometry;
075: import org.deegree.model.spatialschema.GeometryException;
076: import org.deegree.model.spatialschema.GeometryImpl;
077: import org.deegree.ogcbase.SortProperty;
078: import org.deegree.ogcwebservices.wfs.operation.Query;
079:
080: /**
081: * {@link Datastore} implementation for any SQL database that can be accessed through a jdbc
082: * connection (even the odbc-jdbc bridge is supported) and that supports the storing of BLOBs.
083: * <p>
084: * The spatial information is assumed to be stored in a BLOB field as a serialized deegree geometry.
085: * It also will be assumed that a spatial index exists and that it has been created using deegree's
086: * quadtree api.
087: *
088: * @see org.deegree.io.quadtree
089: *
090: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
091: * @author last edited by: $Author: apoth $
092: *
093: * @version $Revision: 9342 $, $Date: 2007-12-27 04:32:57 -0800 (Thu, 27 Dec 2007) $
094: */
095: public class GenericSQLDatastore extends AbstractSQLDatastore {
096:
097: protected static final ILogger LOG = LoggerFactory
098: .getLogger(GenericSQLDatastore.class);
099:
100: @Override
101: public WhereBuilder getWhereBuilder(MappedFeatureType[] rootFts,
102: String[] aliases, Filter filter,
103: SortProperty[] sortProperties,
104: TableAliasGenerator aliasGenerator,
105: VirtualContentProvider vcProvider)
106: throws DatastoreException {
107: JDBCConnection jdbc = ((SQLDatastoreConfiguration) getConfiguration())
108: .getJDBCConnection();
109: return new GenericSQLWhereBuilder(rootFts, aliases, filter,
110: sortProperties, aliasGenerator, vcProvider, jdbc);
111: }
112:
113: @Override
114: protected FeatureCollection performQuery(Query query,
115: MappedFeatureType[] rootFts, Connection conn)
116: throws DatastoreException {
117:
118: query = transformQuery(query);
119:
120: FeatureCollection result = null;
121: try {
122: QueryHandler queryHandler = new QueryHandler(this ,
123: new TableAliasGenerator(), conn, rootFts, query);
124: result = queryHandler.performQuery();
125: } catch (SQLException e) {
126: String msg = "SQL error while performing query: "
127: + e.getMessage();
128: LOG.logError(msg, e);
129: throw new DatastoreException(msg, e);
130: } catch (Exception e) {
131: LOG.logError(e.getMessage(), e);
132: throw new DatastoreException(e);
133: }
134:
135: if (query.getFilter() != null) {
136: try {
137: LOG.logDebug("Features (before refinement): "
138: + result.size());
139: result = filterCollection(result, query.getFilter());
140: LOG.logDebug("Features (after refinement): "
141: + result.size());
142: } catch (Exception e) {
143: LOG.logError(e.getMessage(), e);
144: throw new DatastoreException(e.getMessage(), e);
145: }
146: }
147:
148: result = transformResult(result, query.getSrsName());
149: return result;
150: }
151:
152: /**
153: * Filters the feature collection using the given filter.
154: * <p>
155: * This is required because spatial filtering performed in the {@link GenericSQLWhereBuilder}
156: * just considers the BBOX and non-spatial filter conditions.
157: *
158: * TODO remove BBOX + non-spatial conditions from the filter to speed up evaluation
159: *
160: * @param fc
161: * @param filter
162: * @return filtered feature collection
163: */
164: private FeatureCollection filterCollection(FeatureCollection fc,
165: Filter filter) throws FilterEvaluationException {
166: for (int i = fc.size() - 1; i >= 0; i--) {
167: Feature feat = fc.getFeature(i);
168: if (!filter.evaluate(feat)) {
169: fc.remove(i);
170: }
171: }
172: return fc;
173: }
174:
175: @Override
176: public Geometry convertDBToDeegreeGeometry(Object value,
177: CoordinateSystem targetCS, Connection conn)
178: throws SQLException {
179:
180: Geometry geometry = null;
181: if (value != null) {
182: try {
183: if (targetCS == null) {
184: targetCS = CRSFactory.create("EPSG:4326");
185: }
186: if (value instanceof String) {
187: geometry = GMLGeometryAdapter.wrap((String) value,
188: null);
189: } else if (value instanceof InputStream) {
190: StringBuffer sb = new StringBuffer(10000);
191: BufferedReader br = new BufferedReader(
192: new InputStreamReader((InputStream) value));
193: String line = null;
194: while ((line = br.readLine()) != null) {
195: sb.append(line);
196: }
197: geometry = GMLGeometryAdapter.wrap(sb.toString(),
198: null);
199: } else if (value instanceof Reader) {
200: StringBuffer sb = new StringBuffer(10000);
201: BufferedReader br = new BufferedReader(
202: (Reader) value);
203: String line = null;
204: while ((line = br.readLine()) != null) {
205: sb.append(line);
206: }
207: geometry = GMLGeometryAdapter.wrap(sb.toString(),
208: null);
209: } else {
210: geometry = GMLGeometryAdapter.wrap(new String(
211: (byte[]) value), null);
212: }
213: ((GeometryImpl) geometry).setCoordinateSystem(targetCS);
214: } catch (Exception e) {
215: String msg = Messages
216: .getMessage("DATASTORE_GENERICSQL_GEOM_READ_ERROR");
217: LOG.logError(msg, e);
218: throw new SQLException(msg + e.getMessage());
219: }
220: }
221: return geometry;
222: }
223:
224: @Override
225: public Object convertDeegreeToDBGeometry(Geometry geometry,
226: int nativeSRSCode, Connection conn)
227: throws DatastoreException {
228: String sqlObject = null;
229: try {
230: sqlObject = GMLGeometryAdapter.export(geometry).toString();
231: sqlObject = StringTools
232: .replace(
233: sqlObject,
234: ">",
235: " xmlns:gml=\"http://www.opengis.net/gml\">",
236: false);
237: } catch (GeometryException e) {
238: LOG.logError(e.getMessage(), e);
239: throw new DatastoreException(e.getMessage(), e);
240: }
241: JDBCConnection jdbc = ((SQLDatastoreConfiguration) getConfiguration())
242: .getJDBCConnection();
243: Object result = null;
244: // concrete from depends on backend. At the moment special mapping just is defined
245: // for HSQLDB, Postgres und INGRES. Default will work for MS SQLSERVER
246: if (jdbc.getDriver().toLowerCase().indexOf("ingres") > -1
247: || jdbc.getDriver().equalsIgnoreCase(
248: "ca.edbc.jdbc.EdbcDriver")) {
249: result = new StringReader(sqlObject);
250: } else if (jdbc.getDriver().toLowerCase().indexOf("hsqldb") > -1
251: || jdbc.getDriver().toLowerCase().indexOf("postgres") > -1) {
252: // only postgres is able to handle large strings as they are
253: result = sqlObject;
254: } else {
255: result = sqlObject.getBytes();
256: }
257: return result;
258: }
259:
260: @Override
261: protected GenericSQLTransaction createTransaction()
262: throws DatastoreException {
263:
264: return new GenericSQLTransaction(this ,
265: new TableAliasGenerator(), acquireConnection());
266: }
267: }
|