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 }