001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/datastore/sql/oracle/OracleSpatialWhereBuilder.java $
002 /*---------------- FILE HEADER ------------------------------------------
003 This file is part of deegree.
004 Copyright (C) 2001-2006 by:
005 Department of Geography, University of Bonn
006 http://www.giub.uni-bonn.de/deegree/
007 lat/lon GmbH
008 http://www.lat-lon.de
009
010 This library is free software; you can redistribute it and/or
011 modify it under the terms of the GNU Lesser General Public
012 License as published by the Free Software Foundation; either
013 version 2.1 of the License, or (at your option) any later version.
014
015 This library is distributed in the hope that it will be useful,
016 but WITHOUT ANY WARRANTY; without even the implied warranty of
017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018 Lesser General Public License for more details.
019
020 You should have received a copy of the GNU Lesser General Public
021 License along with this library; if not, write to the Free Software
022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
023
024 Contact:
025
026 Andreas Poth
027 lat/lon GmbH
028 Aennchenstraße 19
029 53177 Bonn
030 Germany
031 E-Mail: poth@lat-lon.de
032
033 Jens Fitzke
034 lat/lon GmbH
035 Aennchenstraße 19
036 53177 Bonn
037 Germany
038 E-Mail: jens.fitzke@uni-bonn.de
039 ---------------------------------------------------------------------------*/
040 package org.deegree.io.datastore.sql.oracle;
041
042 import java.sql.Types;
043
044 import oracle.spatial.geometry.JGeometry;
045
046 import org.deegree.i18n.Messages;
047 import org.deegree.io.datastore.DatastoreException;
048 import org.deegree.io.datastore.schema.MappedFeatureType;
049 import org.deegree.io.datastore.schema.MappedGeometryPropertyType;
050 import org.deegree.io.datastore.sql.StatementBuffer;
051 import org.deegree.io.datastore.sql.TableAliasGenerator;
052 import org.deegree.io.datastore.sql.VirtualContentProvider;
053 import org.deegree.io.datastore.sql.wherebuilder.WhereBuilder;
054 import org.deegree.model.filterencoding.Filter;
055 import org.deegree.model.filterencoding.OperationDefines;
056 import org.deegree.model.filterencoding.SpatialOperation;
057 import org.deegree.model.spatialschema.Geometry;
058 import org.deegree.model.spatialschema.GeometryException;
059 import org.deegree.ogcbase.SortProperty;
060
061 /**
062 * {@link WhereBuilder} implementation for Oracle Spatial. Supports Oracle Spatial for Oracle
063 * Database 10g.
064 *
065 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </A>
066 * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </A>
067 * @author last edited by: $Author: mschneider $
068 *
069 * @version $Revision: 6633 $, $Date: 2007-04-18 16:32:16 +0200 (Mi, 18 Apr 2007) $
070 */
071 public class OracleSpatialWhereBuilder extends WhereBuilder {
072
073 private static final int SRS_UNDEFINED = -1;
074
075 private OracleDatastore ds;
076
077 /**
078 * Creates a new instance of <code>OracleSpatialWhereBuilder</code> from the given parameters.
079 *
080 * @param rootFts
081 * selected feature types, more than one type means that the types are joined
082 * @param aliases
083 * aliases for the feature types, may be null (must have same length as rootFts
084 * otherwise)
085 * @param filter
086 * filter that restricts the matched features
087 * @param sortProperties
088 * sort criteria for the result, may be null or empty
089 * @param aliasGenerator
090 * used to generate unique table aliases
091 * @param vcProvider
092 * @throws DatastoreException
093 */
094 public OracleSpatialWhereBuilder( MappedFeatureType[] rootFts, String[] aliases, Filter filter,
095 SortProperty[] sortProperties, TableAliasGenerator aliasGenerator,
096 VirtualContentProvider vcProvider ) throws DatastoreException {
097 super( rootFts, aliases, filter, sortProperties, aliasGenerator, vcProvider );
098 this.ds = (OracleDatastore) rootFts[0].getGMLSchema().getDatastore();
099 }
100
101 /**
102 * Generates an SQL-fragment for the given object.
103 *
104 * @throws DatastoreException
105 */
106 @Override
107 protected void appendSpatialOperationAsSQL( StatementBuffer query, SpatialOperation operation )
108 throws DatastoreException {
109
110 try {
111 switch ( operation.getOperatorId() ) {
112 case OperationDefines.BBOX:
113 case OperationDefines.INTERSECTS: {
114 appendRelateOperationAsSQL( query, operation, "ANYINTERACT" );
115 break;
116 }
117 case OperationDefines.EQUALS: {
118 appendRelateOperationAsSQL( query, operation, "EQUAL" );
119 break;
120 }
121 case OperationDefines.DISJOINT: {
122 query.append( "NOT " );
123 appendRelateOperationAsSQL( query, operation, "ANYINTERACT" );
124 break;
125 }
126 case OperationDefines.TOUCHES: {
127 appendRelateOperationAsSQL( query, operation, "TOUCH" );
128 break;
129 }
130 case OperationDefines.WITHIN: {
131 appendRelateOperationAsSQL( query, operation, "INSIDE+COVEREDBY" );
132 break;
133 }
134 case OperationDefines.OVERLAPS: {
135 appendRelateOperationAsSQL( query, operation, "OVERLAPBDYINTERSECT" );
136 break;
137 }
138 case OperationDefines.CROSSES: {
139 appendRelateOperationAsSQL( query, operation, "OVERLAPBDYDISJOINT" );
140 break;
141 }
142 case OperationDefines.CONTAINS: {
143 appendRelateOperationAsSQL( query, operation, "CONTAINS+COVERS" );
144 break;
145 }
146 case OperationDefines.DWITHIN: {
147 appendDWithinOperationAsSQL( query, operation );
148 break;
149 }
150 case OperationDefines.BEYOND: {
151 query.append( "NOT " );
152 appendDWithinOperationAsSQL( query, operation );
153 break;
154 }
155 default: {
156 String msg = "Spatial operator" + OperationDefines.getNameById( operation.getOperatorId() )
157 + " not supported by '" + this.getClass().toString() + "'.";
158 throw new DatastoreException( msg );
159 }
160 }
161 } catch ( GeometryException e ) {
162 throw new DatastoreException( e );
163 }
164
165 }
166
167 private void appendRelateOperationAsSQL( StatementBuffer query, SpatialOperation operation, String mask )
168 throws GeometryException, DatastoreException {
169 query.append( "MDSYS.SDO_RELATE(" );
170 appendPropertyNameAsSQL( query, operation.getPropertyName() );
171 query.append( ',' );
172 appendGeometryArgument( query, getGeometryProperty( operation.getPropertyName() ), operation.getGeometry() );
173 query.append( ",'MASK=" + mask + " QUERYTYPE=WINDOW')='TRUE'" );
174 }
175
176 private void appendDWithinOperationAsSQL( StatementBuffer query, SpatialOperation operation )
177 throws GeometryException, DatastoreException {
178
179 query.append( "SDO_WITHIN_DISTANCE(" );
180 appendPropertyNameAsSQL( query, operation.getPropertyName() );
181 query.append( ',' );
182 appendGeometryArgument( query, getGeometryProperty( operation.getPropertyName() ), operation.getGeometry() );
183 query.append( ",'DISTANCE=" + operation.getDistance() + "')='TRUE'" );
184 }
185
186 /**
187 * Construct and append the geometry argument using the correct internal SRS and perform a
188 * transform call to the internal SRS of the {@link MappedGeometryPropertyType} if necessary.
189 *
190 * @param query
191 * @param geoProperty
192 * @param geometry
193 * @throws DatastoreException
194 * @throws GeometryException
195 */
196 private void appendGeometryArgument( StatementBuffer query, MappedGeometryPropertyType geoProperty,
197 Geometry geometry )
198 throws DatastoreException, GeometryException {
199
200 String argumentSRS = null;
201 if ( geometry.getCoordinateSystem() != null ) {
202 argumentSRS = geometry.getCoordinateSystem().getName();
203 }
204 String propertySRS = geoProperty.getCS().getName();
205 int internalSRS = geoProperty.getMappingField().getSRS();
206
207 int createSRSCode = getArgumentSRSCode( argumentSRS, propertySRS, internalSRS );
208 JGeometry argument = JGeometryAdapter.export( geometry, createSRSCode );
209
210 int targetSRSCode = getTargetSRSCode( argumentSRS, propertySRS, internalSRS );
211 if ( targetSRSCode != SRS_UNDEFINED ) {
212 query.append( ds.buildSRSTransformCall( "?", targetSRSCode ) );
213 } else {
214 query.append( '?' );
215 }
216 query.addArgument( argument, Types.STRUCT );
217 }
218
219 /**
220 * Returns the internal SRS code that must be used for the creation of a geometry argument used
221 * in a spatial operator.
222 *
223 * @param literalSRS
224 * @param propertySRS
225 * @param internalSrs
226 * @return the internal SRS code that must be used for the creation of a geometry argument
227 * @throws DatastoreException
228 */
229 private int getArgumentSRSCode( String argumentSRS, String propertySRS, int internalSrs )
230 throws DatastoreException {
231 int argumentSRSCode = internalSrs;
232 if ( argumentSRS == null ) {
233 argumentSRSCode = internalSrs;
234 } else if ( !propertySRS.equals( argumentSRS ) ) {
235 argumentSRSCode = this.ds.getNativeSRSCode( argumentSRS );
236 if ( argumentSRSCode == SRS_UNDEFINED ) {
237 String msg = Messages.getMessage( "DATASTORE_SQL_NATIVE_CT_UNKNOWN_SRS",
238 OracleDatastore.class.getName(), argumentSRS );
239 throw new DatastoreException( msg );
240 }
241 }
242 return argumentSRSCode;
243 }
244
245 /**
246 * Returns the internal SRS code that must be used for the transform call for a geometry
247 * argument used in a spatial operator.
248 *
249 * @param literalSRS
250 * @param propertySRS
251 * @param internalSrs
252 * @return the internal SRS code that must be used for the transform call of a geometry
253 * argument, or -1 if no transformation is necessary
254 */
255 private int getTargetSRSCode( String argumentSRS, String propertySRS, int internalSrs )
256 throws DatastoreException {
257 int targetSRS = SRS_UNDEFINED;
258 if ( argumentSRS != null && !argumentSRS.equals( propertySRS ) ) {
259 if ( internalSrs == SRS_UNDEFINED ) {
260 String msg = Messages.getMessage( "DATASTORE_SRS_NOT_SPECIFIED2", argumentSRS, propertySRS );
261 throw new DatastoreException( msg );
262 }
263 targetSRS = internalSrs;
264 }
265 return targetSRS;
266 }
267 }