001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/ogcwebservices/csw/discovery/GetRecords.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 package org.deegree.ogcwebservices.csw.discovery; 037 038 import java.io.StringReader; 039 import java.net.URI; 040 import java.net.URISyntaxException; 041 import java.util.Map; 042 043 import org.deegree.framework.log.ILogger; 044 import org.deegree.framework.log.LoggerFactory; 045 import org.deegree.framework.util.StringTools; 046 import org.deegree.framework.xml.NamespaceContext; 047 import org.deegree.framework.xml.XMLParsingException; 048 import org.deegree.framework.xml.XMLTools; 049 import org.deegree.i18n.Messages; 050 import org.deegree.model.filterencoding.AbstractFilter; 051 import org.deegree.model.filterencoding.Filter; 052 import org.deegree.ogcbase.CommonNamespaces; 053 import org.deegree.ogcbase.ExceptionCode; 054 import org.deegree.ogcbase.SortProperty; 055 import org.deegree.ogcwebservices.InvalidParameterValueException; 056 import org.deegree.ogcwebservices.MissingParameterValueException; 057 import org.deegree.ogcwebservices.OGCWebServiceException; 058 import org.deegree.ogcwebservices.OperationNotSupportedException; 059 import org.deegree.ogcwebservices.csw.AbstractCSWRequest; 060 import org.deegree.ogcwebservices.csw.CSWPropertiesAccess; 061 import org.w3c.dom.Document; 062 import org.w3c.dom.Element; 063 064 /** 065 * Class representation of a <code>GetRecords</code> request. 066 * <p> 067 * The primary means of resource discovery in the general model are the two operations search and present. In the HTTP 068 * protocol binding these are combined in the form of the mandatory <code>GetRecords</code> operation, which does a 069 * search. 070 * <p> 071 * Parameters specific to the <code>GetRecords</code> -request (omitting REQUEST, SERVICE and VERSION): 072 * <table * border="1"> 073 * <tr> 074 * <th>Name</th> 075 * <th>Occurences</th> 076 * <th>Function</th> 077 * </tr> 078 * <tr> 079 * <td align="center">NAMESPACE</td> 080 * <td align="center">0|1</td> 081 * <td>The NAMESPACE parameter is included in the KVP encoding to allow clients to bind any namespace prefixes that 082 * might be used for qualified names specified in other parameters. For example, the typeName parameter may include 083 * qualified names of the form namespace prefix:name. The value of the NAMESPACE parameter is a comma separated list of 084 * character strings of the form [namespace prefix:] namespace url. Not including the name namespace prefix binds the 085 * specified URL to the default namespace. As in XML, only one default namespace may be bound. This parameter is not 086 * required for the XML encoding since XML includes a mechanism for binding namespace prefixes.</td> 087 * </tr> 088 * <tr> 089 * <td align="center">resultType</td> 090 * <td align="center">0|1 (default: RESULTS)</td> 091 * <td>The resultType parameter may have the values HITS, RESULTS or VALIDATE and is used to indicate whether the 092 * catalogue service returns the full result set, the number of hits the query found or validates the request. If the 093 * resultType parameter is set to HITS, the catalogue service shall return an empty <GetRecordsResponse> element 094 * with the numberOfRecordsMatched attribute set to indicate the number of hits. The other attributes may be set to zero 095 * or not specified at all if they are optional. If the resultType parameter is set to HITS, then the values for the 096 * parameters outputFormat and outputSchema (if specified) shall be ignored since no actual records will be returned. If 097 * the resultType parameter is set to RESULTS, the catalogue service should generate a complete response with the 098 * <GetRecordsResponse> element containing the result set for the request. If the resultType parameter is set to 099 * VALIDATE, the catalogue service shall validate the request and return an empty <GetRecordsResponse>. All 100 * mandatory attributes may be given a value of zero and all optional attributes may be omitted. If the request does not 101 * validate then a service exception shall be raised as describe in Subclause 10.3.2.3.</td> 102 * </tr> 103 * <tr> 104 * <td align="center">outputFormat</td> 105 * <td align="center">0|1 (default: text/xml)</td> 106 * <td>The outputFormat parameter is used to control the format of the output that is generated in response to a 107 * GetRecords request. Its value must be a MIME type. The default value, "text/xml", means that the output shall be an 108 * XML document. All registries shall at least support XML as an output format. Other output formats may be supported 109 * and may include output formats such as TEXT (MIME type text/plain), or HTML (MIME type text/html). The list of output 110 * formats that a CSW instance provides must be advertised in the Capabilities document. In the case where the output 111 * format is text/xml, the CSW must generate an XML document that validates against a schema document that is specified 112 * in the output document via the xsi:schemaLocation attribute defined in XML.</td> 113 * </tr> 114 * <tr> 115 * <td align="center">outputSchema</td> 116 * <td align="center">0|1 (default: OGCCORE)</td> 117 * <td>The outputSchema parameter is used to indicate the schema of the output that is generated in response to a 118 * GetRecords request. The default value for this parameter shall be OGCCORE indicating that the schema for the core 119 * returnable properties (as defined in subclause 6.3.3) shall be used. Application profiles may define additional 120 * values for outputSchema and may redefine the default value but all profiles must support the value OGCCORE. Examples 121 * values for the outputSchema parameter might be FGDC, or ISO19119, ISO19139 or ANZLIC. The list of supported output 122 * schemas must be advertised in the capabilities document. 123 * </tr> 124 * <tr> 125 * <td align="center">startPosition</td> 126 * <td align="center">0|1 (default: 1)</td> 127 * <td>The startPosition paramater is used to indicate at which record position the catalogue should start generating 128 * output. The default value is 1 meaning it starts at the first record in the result set.</td> 129 * </tr> 130 * <tr> 131 * <td align="center">maxRecords</td> 132 * <td align="center">0|1 (default: 10)</td> 133 * <td>The maxRecords parameter is used to define the maximum number of records that should be returned from the result 134 * set of a query. If it is not specified, then 10 records shall be returned. If its value is set to zero, then the 135 * behavior is indentical to setting "resultType=HITS" as described above.</td> 136 * </tr> 137 * <tr> 138 * <td align="center">typeName</td> 139 * <td align="center">1</td> 140 * <td>The typeName parameter is a list of record type names that define a set of metadata record element names which 141 * will be constrained in the predicate of the query. In addition, all or some of the these names may be specified in 142 * the query to define which metadata record elements the query should present in the response to the GetRecords 143 * operation.</td> 144 * </tr> 145 * <tr> 146 * <td align="center">ElementSetName / ElementName</td> 147 * <td align="center">* (default: 10)</td> 148 * <td>The ElementName parameter is used to specify one or more metadata record elements that the query should present 149 * in the response to the a GetRecords operation. Well known sets of element may be named, in which case the 150 * ElementSetName parameter may be used (e.g.brief, summary or full). If neither parameter is specified, then a CSW 151 * shall present all metadata record elements. As mentioned above, if the outputFormat parameter is set to text/xml, 152 * then the response to the GetRecords operation shall validate against a schema document that is referenced in the 153 * response using the xmlns attributes. If the set of metadata record elements that the client specifies in the query in 154 * insufficient to generate a valid XML response document, a CSW may augment the list of elements presented to the 155 * client in order to be able to generate a valid document. Thus a client application should expect to receive more than 156 * the requested elements if the output format is set to XML.</td> 157 * </tr> 158 * <tr> 159 * <td align="center">CONSTRAINTLANGUAGE / Constraint</td> 160 * <td align="center">0|1</td> 161 * <td>Each request encoding (XML and KVP) has a specific mechanism for specifying the predicate language that will be 162 * used to constrain a query. In the XML encoding, the element <Constraint> is used to define the query predicate. 163 * The root element of the content of the <Constraint> element defines the predicate language that is being used. 164 * Two possible root elements are <ogc:Filter> for the OGC XML filter encoding, and <csw:CqlText> for a 165 * common query language string. An example predicate specification in the XML encoding is: 166 * 167 * <Constraint> <CqlText>prop1!=10</CqlText> </Constraint> 168 * 169 * In the KVP encoding, the parameter CONSTRAINTLANGUAGE is used to specify the predicate language being used. The 170 * Constraint parameter is used to specify the actual predicate. For example, to specify a CQL predicate, the following 171 * parameters would be set in the KVP encoding: <br> 172 * 173 * ...CONSTRAINTLANGUAGE=CQL_TEXT&CONSTRAINT="prop1!=10"... 174 * 175 * </td> 176 * </tr> 177 * <tr> 178 * <td align="center">SortBy</td> 179 * <td align="center">0|1</td> 180 * <td>The result set may be sorted by specifying one or more metadata record elements upon which to sort. In KVP 181 * encoding, the SORTBY parameter is used to specify the list of sort elements. The value for the SORTBY parameter is a 182 * comma-separated list of metadata record element names upon which to sort the result set. The format for each element 183 * in the list shall be either element name:A indicating that the element values should be sorted in ascending order or 184 * element name:D indicating that the element values should be sorted in descending order. For XML encoded requests, the 185 * <ogc:SortBy> element is used to specify a list of sort metadata record elements. The attribute sortOrder is 186 * used to specify the sort order for each element. Valid values for the sortOrder attribute are ASC indicating an 187 * ascending sort and DESC indicating a descending sort.</td> 188 * </tr> 189 * <tr> 190 * <td align="center">DistributedSearch / hopCount</td> 191 * <td align="center">0|1 (default: FALSE)</td> 192 * <td>The DistributedSearch parameter may be used to indicate that the query should be distributed. The default query 193 * behaviour, if the DistributedSearch parameter is set to FALSE (or is not specified at all), is to execute the query 194 * on the local server. In the XML encoding, if the <DistributedSearch> element is not specified then the query is 195 * executed on the local server. <br> 196 * <br> 197 * The hopCount parameter controls the distributed query behaviour by limiting the maximum number of message hops before 198 * the search is terminated. Each catalogue decrements this value by one when the request is received and does not 199 * propagate the request if the hopCount=0.</td> 200 * </tr> 201 * <tr> 202 * <td align="center">ResponseHandler</td> 203 * <td align="center">0|1</td> 204 * <td>The ResponseHandler parameter is a flag that indicates how the GetRecords operation should be processed by a CSW. 205 * If the parameter is not present, then the GetRecords operation is processed synchronously meaning that the client 206 * sends the GetRecords request to a CSW and waits to receive a valid response or exception message. The CSW immediately 207 * processes the GetRecords request while the client waits for a response. The problem with this mode of operation is 208 * that the client may timeout waiting for the CSW to process the request. If the ResponseHandler parameter is present, 209 * the GetRecords operation is processed asynchronously. In this case, the CSW responds immediately to a client's 210 * request with an acknowledgment message that tells the client that the request has been received and validated, and 211 * notification of completion will be sent to the URI specified as the value of the ResponseHandler parameter.</td> 212 * </tr> 213 * </table> 214 * 215 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a> 216 * @version $Revision: 28346 $ 217 * 218 * 219 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> 220 * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a> 221 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a> 222 * 223 * @author last edited by: $Author: lbuesching $ 224 * 225 * @version $Revision: 28346 $, $Date: 2010-11-23 12:08:02 +0100 (Di, 23 Nov 2010) $ 226 */ 227 228 public class GetRecords extends AbstractCSWRequest { 229 230 private static final long serialVersionUID = 2796229558893029054L; 231 232 private static final ILogger LOG = LoggerFactory.getLogger( GetRecords.class ); 233 234 protected static final String DEFAULT_OUTPUTFORMAT = "application/xml"; 235 236 protected static final String DEFAULT_OUTPUTSCHEMA = "csw:Record"; 237 238 protected static final String DEFAULT_OUTPUTSCHEMA_202 = "http://www.opengis.net/cat/csw/2.0.2"; 239 240 protected static final int DEFAULT_STARTPOSITION = 1; 241 242 protected static final int DEFAULT_MAX_RECORDS = 10; 243 244 protected static final int DEFAULT_HOPCOUNT = 2; 245 246 protected static final String DEFAULT_VERSION = "2.0.0"; 247 248 /** 249 * defining HITS as String 250 */ 251 public static String RESULT_TYPE_STRING_HITS = "hits"; 252 253 /** 254 * defining VALIDATE as String 255 */ 256 public static String RESULT_TYPE_STRING_VALIDATE = "validate"; 257 258 /** 259 * defining RESULTS as String 260 */ 261 public static String RESULT_TYPE_STRING_RESULTS = "results"; 262 263 private static NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); 264 265 private RESULT_TYPE resultType = RESULT_TYPE.RESULTS; 266 267 // keys are Strings (namespace prefix or "" for default namespace), values 268 // are URIs 269 private Map<String, URI> namespace; 270 271 private String outputFormat; 272 273 private String outputSchema; 274 275 private int startPosition; 276 277 private int maxRecords; 278 279 private int hopCount; 280 281 private URI responseHandler; 282 283 // private Query[] queries; 284 285 private Query query; 286 287 /** 288 * Creates a new <code>GetRecords</code> instance. 289 * 290 * @param id 291 * @param version 292 * @param vendorSpecificParameters 293 * @param namespace 294 * @param resultType 295 * @param outputFormat 296 * @param outputSchema 297 * @param startPosition 298 * @param maxRecords 299 * @param hopCount 300 * @param responseHandler 301 * @param query 302 */ 303 public GetRecords( String id, String version, Map<String, String> vendorSpecificParameters, 304 Map<String, URI> namespace, RESULT_TYPE resultType, String outputFormat, String outputSchema, 305 int startPosition, int maxRecords, int hopCount, URI responseHandler, Query query ) { 306 super( version, id, vendorSpecificParameters ); 307 this.namespace = namespace; 308 this.resultType = resultType; 309 this.outputFormat = outputFormat; 310 this.outputSchema = outputSchema; 311 this.startPosition = startPosition; 312 this.maxRecords = maxRecords; 313 this.hopCount = hopCount; 314 this.responseHandler = responseHandler; 315 this.query = query; 316 } 317 318 /** 319 * creates a GetRecords request from the XML fragment passed. The passed element must be valid against the OGC CSW 320 * 2.0 GetRecords schema. 321 * 322 * TODO respect namespaces (use QualifiedNames) for type names 323 * 324 * @param id 325 * unique ID of the request 326 * @param root 327 * root element of the GetRecors request 328 * @return a GetRecords instance with given id and parsed values from the root element 329 * @throws MissingParameterValueException 330 * if a required parameter was not set 331 * @throws InvalidParameterValueException 332 * if a parameter is invalid 333 * @throws OGCWebServiceException 334 * if something went wrong while creating the Request 335 */ 336 public static GetRecords create( String id, Element root ) 337 throws MissingParameterValueException, InvalidParameterValueException, 338 OGCWebServiceException { 339 String version = null; 340 try { 341 // first try to read verdsion attribute which is optional for CSW 2.0.0 and 2.0.1 342 version = XMLTools.getNodeAsString( root, "./@version", nsContext, null ); 343 } catch ( XMLParsingException e ) { 344 // default version? 345 } 346 if ( version == null ) { 347 // if no version attribute has been set try mapping namespace URI to a version; 348 // this is not well defined for 2.0.0 and 2.0.1 which uses the same namespace. 349 // in this case 2.0.0 will be returned! 350 version = CSWPropertiesAccess.getString( root.getNamespaceURI() ); 351 } 352 353 // read class for version depenging parsing of GetRecords request from properties 354 String className = CSWPropertiesAccess.getString( "GetRecords" + version ); 355 Class<?> clzz = null; 356 try { 357 clzz = Class.forName( className ); 358 } catch ( ClassNotFoundException e ) { 359 LOG.logError( e.getMessage(), e ); 360 throw new InvalidParameterValueException( e.getMessage(), e ); 361 } 362 GetRecordsDocument document = null; 363 try { 364 document = (GetRecordsDocument) clzz.newInstance(); 365 } catch ( InstantiationException e ) { 366 LOG.logError( e.getMessage(), e ); 367 throw new InvalidParameterValueException( e.getMessage(), e ); 368 } catch ( IllegalAccessException e ) { 369 LOG.logError( e.getMessage(), e ); 370 throw new InvalidParameterValueException( e.getMessage(), e ); 371 } 372 373 document.setRootElement( root ); 374 375 GetRecords ogcRequest = document.parse( id ); 376 377 return ogcRequest; 378 } 379 380 /** 381 * Creates a new <code>GetRecords</code> instance from the values stored in the submitted Map. Keys (parameter 382 * names) in the Map must be uppercase. 383 * 384 * @TODO evaluate vendorSpecificParameter 385 * 386 * @param kvp 387 * Map containing the parameters 388 * @return a GetRecords instance with given id and values from the kvp 389 * @exception InvalidParameterValueException 390 * @exception MissingParameterValueException 391 * @throws OperationNotSupportedException 392 * if an CQL_TEXT constrain is requested 393 */ 394 public static GetRecords create( Map<String, String> kvp ) 395 throws InvalidParameterValueException, MissingParameterValueException, 396 OperationNotSupportedException { 397 398 // String version = "2.0.0"; 399 // Map<String, String> vendorSpecificParameters = null; 400 // RESULT_TYPE resultType = RESULT_TYPE.HITS; 401 // String outputFormat = "text/xml"; 402 // String outputSchema = "OGCCORE"; 403 // int startPosition = 1; 404 // int maxRecords = 10; 405 // int hopCount = 2; 406 407 String service = getParam( "SERVICE", kvp, "CSW" ); 408 if ( !"CSW".equals( service ) ) { 409 throw new InvalidParameterValueException( "GetRecordDocument", 410 Messages.getMessage( "CSW_INVALID_SERVICE_PARAM" ), 411 ExceptionCode.INVALIDPARAMETERVALUE ); 412 } 413 414 String id = getParam( "ID", kvp, "" ); 415 LOG.logDebug( "GetRecordRequest id=" + id ); 416 417 String version = getParam( "VERSION", kvp, DEFAULT_VERSION ); 418 if ( !( DEFAULT_VERSION.equals( version ) || "2.0.1".equals( version ) || "2.0.2".equals( version ) ) ) { 419 throw new InvalidParameterValueException( "GetRecords", Messages.getMessage( "CSW_NOT_SUPPORTED_VERSION", 420 GetRecords.DEFAULT_VERSION, 421 "2.0.1", "2.0.2", version ), 422 ExceptionCode.INVALIDPARAMETERVALUE ); 423 } 424 425 // extract namespace mappings 426 Map<String, URI> namespaceMappings = getNSMappings( getParam( "NAMESPACE", kvp, null ) ); 427 428 String resultTypeString = getParam( "RESULTTYPE", kvp, RESULT_TYPE_STRING_HITS ); 429 RESULT_TYPE resultType = RESULT_TYPE.HITS; 430 if ( RESULT_TYPE_STRING_HITS.equalsIgnoreCase( resultTypeString ) ) { 431 resultType = RESULT_TYPE.HITS; 432 } else if ( RESULT_TYPE_STRING_RESULTS.equalsIgnoreCase( resultTypeString ) ) { 433 resultType = RESULT_TYPE.RESULTS; 434 } else if ( RESULT_TYPE_STRING_VALIDATE.equalsIgnoreCase( resultTypeString ) ) { 435 resultType = RESULT_TYPE.VALIDATE; 436 } else { 437 throw new InvalidParameterValueException( "GetRecords", 438 Messages.getMessage( "CSW_INVALID_RESULTTYPE", resultTypeString, 439 GetRecords.RESULT_TYPE_STRING_HITS, 440 GetRecords.RESULT_TYPE_STRING_RESULTS, 441 GetRecords.RESULT_TYPE_STRING_VALIDATE ), 442 ExceptionCode.INVALIDPARAMETERVALUE ); 443 } 444 445 String outputFormat = getParam( "OUTPUTFORMAT", kvp, DEFAULT_OUTPUTFORMAT ); 446 String defaultOutputSchema = DEFAULT_OUTPUTSCHEMA; 447 if ( version.equals( "2.0.2" ) ) { 448 defaultOutputSchema = DEFAULT_OUTPUTSCHEMA_202; 449 } 450 String outputSchema = getParam( "OUTPUTSCHEMA", kvp, defaultOutputSchema ); 451 int startPosition = getParamAsInt( "STARTPOSITION", kvp, DEFAULT_STARTPOSITION ); 452 if ( startPosition < 1 ) { 453 String msg = Messages.getMessage( "CSW_INVALID_STARTPOSITION", new Integer( startPosition ) ); 454 throw new InvalidParameterValueException( msg ); 455 } 456 int maxRecords = getParamAsInt( "MAXRECORDS", kvp, DEFAULT_MAX_RECORDS ); 457 458 if ( maxRecords < 0 ) { 459 maxRecords = DEFAULT_MAX_RECORDS; 460 } 461 462 // build one Query object for each specified typeName 463 String tmp = getRequiredParam( "TYPENAMES", kvp ); 464 String[] typeNames = StringTools.toArray( tmp, ",", false ); 465 if ( typeNames.length == 0 ) { 466 throw new MissingParameterValueException( "Mandatory parameter 'TYPENAMES' is missing!" ); 467 } 468 469 String elementSetName = kvp.remove( "ELEMENTSETNAME" ); 470 String elementName = kvp.remove( "ELEMENTNAME" ); 471 String[] elementNames = null; 472 473 if ( version.equals( "2.0.2" ) ) { 474 if ( elementSetName == null ) { 475 elementSetName = "summary"; 476 } else { 477 if ( elementName != null ) { 478 LOG.logInfo( Messages.getMessage( "CSW_ELEMENT_SET_NAME_DUPLICATE" ) ); 479 } else { 480 elementNames = StringTools.toArray( elementName, ",", false ); 481 } 482 } 483 } else { 484 485 if ( elementSetName == null ) { 486 elementSetName = kvp.remove( "ELEMENTNAME" ); 487 } else { 488 String test = kvp.remove( "ELEMENTNAME" ); 489 if ( test != null ) { 490 LOG.logInfo( Messages.getMessage( "CSW_ELEMENT_SET_NAME_DUPLICATE" ) ); 491 } 492 } 493 494 if ( elementSetName != null ) { 495 elementNames = StringTools.toArray( elementSetName, ",", false ); 496 if ( elementNames.length == 0 ) { 497 elementNames = null; 498 } 499 } 500 if ( elementNames == null ) { 501 elementNames = new String[] { "full" }; 502 } 503 504 } 505 506 String constraintString = kvp.remove( "CONSTRAINT" ); 507 if ( constraintString == null ) { 508 // not really clear if CSW 2.0.2 uses parameter QUERYCONSTRAINT instead 509 constraintString = kvp.remove( "QUERYCONSTRAINT" ); 510 } 511 Filter constraint = null; 512 String constraintLanguage = null; 513 String cnstrntVersion = null; 514 if ( constraintString != null ) { 515 // build Filter object (from CONSTRAINT parameter) 516 constraintLanguage = kvp.remove( "CONSTRAINTLANGUAGE" ); 517 if ( constraintLanguage != null ) { 518 if ( "CQL_TEXT".equalsIgnoreCase( constraintLanguage.trim() ) ) { 519 throw new OperationNotSupportedException( Messages.getMessage( "CSW_NO_CQL_IMPLEMENTATION" ) ); 520 } else if ( !"FILTER".equalsIgnoreCase( constraintLanguage.trim() ) ) { 521 throw new InvalidParameterValueException( Messages.getMessage( "CSW_INVALID_CONSTRAINT_LANGUAGE", 522 constraintLanguage.trim() ) ); 523 } 524 } else { 525 throw new InvalidParameterValueException( Messages.getMessage( "CSW_CQL_NOR_FILTER_KVP" ) ); 526 } 527 cnstrntVersion = kvp.remove( "CONSTRAINT_LANGUAGE_VERSION" ); 528 if ( "2.0.2".equals( version ) && cnstrntVersion == null ) { 529 throw new InvalidParameterValueException( 530 Messages.getMessage( "CSW_MISSING_CONSTRAINT_LANGUAGE_VERSION" ) ); 531 } 532 533 try { 534 Document doc = XMLTools.parse( new StringReader( constraintString ) ); 535 Element element = doc.getDocumentElement(); 536 constraint = AbstractFilter.buildFromDOM( element, "1.0.0".equals( cnstrntVersion ) ); 537 } catch ( Exception e ) { 538 String msg = "An error occured when parsing the 'CONSTRAINT' parameter " + "Filter expression: " 539 + e.getMessage(); 540 throw new InvalidParameterValueException( msg ); 541 } 542 } 543 544 SortProperty[] sortProperties = SortProperty.create( kvp.remove( "SORTBY" ), namespaceMappings ); 545 546 // Query[] queries = new Query[typeNames.length]; 547 // for ( int i = 0; i < typeNames.length; i++ ) { 548 Query query = new Query( elementSetName, elementNames, constraint, sortProperties, typeNames ); 549 // } 550 551 // find out if the query should be performed locally or in a distributed 552 // fashion 553 int hopCount = DEFAULT_HOPCOUNT; 554 String distributedSearch = getParam( "DISTRIBUTEDSEARCH", kvp, "false" ); 555 if ( distributedSearch.equalsIgnoreCase( "true" ) ) { 556 hopCount = getParamAsInt( "HOPCOUNT", kvp, DEFAULT_HOPCOUNT ); 557 } 558 559 String rHandler = kvp.remove( "RESPONSEHANDLER" ); 560 URI responseHandler = null; 561 if ( rHandler != null ) { 562 try { 563 responseHandler = new URI( rHandler ); 564 } catch ( URISyntaxException e ) { 565 throw new InvalidParameterValueException( 566 Messages.getMessage( "CSW_INVALID_RESPONSE_HANDLER", rHandler ) ); 567 } 568 throw new OperationNotSupportedException( Messages.getMessage( "CSW_NO_REPONSE_HANDLER_IMPLEMENTATION" ) ); 569 570 } 571 572 return new GetRecords( id, version, kvp, namespaceMappings, resultType, outputFormat, outputSchema, 573 startPosition, maxRecords, hopCount, responseHandler, query ); 574 } 575 576 /** 577 * Used to specify a namespace and its prefix. Format must be [ <prefix>:] <url>. If the prefix is not specified 578 * then this is the default namespace 579 * <p> 580 * Zero or one (Optional) ; Include value for each distinct namespace used by all qualified names in the request. If 581 * not included, all qualified names are in default namespace 582 * <p> 583 * The NAMESPACE parameter is included in the KVP encoding to allow clients to bind any namespace prefixes that 584 * might be used for qualified names specified in other parameters. For example, the typeName parameter may include 585 * qualified names of the form namespace prefix:name. 586 * <p> 587 * The value of the NAMESPACE parameter is separated list of character strings of the form [namespace 588 * prefix:]namespace url. Not including the name namespace prefix binds the specified URL to the default namespace. 589 * As in XML, only one default namespace may be bound. 590 * 591 * @return the mapped namespaces or <code>null</code> if all qualified names are in default namespace. 592 * 593 */ 594 public Map<String, URI> getNamespace() { 595 return this.namespace; 596 } 597 598 /** 599 * The resultType parameter may have the values HITS, RESULTS or VALIDATE and is used to indicate whether the 600 * catalogue service returns the full result set, the number of hits the query found or validates the request. 601 * <p> 602 * If the resultType parameter is set to HITS, the catalogue service shall return an empty 603 * <GetRecordsResponse>element with the numberOfRecordsMatched attribute set to indicate the number of hits. 604 * The other attributes may be set to zero or not specified at all if they are optional. 605 * <p> 606 * If the resultType parameter is set to HITS, then the values for the parameters outputFormat and outputSchema (if 607 * specified) shall be ignored since no actual records will be returned 608 * <p> 609 * If the resultType parameter is set to RESULTS, the catalogue service should generate a complete response with the 610 * <GetRecordsResponse>element containing the result set for the request 611 * <p> 612 * If the resultType parameter is set to VALIDATE, the catalogue service shall validate the request and return an 613 * empty <GetRecordsResponse>. All mandatory attributes may be given a value of zero and all optional 614 * attributes may be omitted. If the request does not validate then a service exception shall be raised 615 * 616 * @return one of HITS, RESULTS or VALIDATE 617 * 618 */ 619 public RESULT_TYPE getResultType() { 620 return this.resultType; 621 } 622 623 /** 624 * The resultType parameter may have the values HITS, RESULTS or VALIDATE and is used to indicate whether the 625 * catalogue service returns the full result set, the number of hits the query found or validates the request. 626 * <p> 627 * If the resultType parameter is set to HITS, the catalogue service shall return an empty 628 * <GetRecordsResponse>element with the numberOfRecordsMatched attribute set to indicate the number of hits. 629 * The other attributes may be set to zero or not specified at all if they are optional. 630 * <p> 631 * If the resultType parameter is set to HITS, then the values for the parameters outputFormat and outputSchema (if 632 * specified) shall be ignored since no actual records will be returned 633 * <p> 634 * If the resultType parameter is set to RESULTS, the catalogue service should generate a complete response with the 635 * <GetRecordsResponse>element containing the result set for the request 636 * <p> 637 * If the resultType parameter is set to VALIDATE, the catalogue service shall validate the request and return an 638 * empty <GetRecordsResponse>. All mandatory attributes may be given a value of zero and all optional 639 * attributes may be omitted. If the request does not validate then a service exception shall be raised 640 * 641 * @return the resulttype as a String, one of "HITS", "VALIDATE" or "RESULTS" 642 * 643 */ 644 public String getResultTypeAsString() { 645 String resultTypeString = null; 646 switch ( this.resultType ) { 647 case HITS: { 648 resultTypeString = RESULT_TYPE_STRING_HITS; 649 break; 650 } 651 case RESULTS: { 652 resultTypeString = RESULT_TYPE_STRING_RESULTS; 653 break; 654 } 655 case VALIDATE: { 656 resultTypeString = RESULT_TYPE_STRING_VALIDATE; 657 break; 658 } 659 } 660 return resultTypeString; 661 } 662 663 /** 664 * sets the resultType of a request. This may be useful to perform a request first with resultType = HITS to 665 * determine the total number of records matching a query and afterwards performing the same request with resultType 666 * = RESULTS (and maxRecords < number of matched records). 667 * 668 * @param resultType 669 */ 670 public void setResultType( RESULT_TYPE resultType ) { 671 this.resultType = resultType; 672 } 673 674 /** 675 * setst the startPosition of a request. This may be useful to perform a request first with startPosition = 0 to 676 * determine the total number of records matching a query. 677 * 678 * @param startPosition 679 */ 680 public void setStartPosition( int startPosition ) { 681 this.startPosition = startPosition; 682 } 683 684 /** 685 * returns <= 0 if no distributed search shall be performed. otherwise the recursion depht is returned. 686 * <p> 687 * The hopCount parameter controls the distributed query behaviour by limiting the maximum number of message hops 688 * before the search is terminated. Each catalogue decrements this value by one when the request is received and 689 * does not propagate the request if the hopCount=0 690 * 691 * @return <= 0 if no distributed search shall be performed. otherwise the recursion depht is returned. 692 * 693 */ 694 public int getHopCount() { 695 return this.hopCount; 696 } 697 698 /** 699 * Value is Mime type;The only value that must be supported is text/xml. Other suppored values may include text/html 700 * and text/plain 701 * <p> 702 * The outputFormat parameter is used to control the format of the output that is generated in response to a 703 * GetRecords request. Its value must be a MIME type. The default value, "text/xml", means that the output shall be 704 * an XML document. All registries shall at least support XML as an output format. Other output formats may be 705 * supported and may include output formats such as TEXT (MIME type text/plain), or HTML (MIME type text/html). The 706 * list of output formats that a CSW instance provides must be advertised in the Capabilities document 707 * <p> 708 * In the case where the output format is text/xml, the CSW must generate an XML document that validates against a 709 * schema document that is specified in the output document via the xsi:schemaLocation attribute defined in XML 710 * 711 * @return Value is a Mime type 712 * 713 */ 714 public String getOutputFormat() { 715 return this.outputFormat; 716 } 717 718 /** 719 * The outputSchema parameter is used to indicate the schema of the output that is generated in response to a 720 * GetRecords request. The default value for this parameter shall be OGCCORE indicating that the schema for the core 721 * returnable properties shall be used. Application profiles may define additional values for outputSchema and may 722 * redefine the default value but all profiles must support the value OGCCORE 723 * <p> 724 * Examples values for the outputSchema parameter might be FGDC, or ISO19119, ISO19139 or ANZLIC. The list of 725 * supported output schemas must be advertised in the capabilities document 726 * 727 * @return The default value for this parameter shall be OGCCORE 728 * 729 */ 730 public String getOutputSchema() { 731 return this.outputSchema; 732 } 733 734 /** 735 * @return the number of the first returned dataset. Zero or one (Optional)Default value is 1. If startPosition > 736 * the number of datasets satisfying the constraint, no dataset will be returned 737 * 738 */ 739 public int getStartPosition() { 740 return this.startPosition; 741 } 742 743 /** 744 * @return The maxRecords parameter. It is used to define the maximum number of records that should be returned from 745 * the result set of a query. If it is not specified, then 10 records shall be returned. If its value is set 746 * to zero, then the behavior is indentical to setting "resultType=HITS" 747 * 748 */ 749 public int getMaxRecords() { 750 return this.maxRecords; 751 } 752 753 /** 754 * @return the location of a response adress to which an asynchronous result may be sent. 755 */ 756 public URI getResponseHandler() { 757 return responseHandler; 758 } 759 760 /** 761 * @return the query object. 762 */ 763 public Query getQuery() { 764 return query; 765 } 766 767 /** 768 * @see #getQuery() 769 * @param query 770 */ 771 public void setQuery( Query query ) { 772 this.query = query; 773 } 774 775 /** 776 * The <code>RESULT_TYPE</code> a simple enum which defines some result values of a GetRecord. 777 * 778 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 779 * 780 * @author last edited by: $Author: lbuesching $ 781 * 782 * @version $Revision: 28346 $, $Date: 2010-11-23 12:08:02 +0100 (Di, 23 Nov 2010) $ 783 * 784 */ 785 786 public static enum RESULT_TYPE { 787 /** 788 * HITS, the catalogue service shall return an empty <GetRecordsResponse>element with the 789 * numberOfRecordsMatched attribute set to indicate the number of hits 790 */ 791 HITS, 792 /** 793 * VALIDATE, the catalogue service shall validate the request 794 */ 795 VALIDATE, 796 /** 797 * RESULTS, the catalogue service should generate a complete response with the <GetRecordsResponse>element 798 * containing the result set for the request 799 */ 800 RESULTS 801 } 802 }