001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/csw/discovery/GetRecordsDocument.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2007 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/exse/ 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 Meckenheimer Allee 176 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.ogcwebservices.csw.discovery; 045 046 import java.io.IOException; 047 import java.net.URI; 048 import java.net.URISyntaxException; 049 import java.net.URL; 050 import java.util.ArrayList; 051 import java.util.HashMap; 052 import java.util.List; 053 import java.util.Map; 054 055 import org.deegree.datatypes.QualifiedName; 056 import org.deegree.framework.log.ILogger; 057 import org.deegree.framework.log.LoggerFactory; 058 import org.deegree.framework.util.StringTools; 059 import org.deegree.framework.xml.XMLParsingException; 060 import org.deegree.framework.xml.XMLTools; 061 import org.deegree.i18n.Messages; 062 import org.deegree.model.filterencoding.AbstractFilter; 063 import org.deegree.model.filterencoding.AbstractOperation; 064 import org.deegree.model.filterencoding.ComplexFilter; 065 import org.deegree.model.filterencoding.Expression; 066 import org.deegree.model.filterencoding.Filter; 067 import org.deegree.model.filterencoding.FilterConstructionException; 068 import org.deegree.model.filterencoding.LogicalOperation; 069 import org.deegree.model.filterencoding.Operation; 070 import org.deegree.model.filterencoding.PropertyIsBetweenOperation; 071 import org.deegree.model.filterencoding.PropertyIsCOMPOperation; 072 import org.deegree.model.filterencoding.PropertyIsInstanceOfOperation; 073 import org.deegree.model.filterencoding.PropertyIsLikeOperation; 074 import org.deegree.model.filterencoding.PropertyIsNullOperation; 075 import org.deegree.model.filterencoding.PropertyName; 076 import org.deegree.model.filterencoding.SpatialOperation; 077 import org.deegree.ogcbase.CommonNamespaces; 078 import org.deegree.ogcbase.ExceptionCode; 079 import org.deegree.ogcbase.PropertyPath; 080 import org.deegree.ogcbase.PropertyPathFactory; 081 import org.deegree.ogcbase.SortProperty; 082 import org.deegree.ogcwebservices.InvalidParameterValueException; 083 import org.deegree.ogcwebservices.MissingParameterValueException; 084 import org.deegree.ogcwebservices.OGCWebServiceException; 085 import org.deegree.ogcwebservices.OperationNotSupportedException; 086 import org.deegree.ogcwebservices.csw.AbstractCSWRequestDocument; 087 import org.deegree.ogcwebservices.csw.discovery.GetRecords.RESULT_TYPE; 088 import org.w3c.dom.Element; 089 import org.w3c.dom.Node; 090 import org.w3c.dom.NodeList; 091 import org.xml.sax.SAXException; 092 093 /** 094 * Represents an XML GetRecords document of an OGC CSW 2.0 compliant service. 095 * 096 * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a> 097 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a> 098 * @author last edited by: $Author: rbezema $ 099 * 100 * @version $Revision: 7555 $, $Date: 2007-06-13 12:19:46 +0200 (Mi, 13 Jun 2007) $ 101 */ 102 public class GetRecordsDocument extends AbstractCSWRequestDocument { 103 104 private static final long serialVersionUID = 2796229558893029054L; 105 106 private static final ILogger LOG = LoggerFactory.getLogger( GetRecordsDocument.class ); 107 108 private static final String XML_TEMPLATE = "GetRecordsTemplate.xml"; 109 110 /** 111 * Extracts a <code>GetRecords</code> representation of this object. 112 * 113 * @param id 114 * unique ID of the request 115 * @return GetRecords representation of this object 116 * @throws MissingParameterValueException 117 * @throws InvalidParameterValueException 118 * @throws OperationNotSupportedException 119 * if an CqlText constrained is requested 120 * @throws OGCWebServiceException 121 * if something else went wrong 122 */ 123 public GetRecords parse( String id ) 124 throws OGCWebServiceException { 125 126 // '<csw:GetRecords>'-element (required) 127 try { 128 Element contextNode = (Element) XMLTools.getRequiredNode( this.getRootElement(), "self::csw:GetRecords", 129 nsContext ); 130 // 'service'-attribute (optional, must be CSW) 131 String service = XMLTools.getNodeAsString( contextNode, "@service", nsContext, "CSW" ); 132 if ( !"CSW".equals( service ) ) { 133 throw new OGCWebServiceException( "GetRecordDocument", 134 Messages.getMessage( "CSW_INVALID_SERVICE_PARAM" ), 135 ExceptionCode.INVALIDPARAMETERVALUE ); 136 } 137 138 String defaultVersion = GetRecords.DEFAULT_VERSION; 139 boolean isEBRIM = (contextNode.getOwnerDocument().lookupPrefix( CommonNamespaces.OASIS_EBRIMNS.toASCIIString() ) != null); 140 if( !isEBRIM ){ 141 isEBRIM = isEbrimDefined( contextNode ); 142 } 143 LOG.logDebug( "GetRecordsDocument: For the namespaceDefinition of the ebrim catalogue, the value is: " + isEBRIM ); 144 if ( isEBRIM ) { 145 defaultVersion = "2.0.1"; 146 } 147 148 // 'version'-attribute (optional) 149 String version = XMLTools.getNodeAsString( contextNode, "@version", nsContext, defaultVersion ); 150 if ( !( GetRecords.DEFAULT_VERSION.equals( version ) || "2.0.1".equals( version ) || "2.0.2".equals( version ) ) ) { 151 throw new OGCWebServiceException( "GetRecordDocument", 152 Messages.getMessage( "CSW_NOT_SUPPORTED_VERSION", 153 GetRecords.DEFAULT_VERSION, "2.0.1", "2.0.2", 154 version ), ExceptionCode.INVALIDPARAMETERVALUE ); 155 } 156 157 // 'requestId'-attribute (optional) 158 String requestId = XMLTools.getNodeAsString( contextNode, "@requestId", nsContext, id ); 159 160 // 'resultType'-attribute 161 // type="csw:ResultType" use="optional" default="hits" 162 String resultTypeString = XMLTools.getNodeAsString( contextNode, "@resultType", nsContext, 163 GetRecords.RESULT_TYPE_STRING_HITS ); 164 RESULT_TYPE resultType = RESULT_TYPE.RESULTS; 165 if ( GetRecords.RESULT_TYPE_STRING_HITS.equalsIgnoreCase( resultTypeString ) ) { 166 resultType = RESULT_TYPE.HITS; 167 } else if ( GetRecords.RESULT_TYPE_STRING_RESULTS.equalsIgnoreCase( resultTypeString ) ) { 168 resultType = RESULT_TYPE.RESULTS; 169 } else if ( GetRecords.RESULT_TYPE_STRING_VALIDATE.equalsIgnoreCase( resultTypeString ) ) { 170 resultType = RESULT_TYPE.VALIDATE; 171 } else { 172 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_RESULTTYPE", resultTypeString, 173 GetRecords.RESULT_TYPE_STRING_HITS, 174 GetRecords.RESULT_TYPE_STRING_RESULTS, 175 GetRecords.RESULT_TYPE_STRING_VALIDATE ), 176 ExceptionCode.INVALIDPARAMETERVALUE ); 177 } 178 179 // 'outputFormat'-attribute 180 // type="xsd:string" use="optional" default="text/xml" 181 String outputFormat = XMLTools.getNodeAsString( contextNode, "@outputFormat", nsContext, 182 GetRecords.DEFAULT_OUTPUTFORMAT ); 183 184 String defaultOutputSchema = GetRecords.DEFAULT_OUTPUTSCHEMA; 185 if( isEBRIM ){ 186 defaultOutputSchema = CommonNamespaces.OASIS_EBRIMNS.toASCIIString(); 187 } 188 // 'outputSchema'-attribute 189 // type="xsd:anyURI" use="optional" default="OGCCORE" 190 String outputSchema = XMLTools.getNodeAsString( contextNode, "@outputSchema", nsContext, 191 defaultOutputSchema ); 192 193 // 'startPosition'-attribute 194 // type="xsd:positiveInteger" use="optional" default="1" 195 int startPosition = XMLTools.getNodeAsInt( contextNode, "@startPosition", nsContext, 196 GetRecords.DEFAULT_STARTPOSITION ); 197 if ( startPosition < 1 ) { 198 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_STARTPOSITION", 199 new Integer( startPosition ) ), 200 ExceptionCode.INVALIDPARAMETERVALUE ); 201 } 202 203 // 'maxRecords'-attribute 204 // type="xsd:nonNegativeInteger" use="optional" default="10" 205 int maxRecords = XMLTools.getNodeAsInt( contextNode, "@maxRecords", nsContext, 206 GetRecords.DEFAULT_MAX_RECORDS ); 207 208 // '<csw:DistributedSearch>'-element (optional) 209 Node distributedSearchElement = XMLTools.getNode( contextNode, "csw:DistributedSearch", nsContext ); 210 int hopCount = GetRecords.DEFAULT_HOPCOUNT; 211 if ( distributedSearchElement != null ) { 212 hopCount = XMLTools.getNodeAsInt( contextNode, "@hopCount", nsContext, GetRecords.DEFAULT_HOPCOUNT ); 213 } 214 215 // '<csw:ResponseHandler>'-elements (optional) 216 String rHandler = XMLTools.getNodeAsString( contextNode, "csw:ResponseHandler", nsContext, null ); 217 URI responseHandler = null; 218 if ( rHandler != null ) { 219 try { 220 responseHandler = new URI( rHandler ); 221 } catch ( URISyntaxException e ) { 222 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_RESPONSE_HANDLER", rHandler ), 223 ExceptionCode.INVALIDPARAMETERVALUE ); 224 } 225 LOG.logWarning( Messages.getMessage( "CSW_NO_REPONSE_HANDLER_IMPLEMENTATION" ) ); 226 227 } 228 229 // '<csw:Query>'-elements (required) 230 // List nl = XMLTools.getRequiredNodes( contextNode, "csw:Query", nsContext ); 231 Element queryNode = (Element) XMLTools.getRequiredNode( contextNode, "csw:Query", nsContext ); 232 233 Map<String, QualifiedName> declaredVariables = new HashMap<String, QualifiedName>(); 234 List<QualifiedName> queryTypeNames = new ArrayList<QualifiedName>(); 235 236 // 'typeName'-attribute use="required" 237 String tNames = XMLTools.getRequiredNodeAsString( queryNode, "@typeNames", nsContext ); 238 String[] simpleTypeNames = tNames.split( " " ); 239 // only bind the prefixes to namespaces if the version is 2.0.0 240 boolean bindTypeNamesToNS = !GetRecords.DEFAULT_VERSION.equals( version ); 241 // Find any variables 242 for ( String typeName : simpleTypeNames ) { 243 findVariablesInTypeName( typeName, queryNode, queryTypeNames, declaredVariables, bindTypeNamesToNS ); 244 } 245 246 // '<csw:ElementSetName>'-element (optional) 247 Element elementSetNameElement = (Element) XMLTools.getNode( queryNode, "csw:ElementSetName", nsContext ); 248 String elementSetName = null; 249 List<QualifiedName> elementSetNameTypeNames = null; 250 Map<String, QualifiedName> elementSetNameVariables = null; 251 List<PropertyPath> elementNames = null; 252 // choice construct 253 if ( elementSetNameElement != null ) { 254 // must contain one of the values 'brief', 'summary' or 255 // 'full' 256 elementSetName = XMLTools.getRequiredNodeAsString( elementSetNameElement, "text()", nsContext, 257 new String[] { "brief", "summary", "full" } ); 258 tNames = elementSetNameElement.getAttribute( "typeNames" ); 259 if ( tNames != null ) { 260 String[] esnTypeNames = tNames.split( " " ); 261 elementSetNameVariables = new HashMap<String, QualifiedName>(); 262 elementSetNameTypeNames = new ArrayList<QualifiedName>(); 263 for ( String tn : esnTypeNames ) { 264 if ( tn.trim().startsWith( "$" ) ) { 265 String tmpVar = tn.trim().substring( 1 ); 266 if ( !declaredVariables.containsKey( tmpVar ) ) { 267 throw new OGCWebServiceException( 268 Messages.getMessage( 269 "CSW_ELEMENT_SET_NAME_TYPENAME_ALIAS", 270 tmpVar ), 271 ExceptionCode.INVALIDPARAMETERVALUE ); 272 } 273 elementSetNameVariables.put( tmpVar, declaredVariables.get( tmpVar ) ); 274 } else { 275 QualifiedName qName = parseQNameFromString( tn.trim(), elementSetNameElement, 276 bindTypeNamesToNS ); 277 elementSetNameTypeNames.add( qName ); 278 } 279 } 280 } 281 282 } else { 283 // '<csw:ElementName>'-element (required, if no 284 // '<csw:ElementSetName>' is given) 285 List elementNameList = XMLTools.getNodes( queryNode, "csw:ElementName", nsContext ); 286 if ( elementNameList.size() == 0 ) { 287 throw new XMLParsingException( Messages.getMessage( "CSW_MISSING_QUERY_ELEMENT(SET)NAME" ) ); 288 } 289 for ( Object en : elementNameList ) { 290 Node n = (Node) en; 291 QualifiedName elementName = XMLTools.getNodeAsQualifiedName( n, "text()", nsContext, null ); 292 if ( elementName != null ) { 293 elementNames.add( PropertyPathFactory.createPropertyPath( elementName ) ); 294 } 295 } 296 297 } 298 299 // '<csw:Constraint>'-element (optional) 300 Element constraintElement = (Element) XMLTools.getNode( queryNode, "csw:Constraint", nsContext ); 301 Filter constraint = null; 302 if ( constraintElement != null ) { 303 String ver = XMLTools.getRequiredNodeAsString( constraintElement, "@version", nsContext ); 304 if ( !"1.0.0".equals( ver ) && !"1.1.0".equals( ver ) ) { 305 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_CONSTRAINT_VERSION", ver ), 306 ExceptionCode.INVALIDPARAMETERVALUE ); 307 } 308 Node filterElement = XMLTools.getNode( constraintElement, "ogc:Filter", nsContext ); 309 if ( filterElement != null ) { 310 try { 311 constraint = AbstractFilter.buildFromDOM( (Element) filterElement ); 312 } catch ( FilterConstructionException fce ) { 313 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_CONSTRAINT_CONTENT", 314 fce.getMessage() ), 315 ExceptionCode.INVALIDPARAMETERVALUE ); 316 } 317 } else { 318 String cqlText = XMLTools.getNodeAsString( constraintElement, "csw:CqlText", nsContext, null ); 319 if ( cqlText == null ) { 320 throw new OGCWebServiceException( Messages.getMessage( "CSW_CQL_NOR_FILTER" ), 321 ExceptionCode.INVALIDPARAMETERVALUE ); 322 } 323 324 throw new OGCWebServiceException( Messages.getMessage( "CSW_NO_CQL_IMPLEMENTATION" ), 325 ExceptionCode.OPERATIONNOTSUPPORTED ); 326 } 327 } 328 // find undeclared referenced variables used in the filter element. 329 if ( constraint instanceof ComplexFilter ) { 330 checkReferencedVariables( (ComplexFilter) constraint, declaredVariables ); 331 } 332 333 // '<ogc:SortBy>'-element (optional) 334 Node sortByElement = XMLTools.getNode( queryNode, "ogc:SortBy", nsContext ); 335 SortProperty[] sortProperties = null; 336 if ( sortByElement != null ) { 337 List sortPropertyList = XMLTools.getNodes( sortByElement, "ogc:SortProperty", nsContext ); 338 if ( sortPropertyList.size() == 0 ) { 339 throw new OGCWebServiceException( Messages.getMessage( "CSW_NO_SORTPROPERTY_LIST" ), 340 ExceptionCode.INVALIDPARAMETERVALUE ); 341 342 } 343 sortProperties = new SortProperty[sortPropertyList.size()]; 344 for ( int j = 0; j < sortPropertyList.size(); j++ ) { 345 sortProperties[j] = SortProperty.create( (Element) sortPropertyList.get( j ) ); 346 } 347 } 348 349 Query query = new Query( elementSetName, elementSetNameTypeNames, elementSetNameVariables, elementNames, 350 constraint, sortProperties, queryTypeNames, declaredVariables ); 351 352 // in the future the vendorSpecificParameters 353 Map<String, String> vendorSpecificParameters = parseDRMParams( this.getRootElement() ); 354 return new GetRecords( requestId, version, vendorSpecificParameters, null, resultType, outputFormat, 355 outputSchema, startPosition, maxRecords, hopCount, responseHandler, query ); 356 } catch ( XMLParsingException xmlpe ) { 357 LOG.logError( "CatalogGetRecords", xmlpe ); 358 throw new OGCWebServiceException( xmlpe.getMessage(), ExceptionCode.INVALID_FORMAT ); 359 } catch ( URISyntaxException urise ) { 360 LOG.logError( "CatalogGetRecords", urise ); 361 throw new OGCWebServiceException( urise.getMessage(), ExceptionCode.INVALID_FORMAT ); 362 } 363 } 364 365 /** 366 * @param contextNode 367 * @return true if the namespace "urn:oasis:names:tc:ebxml- regrep:xsd:rim:3.0" was found in one of the nodes of the 368 * dom-tree. 369 */ 370 private boolean isEbrimDefined( Node contextNode ) { 371 372 boolean isEbRim = ( contextNode.lookupPrefix( CommonNamespaces.OASIS_EBRIMNS.toASCIIString() ) != null ); 373 if ( !isEbRim ) { 374 NodeList nl = contextNode.getChildNodes(); 375 for ( int i = 0; i < nl.getLength(); ++i ) { 376 isEbRim = isEbrimDefined( nl.item( i ) ); 377 if ( isEbRim ) { 378 return true; 379 } 380 } 381 } 382 return isEbRim; 383 } 384 385 /** 386 * Helper method to find any declared variables in given Query/@typeNames 387 * 388 * @param typeName 389 * the type name to test 390 * @param queryNode 391 * the querynode (used to find a given prefix) 392 * @param typeNames 393 * a list to save the typeName (as QualifiedNames) in 394 * @param variables 395 * a Map containing the vars/QualifiedName mappings 396 * @param bindTypeNameToNS 397 * if the namespaces should be bounded to the typeNames 398 * @throws URISyntaxException 399 * if the prefix is not bound to a namespace 400 * @throws OGCWebServiceException 401 * if a variable name is unambiguous 402 */ 403 public void findVariablesInTypeName( String typeName, Node queryNode, List<QualifiedName> typeNames, 404 Map<String, QualifiedName> variables, boolean bindTypeNameToNS ) 405 throws OGCWebServiceException, URISyntaxException { 406 LOG.logDebug( "testing for variables in typeName: " + typeName ); 407 int variableIndex = typeName.lastIndexOf( '=' ); 408 String tmpTypeName = typeName; 409 if ( variableIndex != -1 ) { 410 // find the typeNames 411 tmpTypeName = typeName.substring( 0, variableIndex ).trim(); 412 LOG.logDebug( "typeName contains variables" ); 413 } 414 415 // creating the qualified name 416 QualifiedName qName = parseQNameFromString( tmpTypeName, queryNode, bindTypeNameToNS ); 417 typeNames.add( qName ); 418 if ( variableIndex != -1 ) { 419 if ( ( variableIndex + 1 ) < typeName.length() ) { 420 // find the variables which should be referenced with the $-sign 421 String allVars = typeName.substring( variableIndex + 1 ); 422 String[] vars = allVars.split( "," ); 423 for ( String var : vars ) { 424 LOG.logDebug( "found var: " + var ); 425 if ( variables.put( var.trim(), qName ) != null ) { 426 String out = Messages.getMessage( "CSW_AMBIGUOUS_VARIABLE_DEF", var.trim() ); 427 throw new OGCWebServiceException( "GetRecords", out, ExceptionCode.INVALIDPARAMETERVALUE ); 428 } 429 } 430 } 431 } 432 } 433 434 /** 435 * @param typeName to be transformed to a QName 436 * @param queryNode needed to get the namespace 437 * @param bindTypeNameToNS if true the namespace will be bound to the qualified name 438 * @return a QualifiedName representing the typeName 439 * @throws URISyntaxException 440 */ 441 public QualifiedName parseQNameFromString( String typeName, Node queryNode, boolean bindTypeNameToNS ) 442 throws URISyntaxException { 443 int prefixIndex = typeName.indexOf( ':' ); 444 String preFix = null; 445 URI nameSpace = null; 446 String localName = typeName; 447 if ( prefixIndex != -1 ) { 448 preFix = typeName.substring( 0, prefixIndex ).trim(); 449 if ( bindTypeNameToNS ) { 450 LOG.logDebug( "Trying to find namespace binding for the prefix: " + preFix + " on node queryNode: " 451 + queryNode.getNodeName() ); 452 nameSpace = XMLTools.getNamespaceForPrefix( preFix, queryNode ); 453 } else { 454 LOG.logDebug( "Not binding namespaces for the prefix: " + preFix + " on node queryNode: " 455 + queryNode.getNodeName() + " because the version of the GetRecordsRequest is not 2.0.2" ); 456 } 457 // for version 2.0.0 no namespace checkin is required following versions should check if 458 // the returned namespace is null. 459 if ( ( prefixIndex + 1 ) < typeName.length() ) { 460 localName = typeName.substring( prefixIndex + 1 ).trim(); 461 } else { 462 localName = typeName.substring( prefixIndex ).trim(); 463 } 464 } 465 LOG.logDebug( "found prefix: " + preFix ); 466 LOG.logDebug( "found localName: " + localName ); 467 LOG.logDebug( "found namespace: " + nameSpace ); 468 return new QualifiedName( preFix, localName, nameSpace ); 469 } 470 471 /** 472 * Iterates over the Operations of a complexfilter to find if non declared variables are used. 473 * 474 * @param constraint 475 * @param variables 476 * @throws OGCWebServiceException 477 */ 478 private void checkReferencedVariables( ComplexFilter constraint, Map<String, QualifiedName> variables ) 479 throws OGCWebServiceException { 480 AbstractOperation topOperation = (AbstractOperation) constraint.getOperation(); 481 if ( topOperation instanceof LogicalOperation ) { 482 List<Operation> operations = ( (LogicalOperation) topOperation ).getArguments(); 483 for ( Operation op : operations ) { 484 findNonDeclaredVariables( (AbstractOperation) op, variables ); 485 } 486 } else { 487 findNonDeclaredVariables( topOperation, variables ); 488 } 489 } 490 491 /** 492 * (Recursively) finds a reference to a non declared variable in the propertyname of the given operation. 493 * 494 * @param operation 495 * to be checked 496 * @param variables 497 * which were declared 498 * @throws OGCWebServiceException 499 * if such a reference is found 500 */ 501 private void findNonDeclaredVariables( AbstractOperation operation, Map<String, QualifiedName> variables ) 502 throws OGCWebServiceException { 503 if ( operation instanceof LogicalOperation ) { 504 List<Operation> operations = ( (LogicalOperation) operation ).getArguments(); 505 for ( Operation op : operations ) { 506 findNonDeclaredVariables( (AbstractOperation) op, variables ); 507 } 508 } else if ( operation instanceof SpatialOperation ) { 509 findNonDeclaredVariables( ( (SpatialOperation) operation ).getPropertyName(), variables ); 510 } else { 511 if ( operation instanceof PropertyIsBetweenOperation ) { 512 findNonDeclaredVariables( ( (PropertyIsBetweenOperation) operation ).getPropertyName(), variables ); 513 } else if ( operation instanceof PropertyIsCOMPOperation ) { 514 Expression expr = ( (PropertyIsCOMPOperation) operation ).getFirstExpression(); 515 if ( expr instanceof PropertyName ) { 516 findNonDeclaredVariables( ( (PropertyName) expr ), variables ); 517 } 518 expr = ( (PropertyIsCOMPOperation) operation ).getSecondExpression(); 519 if ( expr instanceof PropertyName ) { 520 findNonDeclaredVariables( ( (PropertyName) expr ), variables ); 521 } 522 } else if ( operation instanceof PropertyIsInstanceOfOperation ) { 523 findNonDeclaredVariables( ( (PropertyIsInstanceOfOperation) operation ).getPropertyName(), variables ); 524 } else if ( operation instanceof PropertyIsLikeOperation ) { 525 findNonDeclaredVariables( ( (PropertyIsLikeOperation) operation ).getPropertyName(), variables ); 526 } else if ( operation instanceof PropertyIsNullOperation ) { 527 findNonDeclaredVariables( ( (PropertyIsNullOperation) operation ).getPropertyName(), variables ); 528 } 529 } 530 } 531 532 /** 533 * Parse the string representation of the the propertyname to find a variable reference to a non declared Variable. 534 * 535 * @param propName 536 * to check 537 * @param variables 538 * which were declared 539 * @throws InvalidParameterValueException 540 * if such a reference was found. 541 */ 542 private void findNonDeclaredVariables( PropertyName propName, Map<String, QualifiedName> variables ) 543 throws OGCWebServiceException { 544 String propertyPath = propName.toString(); 545 String[] foundVariables = StringTools.extractStrings( propertyPath, "$", "/" ); 546 if ( foundVariables != null && foundVariables.length > 0 ) { 547 LOG.logDebug( "found following variables in properertyName: " + propName.toString() ); 548 for ( String var : foundVariables ) { 549 LOG.logDebug( "variable: " + var ); 550 if ( !variables.containsKey( var ) ) { 551 throw new OGCWebServiceException( Messages.getMessage( "CSW_VARIABLE_NOT_DEFINED", var ), 552 ExceptionCode.INVALIDPARAMETERVALUE ); 553 } 554 } 555 } 556 } 557 558 /* 559 * (non-Javadoc) 560 * 561 * @see org.deegree.framework.xml.XMLFragment#createEmptyDocument() 562 */ 563 void createEmptyDocument() 564 throws IOException, SAXException { 565 URL url = GetRecordsDocument.class.getResource( XML_TEMPLATE ); 566 if ( url == null ) { 567 throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." ); 568 } 569 load( url ); 570 } 571 }