001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/datastore/sql/oracle/OracleSpatialWhereBuilder.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 Aennchenstr. 19
030 53115 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 ---------------------------------------------------------------------------*/
044 package org.deegree.io.datastore.sql.oracle;
045
046 import java.sql.Types;
047
048 import oracle.spatial.geometry.JGeometry;
049
050 import org.deegree.i18n.Messages;
051 import org.deegree.io.datastore.DatastoreException;
052 import org.deegree.io.datastore.schema.MappedFeatureType;
053 import org.deegree.io.datastore.schema.MappedGeometryPropertyType;
054 import org.deegree.io.datastore.sql.StatementBuffer;
055 import org.deegree.io.datastore.sql.TableAliasGenerator;
056 import org.deegree.io.datastore.sql.VirtualContentProvider;
057 import org.deegree.io.datastore.sql.wherebuilder.WhereBuilder;
058 import org.deegree.model.filterencoding.Filter;
059 import org.deegree.model.filterencoding.OperationDefines;
060 import org.deegree.model.filterencoding.SpatialOperation;
061 import org.deegree.model.spatialschema.Geometry;
062 import org.deegree.model.spatialschema.GeometryException;
063 import org.deegree.ogcbase.SortProperty;
064
065 /**
066 * {@link WhereBuilder} implementation for Oracle Spatial. Supports Oracle Spatial for Oracle
067 * Database 10g.
068 *
069 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </A>
070 * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </A>
071 * @author last edited by: $Author: apoth $
072 *
073 * @version $Revision: 9342 $, $Date: 2007-12-27 13:32:57 +0100 (Do, 27 Dez 2007) $
074 */
075 public class OracleSpatialWhereBuilder extends WhereBuilder {
076
077 private static final int SRS_UNDEFINED = -1;
078
079 private OracleDatastore ds;
080
081 /**
082 * Creates a new instance of <code>OracleSpatialWhereBuilder</code> from the given parameters.
083 *
084 * @param rootFts
085 * selected feature types, more than one type means that the types are joined
086 * @param aliases
087 * aliases for the feature types, may be null (must have same length as rootFts
088 * otherwise)
089 * @param filter
090 * filter that restricts the matched features
091 * @param sortProperties
092 * sort criteria for the result, may be null or empty
093 * @param aliasGenerator
094 * used to generate unique table aliases
095 * @param vcProvider
096 * @throws DatastoreException
097 */
098 public OracleSpatialWhereBuilder( MappedFeatureType[] rootFts, String[] aliases, Filter filter,
099 SortProperty[] sortProperties, TableAliasGenerator aliasGenerator,
100 VirtualContentProvider vcProvider ) throws DatastoreException {
101 super( rootFts, aliases, filter, sortProperties, aliasGenerator, vcProvider );
102 this.ds = (OracleDatastore) rootFts[0].getGMLSchema().getDatastore();
103 }
104
105 /**
106 * Generates an SQL-fragment for the given object.
107 *
108 * @throws DatastoreException
109 */
110 @Override
111 protected void appendSpatialOperationAsSQL( StatementBuffer query, SpatialOperation operation )
112 throws DatastoreException {
113
114 try {
115 switch ( operation.getOperatorId() ) {
116 case OperationDefines.BBOX:
117 case OperationDefines.INTERSECTS: {
118 appendRelateOperationAsSQL( query, operation, "ANYINTERACT" );
119 break;
120 }
121 case OperationDefines.EQUALS: {
122 appendRelateOperationAsSQL( query, operation, "EQUAL" );
123 break;
124 }
125 case OperationDefines.DISJOINT: {
126 query.append( "NOT " );
127 appendRelateOperationAsSQL( query, operation, "ANYINTERACT" );
128 break;
129 }
130 case OperationDefines.TOUCHES: {
131 appendRelateOperationAsSQL( query, operation, "TOUCH" );
132 break;
133 }
134 case OperationDefines.WITHIN: {
135 appendRelateOperationAsSQL( query, operation, "INSIDE+COVEREDBY" );
136 break;
137 }
138 case OperationDefines.OVERLAPS: {
139 appendRelateOperationAsSQL( query, operation, "OVERLAPBDYINTERSECT" );
140 break;
141 }
142 case OperationDefines.CROSSES: {
143 appendRelateOperationAsSQL( query, operation, "OVERLAPBDYDISJOINT" );
144 break;
145 }
146 case OperationDefines.CONTAINS: {
147 appendRelateOperationAsSQL( query, operation, "CONTAINS+COVERS" );
148 break;
149 }
150 case OperationDefines.DWITHIN: {
151 appendDWithinOperationAsSQL( query, operation );
152 break;
153 }
154 case OperationDefines.BEYOND: {
155 query.append( "NOT " );
156 appendDWithinOperationAsSQL( query, operation );
157 break;
158 }
159 default: {
160 String msg = "Spatial operator" + OperationDefines.getNameById( operation.getOperatorId() )
161 + " not supported by '" + this.getClass().toString() + "'.";
162 throw new DatastoreException( msg );
163 }
164 }
165 } catch ( GeometryException e ) {
166 throw new DatastoreException( e );
167 }
168
169 }
170
171 private void appendRelateOperationAsSQL( StatementBuffer query, SpatialOperation operation, String mask )
172 throws GeometryException, DatastoreException {
173 query.append( "MDSYS.SDO_RELATE(" );
174 appendPropertyNameAsSQL( query, operation.getPropertyName() );
175 query.append( ',' );
176 appendGeometryArgument( query, getGeometryProperty( operation.getPropertyName() ), operation.getGeometry() );
177 query.append( ",'MASK=" + mask + " QUERYTYPE=WINDOW')='TRUE'" );
178 }
179
180 private void appendDWithinOperationAsSQL( StatementBuffer query, SpatialOperation operation )
181 throws GeometryException, DatastoreException {
182
183 query.append( "SDO_WITHIN_DISTANCE(" );
184 appendPropertyNameAsSQL( query, operation.getPropertyName() );
185 query.append( ',' );
186 appendGeometryArgument( query, getGeometryProperty( operation.getPropertyName() ), operation.getGeometry() );
187 query.append( ",'DISTANCE=" + operation.getDistance() + "')='TRUE'" );
188 }
189
190 /**
191 * Construct and append the geometry argument using the correct internal SRS and perform a
192 * transform call to the internal SRS of the {@link MappedGeometryPropertyType} if necessary.
193 *
194 * @param query
195 * @param geoProperty
196 * @param geometry
197 * @throws DatastoreException
198 * @throws GeometryException
199 */
200 private void appendGeometryArgument( StatementBuffer query, MappedGeometryPropertyType geoProperty,
201 Geometry geometry )
202 throws DatastoreException, GeometryException {
203
204 String argumentSRS = null;
205 if ( geometry.getCoordinateSystem() != null ) {
206 argumentSRS = geometry.getCoordinateSystem().getName();
207 }
208 String propertySRS = geoProperty.getCS().getName();
209 int internalSRS = geoProperty.getMappingField().getSRS();
210
211 int createSRSCode = getArgumentSRSCode( argumentSRS, propertySRS, internalSRS );
212 JGeometry argument = JGeometryAdapter.export( geometry, createSRSCode );
213
214 int targetSRSCode = getTargetSRSCode( argumentSRS, propertySRS, internalSRS );
215 if ( targetSRSCode != SRS_UNDEFINED ) {
216 query.append( ds.buildSRSTransformCall( "?", targetSRSCode ) );
217 } else {
218 query.append( '?' );
219 }
220 query.addArgument( argument, Types.STRUCT );
221 }
222
223 /**
224 * Returns the internal SRS code that must be used for the creation of a geometry argument used
225 * in a spatial operator.
226 *
227 * @param literalSRS
228 * @param propertySRS
229 * @param internalSrs
230 * @return the internal SRS code that must be used for the creation of a geometry argument
231 * @throws DatastoreException
232 */
233 private int getArgumentSRSCode( String argumentSRS, String propertySRS, int internalSrs )
234 throws DatastoreException {
235 int argumentSRSCode = internalSrs;
236 if ( argumentSRS == null ) {
237 argumentSRSCode = internalSrs;
238 } else if ( !propertySRS.equals( argumentSRS ) ) {
239 argumentSRSCode = this.ds.getNativeSRSCode( argumentSRS );
240 if ( argumentSRSCode == SRS_UNDEFINED ) {
241 String msg = Messages.getMessage( "DATASTORE_SQL_NATIVE_CT_UNKNOWN_SRS",
242 OracleDatastore.class.getName(), argumentSRS );
243 throw new DatastoreException( msg );
244 }
245 }
246 return argumentSRSCode;
247 }
248
249 /**
250 * Returns the internal SRS code that must be used for the transform call for a geometry
251 * argument used in a spatial operator.
252 *
253 * @param literalSRS
254 * @param propertySRS
255 * @param internalSrs
256 * @return the internal SRS code that must be used for the transform call of a geometry
257 * argument, or -1 if no transformation is necessary
258 */
259 private int getTargetSRSCode( String argumentSRS, String propertySRS, int internalSrs )
260 throws DatastoreException {
261 int targetSRS = SRS_UNDEFINED;
262 if ( argumentSRS != null && !argumentSRS.equals( propertySRS ) ) {
263 if ( internalSrs == SRS_UNDEFINED ) {
264 String msg = Messages.getMessage( "DATASTORE_SRS_NOT_SPECIFIED2", argumentSRS, propertySRS );
265 throw new DatastoreException( msg );
266 }
267 targetSRS = internalSrs;
268 }
269 return targetSRS;
270 }
271 }