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 &quote;query&quote; and &quote;present&quote; 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 &quote;query&quote; and &quote;present&quote; 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    }