001 //$HeadURL: svn+ssh://developername@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/ogcwebservices/csw/discovery/Discovery.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.IOException;
039 import java.io.StringReader;
040 import java.io.StringWriter;
041 import java.net.MalformedURLException;
042 import java.net.URI;
043 import java.util.HashMap;
044 import java.util.Iterator;
045 import java.util.List;
046 import java.util.Map;
047
048 import javax.xml.transform.TransformerException;
049
050 import org.deegree.datatypes.QualifiedName;
051 import org.deegree.enterprise.servlet.OGCServletController;
052 import org.deegree.framework.log.ILogger;
053 import org.deegree.framework.log.LoggerFactory;
054 import org.deegree.framework.util.StringTools;
055 import org.deegree.framework.util.TimeTools;
056 import org.deegree.framework.xml.XMLFragment;
057 import org.deegree.framework.xml.XMLParsingException;
058 import org.deegree.framework.xml.XSLTDocument;
059 import org.deegree.io.datastore.PropertyPathResolvingException;
060 import org.deegree.model.feature.Feature;
061 import org.deegree.model.feature.FeatureCollection;
062 import org.deegree.model.feature.FeatureProperty;
063 import org.deegree.model.filterencoding.ComplexFilter;
064 import org.deegree.model.filterencoding.Expression;
065 import org.deegree.model.filterencoding.Literal;
066 import org.deegree.model.filterencoding.OperationDefines;
067 import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
068 import org.deegree.model.filterencoding.PropertyName;
069 import org.deegree.ogcbase.PropertyPath;
070 import org.deegree.ogcbase.PropertyPathFactory;
071 import org.deegree.ogcwebservices.InvalidParameterValueException;
072 import org.deegree.ogcwebservices.OGCWebServiceException;
073 import org.deegree.ogcwebservices.csw.CSWExceptionCode;
074 import org.deegree.ogcwebservices.csw.configuration.CatalogueConfiguration;
075 import org.deegree.ogcwebservices.csw.discovery.GetRecords.RESULT_TYPE;
076 import org.deegree.ogcwebservices.wfs.WFService;
077 import org.deegree.ogcwebservices.wfs.operation.FeatureResult;
078 import org.deegree.ogcwebservices.wfs.operation.GetFeature;
079 import org.deegree.ogcwebservices.wfs.operation.GetFeatureDocument;
080 import org.deegree.ogcwebservices.wfs.operation.Query;
081 import org.w3c.dom.Document;
082 import org.w3c.dom.NamedNodeMap;
083 import org.w3c.dom.Node;
084 import org.w3c.dom.NodeList;
085 import org.xml.sax.SAXException;
086
087 /**
088 * The Discovery class allows clients to discover resources registered in a catalogue, by providing four operations
089 * named <code>query</code>,<code>present</code>, <code>describeRecordType</code>, and <code>getDomain</code>. This
090 * class has a required association from the Catalogue Service class, and is thus always implemented by all Catalogue
091 * Service implementations. The Session class can be included with the Discovery class, in associations with the
092 * Catalogue Service class. The "e;query"e; and "e;present"e; operations may be executed in a session or
093 * stateful context. If a session context exists, the dynamic model uses internal states of the session and the allowed
094 * transitions between states. When the "e;query"e; and "e;present"e; state does not include a session
095 * between a server and a client, any memory or shared information between the client and the server may be based on
096 * private understandings or features available in the protocol binding. The describeRecordType and getDomain operations
097 * do not require a session context.
098 *
099 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
100 * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a>
101 *
102 * @author last edited by: $Author: mschneider $
103 *
104 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $
105 *
106 */
107 public class Discovery_2_0_2_blob extends Discovery {
108
109 private static final ILogger LOG = LoggerFactory.getLogger( Discovery_2_0_2_blob.class );
110
111 /**
112 * to be used with reflections
113 */
114 public Discovery_2_0_2_blob() {
115
116 }
117
118 /**
119 * @param wfsService
120 * to contact
121 * @param cswConfiguration
122 * of this service
123 */
124 public Discovery_2_0_2_blob( WFService wfsService, CatalogueConfiguration cswConfiguration ) {
125 init( wfsService, cswConfiguration );
126 }
127
128 private String normalizeOutputSchema( String outputSchema )
129 throws InvalidParameterValueException {
130 LOG.logDebug( "Normalizing following outputschema: " + outputSchema );
131 if ( outputSchema == null ) {
132 LOG.logDebug( "Setting the outputSchema to: " + DEFAULT_SCHEMA );
133 outputSchema = DEFAULT_SCHEMA;
134 } else if ( outputSchema.equalsIgnoreCase( OGC_CORE_SCHEMA ) ) {
135 LOG.logDebug( "Setting the outputSchema to: " + DEFAULT_SCHEMA );
136 outputSchema = DEFAULT_SCHEMA;
137 }
138 outputSchema = outputSchema.toUpperCase();
139 if ( IN_XSL.get( outputSchema ) == null ) {
140 String msg = "Unsupported output schema '" + outputSchema + "' requested. Supported schemas are: ";
141 Iterator<String> it = IN_XSL.keySet().iterator();
142 while ( it.hasNext() ) {
143 msg += it.next();
144 if ( it.hasNext() ) {
145 msg += ", ";
146 } else {
147 msg += ".";
148 }
149 }
150 throw new InvalidParameterValueException( msg );
151 }
152 return outputSchema;
153 }
154
155 private String getAllNamespaceDeclarations( Document doc ) {
156 Map<String, String> nsp = new HashMap<String, String>();
157 nsp = collect( nsp, doc );
158
159 Iterator<String> iter = nsp.keySet().iterator();
160 StringBuffer sb = new StringBuffer( 1000 );
161 while ( iter.hasNext() ) {
162 String s = iter.next();
163 String val = nsp.get( s );
164 sb.append( s ).append( ":" ).append( val );
165 if ( iter.hasNext() ) {
166 sb.append( ';' );
167 }
168 }
169 return sb.toString();
170 }
171
172 private Map<String, String> collect( Map<String, String> nsp, Node node ) {
173 NamedNodeMap nnm = node.getAttributes();
174 if ( nnm != null ) {
175 for ( int i = 0; i < nnm.getLength(); i++ ) {
176 String s = nnm.item( i ).getNodeName();
177 if ( s.startsWith( "xmlns:" ) ) {
178 nsp.put( s.substring( 6, s.length() ), nnm.item( i ).getNodeValue() );
179 }
180 }
181 }
182 NodeList nl = node.getChildNodes();
183 if ( nl != null ) {
184 for ( int i = 0; i < nl.getLength(); i++ ) {
185 collect( nsp, nl.item( i ) );
186 }
187 }
188 return nsp;
189 }
190
191 /**
192 * Performs a <code>GetRecords</code> request.
193 * <p>
194 * This involves the following steps:
195 * <ul>
196 * <li><code>GetRecords</code>-><code>GetRecordsDocument</code></li>
197 * <li><code>GetRecordsDocument</code>-><code>GetFeatureDocument</code> using XSLT</li>
198 * <li><code>GetFeatureDocument</code>-><code>GetFeature</code></li>
199 * <li><code>GetFeature</code> request is performed against the underlying WFS</li>
200 * <li>WFS answers with a <code>FeatureResult</code> object (which contains a <code>FeatureCollection</code>)</li>
201 * <li><code>FeatureCollection</code>-> GMLFeatureCollectionDocument (as a String)</li>
202 * <li>GMLFeatureCollectionDocument</code>-><code>GetRecordsResultDocument</code> using XSLT</li>
203 * <li><code>GetRecordsResultDocument</code>-><code>GetRecordsResult</code></li>
204 * </ul>
205 * </p>
206 *
207 * @param getRecords
208 * @return GetRecordsResult
209 * @throws OGCWebServiceException
210 */
211 public GetRecordsResult query( GetRecords getRecords )
212 throws OGCWebServiceException {
213 GetFeature getFeature = null;
214 XMLFragment getFeatureDocument = null;
215 Object wfsResponse = null;
216 GetRecordsResult cswResponse = null;
217 String outputSchema = normalizeOutputSchema( getRecords.getOutputSchema() );
218
219 // TODO remove this (only necessary because determineRecordsMatched changes the resultType)
220 String resultType = getRecords.getResultTypeAsString();
221
222 XMLFragment getRecordsDocument = new XMLFragment( XMLFactory.export( getRecords ).getRootElement() );
223 try {
224 String nsp = getAllNamespaceDeclarations( getRecordsDocument.getRootElement().getOwnerDocument() );
225 // incoming GetRecord request must be transformed to a GetFeature
226 // request because the underlying 'data engine' of the CSW is a WFS
227 XSLTDocument xslSheet = IN_XSL.get( outputSchema );
228 synchronized ( xslSheet ) {
229 Map<String, String> param = new HashMap<String, String>();
230 param.put( "NSP", nsp );
231 if ( LOG.isDebug() ) {
232 LOG.logDebug( "Input GetRecords request:\n" + getRecordsDocument.getAsPrettyString() );
233 }
234 try {
235 getFeatureDocument = xslSheet.transform( getRecordsDocument, XMLFragment.DEFAULT_URL, null, param );
236 } catch ( MalformedURLException e ) {
237 LOG.logError( e.getMessage(), e );
238 }
239 if ( LOG.isDebug() ) {
240 LOG.logDebugXMLFile( "first", getFeatureDocument );
241 }
242 xslSheet.notifyAll();
243 }
244
245 } catch ( TransformerException e ) {
246 String msg = "Can't transform GetRecord request to WFS GetFeature request: " + e.getMessage();
247 LOG.logError( msg, e );
248 throw new OGCWebServiceException( msg );
249 }
250 try {
251 LOG.logDebug( "Creating the GetFeature bean from the transformed GetRecordsDocument" );
252 getFeature = GetFeature.create( getRecords.getId(), getFeatureDocument.getRootElement() );
253 } catch ( Exception e ) {
254 String msg = "Cannot generate object representation for GetFeature request: " + e.getMessage();
255 LOG.logError( msg, e );
256 throw new OGCWebServiceException( msg );
257 }
258
259 try {
260 LOG.logDebug( "Sending the GetFeature Request to the local wfs" );
261 wfsResponse = wfsResource.doService( getFeature );
262 } catch ( OGCWebServiceException e ) {
263 String msg = "Generated WFS GetFeature request failed: " + e.getMessage();
264 LOG.logError( msg, e );
265 throw new OGCWebServiceException( msg );
266 }
267
268 // theoretical it is possible the result of a GetFeature request is not
269 // an instance of FeatureResult; but this never should happen
270 if ( !( wfsResponse instanceof FeatureResult ) ) {
271 String msg = "Unexpected result type '" + wfsResponse.getClass().getName()
272 + "' from WFS (must be FeatureResult)." + " Maybe a FeatureType is not correctly registered!?";
273 LOG.logError( msg );
274 throw new OGCWebServiceException( msg );
275 }
276
277 FeatureResult featureResult = (FeatureResult) wfsResponse;
278
279 // this never should happen too - but it is possible
280 if ( !( featureResult.getResponse() instanceof FeatureCollection ) ) {
281 String msg = "Unexpected reponse type: '" + featureResult.getResponse().getClass().getName() + " "
282 + featureResult.getResponse().getClass()
283 + "' in FeatureResult of WFS (must be a FeatureCollection).";
284 LOG.logError( msg );
285 throw new OGCWebServiceException( msg );
286 }
287 FeatureCollection featureCollection = (FeatureCollection) featureResult.getResponse();
288
289 try {
290 int numberOfRecordsReturned = featureCollection.size();
291 int numberOfMatchedRecords = 0;
292 if ( getRecords.getResultType().equals( RESULT_TYPE.HITS ) ) {
293 numberOfMatchedRecords = Integer.parseInt( featureCollection.getAttribute( "numberOfFeatures" ) );
294 } else {
295 // if result type does not equal 'HITS', a separate request must
296 // be created and performed to determine how many records match
297 // the query
298 LOG.logDebug( "Going to determine the number of matched records" );
299 numberOfMatchedRecords = determineRecordsMatched( getRecords );
300 }
301
302 int startPosition = getRecords.getStartPosition();
303 if ( startPosition < 1 )
304 startPosition = 1;
305 int nextRecord = startPosition + featureCollection.size();
306
307 HashMap<String, String> params = new HashMap<String, String>();
308 params.put( "REQUEST_ID", getRecords.getId() );
309 if ( numberOfRecordsReturned != 0 ) {
310 params.put( "SEARCH_STATUS", "complete" );
311 } else {
312 params.put( "SEARCH_STATUS", "none" );
313 }
314 params.put( "TIMESTAMP", TimeTools.getISOFormattedTime() );
315 List<QualifiedName> typenames = getRecords.getQuery().getTypeNamesAsList();
316 // this is a bit critical because
317 // a) not the complete result can be validated but just single records
318 // b) it is possible that several different record types are part
319 // of a response that must be validated against different schemas
320 String s = null;
321 String version = getRecords.getVersion();
322 if ( version == null || "".equals( version.trim() ) ) {
323 version = GetRecords.DEFAULT_VERSION;
324 }
325 if ( "2.0.0".equals( version ) ) {
326 s = StringTools.concat( 300, OGCServletController.address, "?service=CSW&version=2.0.0&",
327 "request=DescribeRecord&typeName=", typenames.get( 0 ).getPrefix(), ":",
328 typenames.get( 0 ).getLocalName() );
329 } else {
330 s = StringTools.concat( 300, OGCServletController.address, "?service=CSW&version=" + version + "&",
331 "request=DescribeRecord&typeName=", typenames.get( 0 ).getFormattedString() );
332 }
333 params.put( "VERSION", version );
334 params.put( "RECORD_SCHEMA", s );
335 params.put( "RECORDS_MATCHED", "" + numberOfMatchedRecords );
336 params.put( "RECORDS_RETURNED", "" + numberOfRecordsReturned );
337 params.put( "NEXT_RECORD", "" + nextRecord );
338 String elementSet = getRecords.getQuery().getElementSetName();
339 if ( elementSet == null ) {
340 elementSet = "brief";
341 }
342 params.put( "ELEMENT_SET", elementSet.toLowerCase() );
343 params.put( "RESULT_TYPE", resultType );
344 params.put( "REQUEST_NAME", "GetRecords" );
345
346 Iterator<Feature> iterator = featureCollection.iterator();
347 QualifiedName qn = new QualifiedName( "metadataset", URI.create( "http://www.deegree.org/app" ) );
348 StringBuilder sb = new StringBuilder( 100000 );
349 sb.append( "<Collection numberOfFeatures='1' xmlns:app='http://www.deegree.org/app' xmlns:wfs='http://www.opengis.net/wfs' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:gml='http://www.opengis.net/gml'>" );
350 while ( iterator.hasNext() ) {
351 Feature feature = (Feature) iterator.next();
352 s = feature.getDefaultProperty( qn ).getValue().toString();
353 int idx = s.indexOf( ">" );
354 sb.append( s.substring( idx + 1 ) );
355 }
356 sb.append( "</Collection>" );
357 XMLFragment tmpXML = new XMLFragment();
358 tmpXML.load( new StringReader( sb.toString() ), XMLFragment.DEFAULT_URL );
359
360 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
361 s = new String( tmpXML.getAsString() );
362 LOG.logDebug( s );
363 LOG.logDebugFile( "CSW_GetRecord_FC", "xml", s );
364 }
365 // vice versa to request transforming the feature collection being result
366 // to the GetFeature request must be transformed into a GetRecords result
367 XSLTDocument xslSheet = OUT_XSL.get( outputSchema );
368 XMLFragment resultDocument = xslSheet.transform( new StringReader( tmpXML.getAsString() ), null, null,
369 params );
370 GetRecordsResultDocument cswResponseDocument = new GetRecordsResultDocument();
371 cswResponseDocument.setRootElement( resultDocument.getRootElement() );
372 cswResponse = cswResponseDocument.parseGetRecordsResponse( getRecords );
373 } catch ( IOException e ) {
374 String msg = "Can't transform WFS response (FeatureCollection) to CSW response: " + e.getMessage();
375 LOG.logError( msg, e );
376 throw new OGCWebServiceException( msg );
377
378 } catch ( TransformerException e ) {
379 String msg = "Can't transform WFS response (FeatureCollection) to CSW response: " + e.getMessage();
380 LOG.logError( msg, e );
381 throw new OGCWebServiceException( msg );
382
383 } catch ( Exception e ) {
384 LOG.logError( e );
385 throw new OGCWebServiceException( e.getMessage() );
386 }
387
388 return cswResponse;
389 }
390
391 /**
392 * Performs a <code>GetRecordById</code> request.
393 * <p>
394 * This involves the following steps:
395 * <ul>
396 * <li><code>GetRecordById</code>-><code>GetRecordByIdDocument</code></li>
397 * <li><code>GetRecordByIdDocument</code>-><code>GetFeatureDocument</code> using XSLT</li>
398 * <li><code>GetFeatureDocument</code>-><code>GetFeature</code></li>
399 * <li><code>GetFeature</code> request is performed against the underlying WFS</li>
400 * <li>WFS answers with a <code>FeatureResult</code> object (which contains a <code>FeatureCollection</code>)</li>
401 * <li><code>FeatureCollection</code>-> GMLFeatureCollectionDocument (as a String)</li>
402 * <li>GMLFeatureCollectionDocument</code>-><code>GetRecordsResultDocument</code> using XSLT</li>
403 * <li><code>GetRecordsResultDocument</code>-><code>GetRecordsResult</code></li>
404 * </ul>
405 * </p>
406 *
407 * @param getRecordById
408 * @return The GetRecordByIdResult created from teh given GetRecordById
409 * @throws OGCWebServiceException
410 */
411 public GetRecordByIdResult query( GetRecordById getRecordById )
412 throws OGCWebServiceException {
413
414 GetFeature getFeature = null;
415 XMLFragment getFeatureDocument = null;
416 Object wfsResponse = null;
417 GetRecordByIdResult cswResponse = null;
418 String outputSchema = cswConfiguration.getDeegreeParams().getDefaultOutputSchema();
419
420 XMLFragment getRecordsDocument = new XMLFragment( XMLFactory.export( getRecordById ).getRootElement() );
421 try {
422 XSLTDocument xslSheet = IN_XSL.get( outputSchema.toUpperCase() );
423 getFeatureDocument = xslSheet.transform( getRecordsDocument );
424 LOG.logDebug( "Generated WFS GetFeature request:\n" + getFeatureDocument );
425 } catch ( TransformerException e ) {
426 String msg = "Can't transform GetRecordById request to WFS GetFeature request: " + e.getMessage();
427 LOG.logError( msg, e );
428 throw new OGCWebServiceException( msg );
429 }
430
431 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
432 StringWriter sw = new StringWriter( 5000 );
433 getFeatureDocument.write( sw );
434 LOG.logDebug( sw.getBuffer().toString() );
435 }
436 System.out.println( getFeatureDocument.getAsPrettyString() );
437 try {
438 getFeature = GetFeature.create( getRecordById.getId(), getFeatureDocument.getRootElement() );
439 } catch ( Exception e ) {
440 String msg = "Cannot generate object representation for GetFeature request: " + e.getMessage();
441 LOG.logError( msg, e );
442 throw new OGCWebServiceException( msg );
443 }
444
445 try {
446 wfsResponse = wfsResource.doService( getFeature );
447 } catch ( OGCWebServiceException e ) {
448 String msg = "Generated WFS GetFeature request failed: " + e.getMessage();
449 LOG.logError( msg, e );
450 throw new OGCWebServiceException( msg );
451 }
452
453 if ( !( wfsResponse instanceof FeatureResult ) ) {
454 String msg = "Unexpected result type '" + wfsResponse.getClass().getName()
455 + "' from WFS (must be FeatureResult)." + " Maybe a FeatureType is not correctly registered!?";
456 LOG.logError( msg );
457 throw new OGCWebServiceException( msg );
458 }
459
460 FeatureResult featureResult = (FeatureResult) wfsResponse;
461
462 if ( !( featureResult.getResponse() instanceof FeatureCollection ) ) {
463 String msg = "Unexpected reponse type: '" + featureResult.getResponse().getClass().getName() + " "
464 + featureResult.getResponse().getClass()
465 + "' in FeatureResult of WFS (must be a FeatureCollection).";
466 LOG.logError( msg );
467 throw new OGCWebServiceException( msg );
468 }
469 FeatureCollection featureCollection = (FeatureCollection) featureResult.getResponse();
470
471 try {
472 int numberOfMatchedRecords = featureCollection == null ? 0 : featureCollection.size();
473 int startPosition = 1;
474 long maxRecords = Integer.MAX_VALUE;
475 long numberOfRecordsReturned = startPosition + maxRecords < numberOfMatchedRecords ? maxRecords
476 : numberOfMatchedRecords
477 - startPosition + 1;
478 long nextRecord = numberOfRecordsReturned + startPosition > numberOfMatchedRecords ? 0
479 : numberOfRecordsReturned
480 + startPosition;
481
482 HashMap<String, String> params = new HashMap<String, String>();
483 params.put( "REQUEST_ID", getRecordById.getId() );
484 if ( numberOfRecordsReturned != 0 ) {
485 params.put( "SEARCH_STATUS", "complete" );
486 } else {
487 params.put( "SEARCH_STATUS", "none" );
488 }
489 params.put( "TIMESTAMP", TimeTools.getISOFormattedTime() );
490 String s = OGCServletController.address + "?service=CSW&version=2.0.0&request=DescribeRecord";
491 params.put( "RECORD_SCHEMA", s );
492 params.put( "RECORDS_MATCHED", "" + numberOfMatchedRecords );
493 params.put( "RECORDS_RETURNED", "" + numberOfRecordsReturned );
494 params.put( "NEXT_RECORD", "" + nextRecord );
495 params.put( "ELEMENT_SET", "full" );
496 params.put( "REQUEST_NAME", "GetRecordById" );
497
498 featureCollection.setAttribute( "byID", "true" );
499 Iterator<Feature> iterator = featureCollection.iterator();
500 QualifiedName qn = new QualifiedName( "metadataset", URI.create( "http://www.deegree.org/app" ) );
501 StringBuilder sb = new StringBuilder( 100000 );
502 sb.append( "<Collection numberOfFeatures='1' xmlns:app='http://www.deegree.org/app' xmlns:wfs='http://www.opengis.net/wfs' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:gml='http://www.opengis.net/gml'>" );
503 while ( iterator.hasNext() ) {
504 Feature feature = (Feature) iterator.next();
505 s = feature.getDefaultProperty( qn ).getValue().toString();
506 int idx = s.indexOf( "><" );
507 sb.append( s.substring( idx + 1 ) );
508 }
509 sb.append( "</Collection>" );
510 XMLFragment tmpXML = new XMLFragment();
511 tmpXML.load( new StringReader( sb.toString() ), XMLFragment.DEFAULT_URL );
512
513 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
514 s = new String( tmpXML.getAsString() );
515 LOG.logDebug( s );
516 LOG.logDebugFile( "CSW_GetRecord_FC", "xml", s );
517 }
518 // vice versa to request transforming the feature collection being result
519 // to the GetFeature request must be transformed into a GetRecords result
520 XSLTDocument xslSheet = OUT_XSL.get( outputSchema.toUpperCase() );
521
522 XMLFragment resultDocument = xslSheet.transform( new StringReader( tmpXML.getAsString() ), null, null,
523 params );
524 GetRecordByIdResultDocument cswResponseDocument = new GetRecordByIdResultDocument();
525 cswResponseDocument.setRootElement( resultDocument.getRootElement() );
526 cswResponse = cswResponseDocument.parseGetRecordByIdResponse( getRecordById );
527 } catch ( Exception e ) {
528 e.printStackTrace();
529 String msg = "Can't transform WFS response (FeatureCollection) " + "to CSW response: " + e.getMessage();
530 LOG.logError( msg, e );
531 throw new OGCWebServiceException( msg );
532 }
533
534 return cswResponse;
535 }
536
537 /**
538 * Contacts the wfsResource to find a rim:ExtrinsicObject which contains the
539 * {@link GetRepositoryItem#getRepositoryItemID()} and retrieves it's
540 * app:RegistryObject/app:extrinsicObject/app:ExtrinsicObject/app:object. The value in this property will then be
541 * written to the response stream (e.g. sent to the requester).
542 *
543 * @param request
544 * the created OGCRequest
545 * @return the repository item response
546 * @throws OGCWebServiceException
547 */
548 public GetRepositoryItemResponse guery( GetRepositoryItem request )
549 throws OGCWebServiceException {
550 // Some properterypaths which are used for the creation of a complex filter.
551 URI appURI = URI.create( "http://www.deegree.org/app" );
552
553 QualifiedName registryObject = new QualifiedName( "app", "RegistryObject", appURI );
554 Expression iduriExpr = new PropertyName( new QualifiedName( "app", "iduri", appURI ) );
555 Expression idLiteral = new Literal( request.getRepositoryItemID().toString() );
556 PropertyIsCOMPOperation idOperator = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
557 iduriExpr, idLiteral );
558 ComplexFilter idFilter = new ComplexFilter( idOperator );
559
560 FeatureCollection featureCollectionOnId = null;
561 try {
562 FeatureResult fr = sendWFSGetFeature( registryObject, idFilter );
563 if ( fr != null ) {
564 featureCollectionOnId = (FeatureCollection) fr.getResponse();
565 }
566 } catch ( OGCWebServiceException e ) {
567 throw new OGCWebServiceException( "The requested item " + request.getRepositoryItemID()
568 + " could not be retrieved from the csw backend: " + e.getMessage(),
569 CSWExceptionCode.WRS_NOTFOUND );
570 }
571 if ( featureCollectionOnId == null ) {
572 throw new OGCWebServiceException( "The requested item " + request.getRepositoryItemID()
573 + " could not be retrieved from the csw backend.",
574 CSWExceptionCode.WRS_NOTFOUND );
575 }
576 String numbOfFeatures = featureCollectionOnId.getAttribute( "numberOfFeatures" );
577 int featureCount = 0;
578 try {
579 featureCount = Integer.parseInt( numbOfFeatures );
580 LOG.logDebug( "the number of features in the GetFeature was: " + featureCount );
581 } catch ( NumberFormatException nfe ) {
582 // nottin
583 }
584
585 GetRepositoryItemResponse response = null;
586 // Check the number of hits we've found, if the id allready exists it means we want to set the status of the
587 // object to invalid.
588 // String newID = id;
589 if ( featureCount > 1 ) {
590 throw new OGCWebServiceException( "The id : " + request.getRepositoryItemID()
591 + " is not unique. This repositoryItem can therefore not be retrieved.",
592 CSWExceptionCode.WRS_NOTFOUND );
593 } else if ( featureCount == 0 ) {
594 throw new OGCWebServiceException(
595 "The id: "
596 + request.getRepositoryItemID()
597 + " corresponds to no rim:ExtrinsicObject. This repositoryItem can therefore not be retrieved.",
598 CSWExceptionCode.WRS_NOTFOUND );
599
600 } else {
601 Feature f = featureCollectionOnId.getFeature( 0 );
602 if ( f != null ) {
603 PropertyPath pp = PropertyPathFactory.createPropertyPath( registryObject );
604 pp.append( PropertyPathFactory.createPropertyPathStep( new QualifiedName( "app", "extrinsicObject",
605 appURI ) ) );
606 pp.append( PropertyPathFactory.createPropertyPathStep( new QualifiedName( "app", "ExtrinsicObject",
607 appURI ) ) );
608 pp.append( PropertyPathFactory.createPropertyPathStep( new QualifiedName( "app", "object", appURI ) ) );
609 FeatureProperty retrievedObject = null;
610 try {
611 retrievedObject = f.getDefaultProperty( pp );
612 } catch ( PropertyPathResolvingException ppre ) {
613 throw new OGCWebServiceException(
614 "The id: "
615 + request.getRepositoryItemID()
616 + " has no repository item stored, there is nothing to be retrieved.",
617 CSWExceptionCode.WRS_NOTFOUND );
618
619 }
620 if ( retrievedObject == null || retrievedObject.getValue() == null ) {
621 throw new OGCWebServiceException(
622 "The id: "
623 + request.getRepositoryItemID()
624 + " has no repository item stored, there is nothing to be retrieved.",
625 CSWExceptionCode.WRS_NOTFOUND );
626 }
627
628 String repositoryItem = (String) retrievedObject.getValue();
629 LOG.logDebug( "found the repositoryItem: " + repositoryItem );
630
631 pp = PropertyPathFactory.createPropertyPath( registryObject );
632 pp.append( PropertyPathFactory.createPropertyPathStep( new QualifiedName( "app", "extrinsicObject",
633 appURI ) ) );
634 pp.append( PropertyPathFactory.createPropertyPathStep( new QualifiedName( "app", "ExtrinsicObject",
635 appURI ) ) );
636 pp.append( PropertyPathFactory.createPropertyPathStep( new QualifiedName( "app", "mimeType", appURI ) ) );
637 FeatureProperty mimeType = null;
638 try {
639 mimeType = f.getDefaultProperty( pp );
640 } catch ( PropertyPathResolvingException ppre ) {
641 LOG.logError( "The mimetype value (of the GetRepositoryItem: " + request.getRepositoryItemID()
642 + ") was not set, setting content header to 'application/xml' " );
643 }
644 if ( mimeType == null || mimeType.getValue() == null ) {
645 LOG.logError( "The mimetype value (of the GetRepositoryItem: " + request.getRepositoryItemID()
646 + ") was not set, setting content header to 'application/xml' " );
647 }
648
649 try {
650 XMLFragment itemFrag = new XMLFragment( new StringReader( repositoryItem ), XMLFragment.DEFAULT_URL );
651 response = new GetRepositoryItemResponse( request.getId(), request.getRepositoryItemID(), itemFrag );
652 } catch ( SAXException e ) {
653 LOG.logError( e.getLocalizedMessage(), e );
654 throw new OGCWebServiceException( null, "The resulting repository item was not of type xml: "
655 + e.getLocalizedMessage(),
656 CSWExceptionCode.NOAPPLICABLECODE );
657 } catch ( IOException e ) {
658 LOG.logError( e.getLocalizedMessage(), e );
659 throw new OGCWebServiceException( null, "The resulting repository item was not of type xml: "
660 + e.getLocalizedMessage(),
661 CSWExceptionCode.NOAPPLICABLECODE );
662 }
663 }
664 }
665 return response;
666 }
667
668 /**
669 * Generates and sends a GetFeature to the wfsResource.
670 *
671 * @param registryObject
672 * the QName of the registryObject e.g. app:RegistryObject (xmlns:app="http://www.deegree.org/app")
673 * @param filter
674 * a ogc:Filter representation containing the (app:iduri isequal requestID) mapping.
675 * @return the FeatureResult of the given filter or <code>null</code> if something went wrong.
676 * @throws OGCWebServiceException
677 * thrown if the wfsResource encounters any problems
678 */
679 private FeatureResult sendWFSGetFeature( QualifiedName registryObject, ComplexFilter filter )
680 throws OGCWebServiceException {
681 Query q = Query.create( registryObject, filter );
682 GetFeature gfwl = GetFeature.create( "1.1.0", "0",
683 org.deegree.ogcwebservices.wfs.operation.GetFeature.RESULT_TYPE.RESULTS,
684 "text/xml; subtype=gml/3.1.1", "no_handle", -1, 0, -1, -1,
685 new Query[] { q } );
686 // GetFeature gfwl = GetFeature.create( "1.1.0", "0", RESULT_TYPE.RESULTS, "text/xml; subtype=gml/3.1.1",
687 // "no_handle", -1, 0, -1, -1, new Query[] { q } );
688 if ( LOG.isDebug() ) {
689 try {
690 GetFeatureDocument gd = org.deegree.ogcwebservices.wfs.XMLFactory.export( gfwl );
691 LOG.logDebug( " The getFeature:\n" + gd.getAsPrettyString() );
692 } catch ( IOException e ) {
693 LOG.logError( "CSW (Ebrim) GetRepositoryItem-Filter: An error occurred while trying to get a debugging output for the generated GetFeatureDocument: "
694 + e.getMessage() );
695 } catch ( XMLParsingException e ) {
696 LOG.logError( "CSW (Ebrim) GetRepositoryItem-Filter: An error occurred while trying to get a debugging output for the generated GetFeatureDocument: "
697 + e.getMessage() );
698 }
699 }
700
701 Object response = wfsResource.doService( gfwl );
702 if ( response instanceof FeatureResult ) {
703 return (FeatureResult) response;
704 }
705 throw new OGCWebServiceException( "No valid response from the backend while retrieving GetRepositoryItem." );
706 // LOG.logDebug( "Got no valid response from the wfsResource, returning null" );
707 // return null;
708 }
709
710 }