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