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