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 }