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 }