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 }