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 }