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 }