001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/ogcwebservices/csw/discovery/XMLFactory.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 static org.deegree.ogcbase.CommonNamespaces.CSW202NS;
039    import static org.deegree.ogcbase.CommonNamespaces.CSWNS;
040    
041    import java.net.URI;
042    import java.net.URISyntaxException;
043    import java.util.Date;
044    import java.util.HashMap;
045    import java.util.List;
046    import java.util.Map;
047    import java.util.Set;
048    
049    import org.deegree.datatypes.QualifiedName;
050    import org.deegree.framework.log.ILogger;
051    import org.deegree.framework.log.LoggerFactory;
052    import org.deegree.framework.util.StringTools;
053    import org.deegree.framework.util.TimeTools;
054    import org.deegree.framework.xml.XMLException;
055    import org.deegree.framework.xml.XMLTools;
056    import org.deegree.ogcbase.CommonNamespaces;
057    import org.deegree.ogcbase.PropertyPath;
058    import org.deegree.ogcbase.SortProperty;
059    import org.deegree.ogcwebservices.InvalidParameterValueException;
060    import org.deegree.ogcwebservices.OGCWebServiceException;
061    import org.deegree.ogcwebservices.csw.CSWExceptionCode;
062    import org.deegree.ogcwebservices.csw.CSWPropertiesAccess;
063    import org.w3c.dom.Attr;
064    import org.w3c.dom.Document;
065    import org.w3c.dom.Element;
066    import org.w3c.dom.NamedNodeMap;
067    import org.w3c.dom.Node;
068    import org.w3c.dom.NodeList;
069    
070    /**
071     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
072     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
073     * @author last edited by: $Author: apoth $
074     *
075     * @version $Revision: 25619 $, $Date: 2010-08-02 08:17:24 +0200 (Mo, 02. Aug 2010) $
076     */
077    public class XMLFactory extends org.deegree.ogcbase.XMLFactory {
078    
079        private static final ILogger LOG = LoggerFactory.getLogger( XMLFactory.class );
080    
081        /**
082         * Exports a <code>GetRecordsResponse</code> instance to a
083         * <code>GetRecordsResponseDocument</code>.
084         *
085         * @param response
086         * @return DOM representation of the <code>GetRecordsResponse</code>
087         * @throws XMLException
088         *             if XML template could not be loaded
089         */
090        public static GetRecordsResultDocument export( GetRecordsResult response )
091                                throws XMLException {
092            // 'version'-attribute
093            String version = response.getRequest().getVersion();
094            if ( version == null || "".equals( version.trim() ) ) {
095                version = "2.0.0";
096            }
097    
098            GetRecordsResultDocument responseDocument = new GetRecordsResultDocument( version );
099    
100            try {
101                Element rootElement = responseDocument.getRootElement();
102                Document doc = rootElement.getOwnerDocument();
103    
104                // set required namespaces
105                Element recordRespRoot = response.getSearchResults().getRecords().getOwnerDocument().getDocumentElement();
106                NamedNodeMap nnm = recordRespRoot.getAttributes();
107                for ( int i = 0; i < nnm.getLength(); i++ ) {
108                    Node node = nnm.item( i );
109                    if ( node instanceof Attr ) {
110                        rootElement.setAttribute( node.getNodeName(), node.getNodeValue() );
111                    }
112                }
113    
114                rootElement.setAttribute( "version", version );
115                String namespace = ( version.equals( "2.0.2" ) ? CSW202NS.toString() : CSWNS.toString() );
116    
117                // 'RequestId'-element (optional)
118                if ( response.getRequest().getId() != null ) {
119                    Element requestIdElement = doc.createElementNS( namespace, "csw:RequestId" );
120                    requestIdElement.appendChild( doc.createTextNode( response.getRequest().getId() ) );
121                    rootElement.appendChild( requestIdElement );
122                }
123    
124                // 'SearchStatus'-element (required)
125                Element searchStatusElement = doc.createElementNS( namespace, "csw:SearchStatus" );
126                // 'status'-attribute (required)
127                if ( !version.equals( "2.0.2" ) ) {
128                    searchStatusElement.setAttribute( "status", response.getSearchStatus().getStatus() );
129                }
130                // 'timestamp'-attribute (optional)
131                if ( response.getSearchStatus().getTimestamp() != null ) {
132                    Date date = response.getSearchStatus().getTimestamp();
133                    String time = TimeTools.getISOFormattedTime( date );
134                    searchStatusElement.setAttribute( "timestamp", time );
135                }
136                rootElement.appendChild( searchStatusElement );
137    
138                // 'SeachResults'-element (required)
139                Element searchResultsElement = doc.createElementNS( namespace, "csw:SearchResults" );
140                SearchResults results = response.getSearchResults();
141    
142                // 'resultSetId'-attribute (optional)
143                if ( results.getResultSetId() != null ) {
144                    searchResultsElement.setAttribute( "resultSetId", results.getResultSetId().toString() );
145                }
146                // 'elementSet'-attribute (optional)
147                if ( results.getElementSet() != null ) {
148                    searchResultsElement.setAttribute( "elementSet", results.getElementSet().toString() );
149                }
150                // 'recordSchema'-attribute (optional)
151                if ( results.getRecordSchema() != null ) {
152                    searchResultsElement.setAttribute( "recordSchema", results.getRecordSchema().toString() );
153                }
154                // 'numberOfRecordsMatched'-attribute (required)
155                searchResultsElement.setAttribute( "numberOfRecordsMatched", "" + results.getNumberOfRecordsMatched() );
156                // 'numberOfRecordsReturned'-attribute (required)
157                searchResultsElement.setAttribute( "numberOfRecordsReturned", "" + results.getNumberOfRecordsReturned() );
158                // 'nextRecord'-attribute (required)
159                searchResultsElement.setAttribute( "nextRecord", "" + results.getNextRecord() );
160                // 'expires'-attribute (optional)
161                if ( results.getExpires() != null ) {
162                    Date date = results.getExpires();
163                    String time = TimeTools.getISOFormattedTime( date );
164                    searchResultsElement.setAttribute( "expires", time );
165                }
166                // append all children of the records container node
167                NodeList nl = results.getRecords().getChildNodes();
168                for ( int i = 0; i < nl.getLength(); i++ ) {
169                    Node copy = doc.importNode( nl.item( i ), true );
170                    searchResultsElement.appendChild( copy );
171                }
172                rootElement.appendChild( searchResultsElement );
173            } catch ( Exception e ) {
174                LOG.logError( e.getMessage(), e );
175                throw new XMLException( e.getMessage() );
176            }
177            return responseDocument;
178        }
179    
180        /**
181         * Exports a instance of {@link GetRecordByIdResult} to a {@link GetRecordByIdResultDocument}.
182         *
183         * @param response
184         * @return a new document
185         * @throws XMLException
186         */
187        public static GetRecordByIdResultDocument export( GetRecordByIdResult response )
188                                throws XMLException {
189    
190            GetRecordByIdResultDocument doc = new GetRecordByIdResultDocument();
191    
192            try {
193                doc.createEmptyDocument( response.getRequest().getVersion() );
194                Document owner = doc.getRootElement().getOwnerDocument();
195                if ( response != null && response.getRecord() != null ) {
196                    Node copy = owner.importNode( response.getRecord(), true );
197                    doc.getRootElement().appendChild( copy );
198                } else if ( "2.0.2".equals( response.getRequest().getVersion() ) && ( response == null || response.getRecord() == null ) ){
199                    throw new OGCWebServiceException( "A record with the given ID does nor exist in the CSW",
200                                                      CSWExceptionCode.INVALIDPARAMETERVALUE );
201                }
202            } catch ( Exception e ) {
203                LOG.logError( e.getMessage(), e );
204                throw new XMLException( e.getMessage() );
205            }
206    
207            return doc;
208        }
209    
210        /**
211         * Exports a <code>DescribeRecordResponse</code> instance to a
212         * <code>DescribeRecordResponseDocument</code>.
213         *
214         * @param response
215         * @return DOM representation of the <code>DescribeRecordResponse</code>
216         * @throws XMLException
217         *             if XML template could not be loaded
218         */
219        public static DescribeRecordResultDocument export( DescribeRecordResult response )
220                                throws XMLException {
221    
222            DescribeRecordResultDocument responseDocument = new DescribeRecordResultDocument();
223    
224            String ns = response.getRequest().getVersion().equals( "2.0.2" ) ? CSW202NS.toString() : CSWNS.toString();
225    
226            try {
227                responseDocument.createEmptyDocument( response.getRequest().getVersion() );
228                Element rootElement = responseDocument.getRootElement();
229                Document doc = rootElement.getOwnerDocument();
230    
231                // 'SchemaComponent'-elements (required)
232                SchemaComponent[] components = response.getSchemaComponents();
233                for ( int i = 0; i < components.length; i++ ) {
234                    Element schemaComponentElement = doc.createElementNS( ns, "csw:SchemaComponent" );
235    
236                    // 'targetNamespace'-attribute (required)
237                    schemaComponentElement.setAttribute( "targetNamespace", components[i].getTargetNamespace().toString() );
238    
239                    // 'parentSchema'-attribute (optional)
240                    if ( components[i].getParentSchema() != null ) {
241                        schemaComponentElement.setAttribute( "parentSchema", components[i].getParentSchema().toString() );
242                    }
243    
244                    // 'schemaLanguage'-attribute (required)
245                    schemaComponentElement.setAttribute( "schemaLanguage", components[i].getSchemaLanguage().toString() );
246    
247                    XMLTools.insertNodeInto( components[i].getSchema().getRootElement(), schemaComponentElement );
248                    rootElement.appendChild( schemaComponentElement );
249                }
250            } catch ( Exception e ) {
251                LOG.logError( e.getMessage(), e );
252                throw new XMLException( e.getMessage() );
253            }
254            return responseDocument;
255        }
256        
257        /**
258         * Exports a <code>GetRecords</code> instance to a <code>GetRecordsDocument</code>.
259         *
260         * @param request
261         * @return DOM representation of the <code>GetRecords</code>
262         * @throws XMLException
263         *             if some elements could not be appended
264         * @throws OGCWebServiceException
265         *             if an error occurred while creating the xml-representation of the GetRecords
266         *             bean.
267         */
268        public static GetRecordsDocument exportWithVersion( GetRecords request )
269                                throws XMLException, OGCWebServiceException {
270    
271            GetRecordsDocument getRecordsDocument = null;
272    
273            // read class for version depenging parsing of GetRecords request from properties
274            String className = CSWPropertiesAccess.getString( "GetRecords" + request.getVersion() );
275            Class<?> clzz = null;
276            try {
277                clzz = Class.forName( className );
278            } catch ( ClassNotFoundException e ) {
279                LOG.logError( e.getMessage(), e );
280                throw new InvalidParameterValueException( e.getMessage(), e );
281            }
282            try {
283                getRecordsDocument = (GetRecordsDocument) clzz.newInstance();            
284            } catch ( InstantiationException e ) {
285                LOG.logError( e.getMessage(), e );
286                throw new InvalidParameterValueException( e.getMessage(), e );
287            } catch ( IllegalAccessException e ) {
288                LOG.logError( e.getMessage(), e );
289                throw new InvalidParameterValueException( e.getMessage(), e );
290            }
291            
292    //        getRecordsDocument = new GetRecordsDocument();
293            try {
294                getRecordsDocument.createEmptyDocument();
295            } catch ( Exception e ) {
296                throw new XMLException( e.getMessage() );
297            }
298            Element rootElement = getRecordsDocument.getRootElement();
299            Document doc = rootElement.getOwnerDocument();
300    
301            // 'version'-attribute
302            rootElement.setAttribute( "version", request.getVersion() );
303            
304            // 'version'-attribute
305            rootElement.setAttribute( "service", "CSW" );        
306    
307            // 'resultType'-attribute
308            rootElement.setAttribute( "resultType", request.getResultTypeAsString() );
309    
310            // 'outputFormat'-attribute
311            rootElement.setAttribute( "outputFormat", request.getOutputFormat() );
312    
313            // 'outputSchema'-attribute
314            rootElement.setAttribute( "outputSchema", request.getOutputSchema() );
315    
316            // 'startPosition'-attribute
317            rootElement.setAttribute( "startPosition", "" + request.getStartPosition() );
318    
319            // 'maxRecords'-attribute
320            rootElement.setAttribute( "maxRecords", "" + request.getMaxRecords() );
321            
322            URI localCSWNS = CSWNS;
323            if ( request.getVersion().equals( "2.0.2" ) ) {
324                localCSWNS = CSW202NS;
325            }
326    
327            // '<csw:DistributedSearch>'-element
328            if ( request.getHopCount() != -1 ) {
329                Element distributedSearchElement = doc.createElementNS( localCSWNS.toString(), "csw:DistributedSearch" );
330    
331                // 'hopCount'-attribute
332                distributedSearchElement.setAttribute( "hopCount", "" + request.getHopCount() );
333                rootElement.appendChild( distributedSearchElement );
334            }
335    
336            // '<csw:ResponseHandler>'-elements (optional)
337            URI responseHandler = request.getResponseHandler();
338            if ( responseHandler != null ) {
339                Element responseHandlerElement = doc.createElementNS( localCSWNS.toString(), "csw:ResponseHandler" );
340                responseHandlerElement.appendChild( doc.createTextNode( responseHandler.toASCIIString() ) );
341                rootElement.appendChild( responseHandlerElement );
342    
343            }
344    
345            // '<csw:Query>'-elements (required)
346            Query query = request.getQuery();
347            if ( query != null ) {
348                LOG.logDebug( "Adding the csw:Query element to the csw:GetRecords document" );
349                Element queryElement = doc.createElementNS( localCSWNS.toString(), "csw:Query" );
350    
351                // 'typeName'-attribute
352                // Testing for the list of typenames.
353                List<QualifiedName> typeNames = query.getTypeNamesAsList();
354                Map<String, QualifiedName> aliases = new HashMap<String, QualifiedName>(
355                                                                                         query.getDeclaredTypeNameVariables() );
356                if ( typeNames.size() > 0 ) {
357                    appendTypeNamesAttribute( rootElement, queryElement, typeNames, aliases );
358                } else {
359                    String s = StringTools.listToString( query.getTypeNamesAsList(), ',' );
360                    queryElement.setAttribute( "typeNames", s );
361                }
362    
363                // '<csw:ElementSetName>'-element (optional)
364                if ( query.getElementSetName() != null ) {
365                    Element elementSetNameElement = doc.createElementNS( localCSWNS.toString(), "csw:ElementSetName" );
366                    List<QualifiedName> elementSetNameTypeNamesList = query.getElementSetNameTypeNamesList();
367                    if ( query.getElementSetNameVariables() != null && query.getElementSetNameVariables().size() > 0 ) {
368                        throw new OGCWebServiceException(
369                                                          "The elementSetName element in a csw:GetRecords request may not refrerence variables (aka. aliases), aborting request" );
370                    }
371                    if ( elementSetNameTypeNamesList.size() > 0 ) {
372                        appendTypeNamesAttribute( rootElement, elementSetNameElement, elementSetNameTypeNamesList, null );
373                    }
374                    elementSetNameElement.appendChild( doc.createTextNode( query.getElementSetName() ) );
375                    queryElement.appendChild( elementSetNameElement );
376                }
377    
378                // '<csw:ElementName>'-elements (optional)
379                if ( query.getElementNamesAsPropertyPaths() != null ) {
380                    List<PropertyPath> elementNames = query.getElementNamesAsPropertyPaths();
381                    for ( int j = 0; j < elementNames.size(); j++ ) {
382                        Element elementNameElement = doc.createElementNS( localCSWNS.toString(), "csw:ElementName" );
383                        elementNameElement.appendChild( doc.createTextNode( elementNames.get( j ).getAsString() ) );
384                        queryElement.appendChild( elementNameElement );
385                    }
386                }
387    
388                // '<csw:Constraint>'-element (optional)
389                if ( query.getContraint() != null ) {
390                    Element constraintElement = doc.createElementNS( localCSWNS.toString(), "csw:Constraint" );
391                    constraintElement.setAttribute( "version", "1.1.0" );
392                    org.deegree.model.filterencoding.XMLFactory.appendFilter( constraintElement, query.getContraint() );
393                    queryElement.appendChild( constraintElement );
394                }
395    
396                // '<ogc:SortBy>'-element (optional)
397                SortProperty[] sortProperties = query.getSortProperties();
398                if ( sortProperties != null && sortProperties.length != 0 ) {
399                    Element sortByElement = doc.createElementNS( OGCNS.toString(), "ogc:SortBy" );
400    
401                    // '<ogc:SortProperty>'-elements
402                    for ( int j = 0; j < sortProperties.length; j++ ) {
403                        Element sortPropertiesElement = doc.createElementNS( OGCNS.toString(), "ogc:SortProperty" );
404    
405                        // '<ogc:PropertyName>'-element (required)
406                        Element propertyNameElement = doc.createElementNS( OGCNS.toString(), "ogc:PropertyName" );
407                        appendPropertyPath( propertyNameElement, sortProperties[j].getSortProperty() );
408    
409                        // '<ogc:SortOrder>'-element (optional)
410                        Element sortOrderElement = doc.createElementNS( OGCNS.toString(), "ogc:SortOrder" );
411                        Node tn = doc.createTextNode( sortProperties[j].getSortOrder() ? "ASC" : "DESC" );
412                        sortOrderElement.appendChild( tn );
413    
414                        sortPropertiesElement.appendChild( propertyNameElement );
415                        sortPropertiesElement.appendChild( sortOrderElement );
416                        sortByElement.appendChild( sortPropertiesElement );
417                    }
418                    queryElement.appendChild( sortByElement );
419                }
420                rootElement.appendChild( queryElement );
421            }
422            return getRecordsDocument;
423        }
424        
425    
426        /**
427         * Exports a <code>GetRecords</code> instance to a <code>GetRecordsDocument</code>.
428         *
429         * @param request
430         * @return DOM representation of the <code>GetRecords</code>
431         * @throws XMLException
432         *             if some elements could not be appended
433         * @throws OGCWebServiceException
434         *             if an error occurred while creating the xml-representation of the GetRecords
435         *             bean.
436         */
437        public static GetRecordsDocument export( GetRecords request )
438                                throws XMLException, OGCWebServiceException {
439    
440            GetRecordsDocument getRecordsDocument = null;
441            // TODO
442            // switch between CSW versions
443            // read class for version depenging parsing of GetRecords request from properties
444    //        String className = CSWPropertiesAccess.getString( "GetRecords" + request.getVersion() );
445    //        Class<?> clzz = null;
446    //        try {
447    //            clzz = Class.forName( className );
448    //        } catch ( ClassNotFoundException e ) {
449    //            LOG.logError( e.getMessage(), e );
450    //            throw new InvalidParameterValueException( e.getMessage(), e );
451    //        }
452    //        try {
453    //            getRecordsDocument = (GetRecordsDocument) clzz.newInstance();
454    //        } catch ( InstantiationException e ) {
455    //            LOG.logError( e.getMessage(), e );
456    //            throw new InvalidParameterValueException( e.getMessage(), e );
457    //        } catch ( IllegalAccessException e ) {
458    //            LOG.logError( e.getMessage(), e );
459    //            throw new InvalidParameterValueException( e.getMessage(), e );
460    //        }
461            
462            getRecordsDocument = new GetRecordsDocument();
463            try {
464                getRecordsDocument.createEmptyDocument();
465            } catch ( Exception e ) {
466                throw new XMLException( e.getMessage() );
467            }
468            Element rootElement = getRecordsDocument.getRootElement();
469            Document doc = rootElement.getOwnerDocument();
470    
471            // 'version'-attribute
472            rootElement.setAttribute( "version", request.getVersion() );
473    
474            // 'resultType'-attribute
475            rootElement.setAttribute( "resultType", request.getResultTypeAsString() );
476    
477            // 'outputFormat'-attribute
478            rootElement.setAttribute( "outputFormat", request.getOutputFormat() );
479    
480            // 'outputSchema'-attribute
481            rootElement.setAttribute( "outputSchema", request.getOutputSchema() );
482    
483            // 'startPosition'-attribute
484            rootElement.setAttribute( "startPosition", "" + request.getStartPosition() );
485    
486            // 'maxRecords'-attribute
487            rootElement.setAttribute( "maxRecords", "" + request.getMaxRecords() );
488    
489            // '<csw:DistributedSearch>'-element
490            if ( request.getHopCount() != -1 ) {
491                Element distributedSearchElement = doc.createElementNS( CSWNS.toString(), "csw:DistributedSearch" );
492    
493                // 'hopCount'-attribute
494                distributedSearchElement.setAttribute( "hopCount", "" + request.getHopCount() );
495                rootElement.appendChild( distributedSearchElement );
496            }
497    
498            // '<csw:ResponseHandler>'-elements (optional)
499            URI responseHandler = request.getResponseHandler();
500            if ( responseHandler != null ) {
501                Element responseHandlerElement = doc.createElementNS( CSWNS.toString(), "csw:ResponseHandler" );
502                responseHandlerElement.appendChild( doc.createTextNode( responseHandler.toASCIIString() ) );
503                rootElement.appendChild( responseHandlerElement );
504    
505            }
506    
507            // '<csw:Query>'-elements (required)
508            Query query = request.getQuery();
509            if ( query != null ) {
510                LOG.logDebug( "Adding the csw:Query element to the csw:GetRecords document" );
511                Element queryElement = doc.createElementNS( CSWNS.toString(), "csw:Query" );
512    
513                // 'typeName'-attribute
514                // Testing for the list of typenames.
515                List<QualifiedName> typeNames = query.getTypeNamesAsList();
516                Map<String, QualifiedName> aliases = new HashMap<String, QualifiedName>(
517                                                                                         query.getDeclaredTypeNameVariables() );
518                if ( typeNames.size() > 0 ) {
519                    appendTypeNamesAttribute( rootElement, queryElement, typeNames, aliases );
520                } else {
521    
522                    String s = StringTools.arrayToString( query.getTypeNames(), ',' );
523                    queryElement.setAttribute( "typeNames", s );
524                }
525    
526                // '<csw:ElementSetName>'-element (optional)
527                if ( query.getElementSetName() != null ) {
528                    Element elementSetNameElement = doc.createElementNS( CSWNS.toString(), "csw:ElementSetName" );
529                    List<QualifiedName> elementSetNameTypeNamesList = query.getElementSetNameTypeNamesList();
530                    if ( query.getElementSetNameVariables() != null && query.getElementSetNameVariables().size() > 0 ) {
531                        throw new OGCWebServiceException(
532                                                          "The elementSetName element in a csw:GetRecords request may not refrerence variables (aka. aliases), aborting request" );
533                    }
534                    if ( elementSetNameTypeNamesList.size() > 0 ) {
535                        appendTypeNamesAttribute( rootElement, elementSetNameElement, elementSetNameTypeNamesList, null );
536                    }
537                    elementSetNameElement.appendChild( doc.createTextNode( query.getElementSetName() ) );
538                    queryElement.appendChild( elementSetNameElement );
539                }
540    
541                // '<csw:ElementName>'-elements (optional)
542                if ( query.getElementNamesAsPropertyPaths() != null ) {
543                    List<PropertyPath> elementNames = query.getElementNamesAsPropertyPaths();
544                    for ( int j = 0; j < elementNames.size(); j++ ) {
545                        Element elementNameElement = doc.createElementNS( CSWNS.toString(), "csw:ElementName" );
546                        elementNameElement.appendChild( doc.createTextNode( elementNames.get( j ).getAsString() ) );
547                        queryElement.appendChild( elementNameElement );
548                    }
549                }
550    
551                // '<csw:Constraint>'-element (optional)
552                if ( query.getContraint() != null ) {
553                    Element constraintElement = doc.createElementNS( CSWNS.toString(), "csw:Constraint" );
554                    constraintElement.setAttribute( "version", "1.1.0" );
555                    org.deegree.model.filterencoding.XMLFactory.appendFilter( constraintElement, query.getContraint() );
556                    queryElement.appendChild( constraintElement );
557                }
558    
559                // '<ogc:SortBy>'-element (optional)
560                SortProperty[] sortProperties = query.getSortProperties();
561                if ( sortProperties != null && sortProperties.length != 0 ) {
562                    Element sortByElement = doc.createElementNS( OGCNS.toString(), "ogc:SortBy" );
563    
564                    // '<ogc:SortProperty>'-elements
565                    for ( int j = 0; j < sortProperties.length; j++ ) {
566                        Element sortPropertiesElement = doc.createElementNS( OGCNS.toString(), "ogc:SortProperty" );
567    
568                        // '<ogc:PropertyName>'-element (required)
569                        Element propertyNameElement = doc.createElementNS( OGCNS.toString(), "ogc:PropertyName" );
570                        appendPropertyPath( propertyNameElement, sortProperties[j].getSortProperty() );
571    
572                        // '<ogc:SortOrder>'-element (optional)
573                        Element sortOrderElement = doc.createElementNS( OGCNS.toString(), "ogc:SortOrder" );
574                        Node tn = doc.createTextNode( sortProperties[j].getSortOrder() ? "ASC" : "DESC" );
575                        sortOrderElement.appendChild( tn );
576    
577                        sortPropertiesElement.appendChild( propertyNameElement );
578                        sortPropertiesElement.appendChild( sortOrderElement );
579                        sortByElement.appendChild( sortPropertiesElement );
580                    }
581                    queryElement.appendChild( sortByElement );
582                }
583                rootElement.appendChild( queryElement );
584            }
585            return getRecordsDocument;
586        }
587    
588        /**
589         *
590         * @param rootElement
591         *            the first node of the Docuement
592         * @param toBeInserted
593         *            to which the typeNames attribute will be appended
594         * @param typeNames
595         *            to be inserted into the toBeInserted element
596         * @param aliases
597         *            may be <code>null</code>, if not each typeName must have exactly one alias
598         *            defined, which will be inserted after the typename (e.g. typename=$o). If map must
599         *            contain a mapping from variable to qualifiedName (e.g. [o, typeName]);
600         */
601        protected static void appendTypeNamesAttribute( Element rootElement, Element toBeInserted,
602                                                        List<QualifiedName> typeNames, Map<String, QualifiedName> aliases ) {
603            if ( !typeNames.isEmpty() ) {
604                for ( QualifiedName qName : typeNames ) {
605                    LOG.logDebug( "found typeName: " + qName );
606                }
607                LOG.logDebug( "for the element: " + toBeInserted.getNodeName()
608                              + " we are trying to set the typeNames attribute." );
609                StringBuffer sb = new StringBuffer();
610                int count = 0;
611                for ( QualifiedName qName : typeNames ) {
612                    if ( qName.getLocalName() != null ) {
613                        URI ns = qName.getNamespace();
614                        String prefix = qName.getPrefix();
615                        if ( ns != null && prefix != null ) {
616                            URI boundNS = null;
617                            try {
618                                boundNS = XMLTools.getNamespaceForPrefix( prefix, toBeInserted );
619                            } catch ( URISyntaxException e ) {
620                                // why for crying out loud an UriSyntax exception while lookin up stuff
621                                // (without giving
622                                // an
623                                // uri).
624                            }
625                            LOG.logDebug( "ElementSetName/@typeNames: Found the namespace " + boundNS + " for the prefix: "
626                                          + prefix + " from typename (localname) : " + qName.getLocalName() );
627                            if ( boundNS == null ) {
628                                if ( CommonNamespaces.OASIS_EBRIMNS.equals( ns ) ) {
629                                    XMLTools.appendNSBinding( rootElement, "rim", ns );
630                                    LOG.logDebug( toBeInserted.getLocalName()
631                                                  + "/@typeName: While no namespace was bound to the prefix: " + prefix
632                                                  + " the namespace: " + ns
633                                                  + " has been bound to 'rim' in the the root element." );
634                                } else {
635                                    XMLTools.appendNSBinding( rootElement, prefix, ns );
636                                    LOG.logDebug( toBeInserted.getLocalName()
637                                                  + "/@typeName: While no namespace was bound to the prefix: " + prefix
638                                                  + " the namespace: " + ns + " has been bound to '" + prefix
639                                                  + "' in the the root element." );
640                                }
641    
642                            }
643                        }
644                        String typeName = prefix;
645                        if ( typeName != null ) {
646                            typeName += ":" + qName.getLocalName();
647                        }
648                        sb.append( typeName );
649                        if ( aliases != null ) {
650                            if ( aliases.containsValue( qName ) ) {
651                                Set<String> keys = aliases.keySet();
652                                for ( String key : keys ) {
653                                    if ( aliases.get( key ).equals( qName ) ) {
654                                        sb.append( "=" ).append( key );
655                                        aliases.remove( key );
656                                        break;
657                                    }
658                                }
659                            } else if ( aliases.size() > 0 ) {
660                                LOG.logError( "No variable mapping found for typename: "
661                                              + typeName
662                                              + " this may not be, because every single typename must or no typename may have a variable!" );
663                            }
664                        }
665                        if ( ++count < typeNames.size() ) {
666                            sb.append( " " );
667                        }
668                    }
669                }
670                if ( !"null".equals( sb.toString().trim() ) && !"".equals( sb.toString().trim() ) ) {
671                    LOG.logDebug( "for the element: " + toBeInserted.getNodeName()
672                                  + " we are settin the typeNames attribute to: " + sb.toString() );
673                    toBeInserted.setAttribute( "typeNames", sb.toString() );
674                }
675            }
676        }
677    
678        /**
679         * Exports a <code>GetRecordById</code> instance to a <code>GetRecordByIdDocument</code>.
680         *
681         * @param request
682         * @return DOM representation of the <code>GetRecordById</code>
683         * @throws XMLException
684         *             if XML template could not be loaded
685         */
686        public static GetRecordByIdDocument export( GetRecordById request )
687                                throws XMLException {
688    
689            GetRecordByIdDocument getRecordByIdDoc = new GetRecordByIdDocument();
690            try {
691                getRecordByIdDoc.createEmptyDocument();
692            } catch ( Exception e ) {
693                throw new XMLException( e.getMessage() );
694            }
695            Element rootElement = getRecordByIdDoc.getRootElement();
696            Document doc = rootElement.getOwnerDocument();
697    
698            // 'version'-attribute
699            rootElement.setAttribute( "version", request.getVersion() );
700    
701            String[] ids = request.getIds();
702            for ( int i = 0; i < ids.length; i++ ) {
703                Element idElement = doc.createElementNS( CSWNS.toString(), "csw:Id" );
704                idElement.appendChild( doc.createTextNode( ids[i] ) );
705                rootElement.appendChild( idElement );
706            }
707    
708            String elementSetName = request.getElementSetName();
709            if ( elementSetName != null ) {
710                Element esnElement = doc.createElementNS( CSWNS.toString(), "csw:ElementSetName" );
711                esnElement.appendChild( doc.createTextNode( elementSetName ) );
712                rootElement.appendChild( esnElement );
713            }
714    
715            return getRecordByIdDoc;
716        }
717    }