001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/capabilities/WPVSCapabilitiesDocument.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstraße 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041     
042     ---------------------------------------------------------------------------*/
043    
044    package org.deegree.ogcwebservices.wpvs.capabilities;
045    
046    import java.io.IOException;
047    import java.net.MalformedURLException;
048    import java.net.URI;
049    import java.net.URL;
050    import java.util.ArrayList;
051    import java.util.Arrays;
052    import java.util.HashMap;
053    import java.util.List;
054    import java.util.Map;
055    import java.util.Queue;
056    import java.util.concurrent.LinkedBlockingQueue;
057    
058    import org.deegree.datatypes.values.TypedLiteral;
059    import org.deegree.datatypes.values.ValueRange;
060    import org.deegree.datatypes.xlink.SimpleLink;
061    import org.deegree.framework.log.ILogger;
062    import org.deegree.framework.log.LoggerFactory;
063    import org.deegree.framework.util.StringTools;
064    import org.deegree.framework.xml.NamespaceContext;
065    import org.deegree.framework.xml.XMLParsingException;
066    import org.deegree.framework.xml.XMLTools;
067    import org.deegree.i18n.Messages;
068    import org.deegree.model.crs.CRSFactory;
069    import org.deegree.model.crs.CoordinateSystem;
070    import org.deegree.model.crs.UnknownCRSException;
071    import org.deegree.model.metadata.iso19115.Keywords;
072    import org.deegree.model.metadata.iso19115.OnlineResource;
073    import org.deegree.model.spatialschema.Envelope;
074    import org.deegree.model.spatialschema.GeometryFactory;
075    import org.deegree.ogcbase.CommonNamespaces;
076    import org.deegree.ogcwebservices.InvalidParameterValueException;
077    import org.deegree.ogcwebservices.MissingParameterValueException;
078    import org.deegree.ogcwebservices.OGCWebServiceException;
079    import org.deegree.ogcwebservices.getcapabilities.DCPType;
080    import org.deegree.ogcwebservices.getcapabilities.HTTP;
081    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
082    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
083    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
084    import org.deegree.ogcwebservices.getcapabilities.Protocol;
085    import org.deegree.owscommon.OWSCommonCapabilitiesDocument;
086    import org.deegree.owscommon.OWSMetadata;
087    import org.deegree.owscommon.com110.HTTP110;
088    import org.deegree.owscommon.com110.OWSAllowedValues;
089    import org.deegree.owscommon.com110.OWSDomainType110;
090    import org.deegree.owscommon.com110.OWSRequestMethod;
091    import org.deegree.owscommon.com110.Operation110;
092    import org.w3c.dom.Element;
093    import org.w3c.dom.Node;
094    import org.xml.sax.SAXException;
095    
096    /**
097     * This class represents a <code>WPVSCapabilitiesDocument</code> object.
098     * 
099     * @author <a href="mailto:mays@lat-lon.de">Judit Mays</a>
100     * @author last edited by: $Author: rbezema $
101     * 
102     * $Revision: 11466 $, $Date: 2008-04-25 12:17:02 +0200 (Fr, 25 Apr 2008) $
103     * 
104     */
105    public class WPVSCapabilitiesDocument extends OWSCommonCapabilitiesDocument {
106    
107        private ArrayList<String> datasetIdentifiers = new ArrayList<String>();
108    
109        private ArrayList<String> styleIdentifiers = new ArrayList<String>();
110    
111        /**
112         * 
113         */
114        private static final long serialVersionUID = 2633513531080190745L;
115    
116        private static final ILogger LOG = LoggerFactory.getLogger( WPVSCapabilitiesDocument.class );
117    
118        private static final String XML_TEMPLATE = "WPVSCapabilitiesTemplate.xml";
119    
120        private static String PRE_WPVS = CommonNamespaces.WPVS_PREFIX + ":";
121    
122        private static String PRE_OWS = CommonNamespaces.OWS_PREFIX + ":";
123    
124        /**
125         * Creates a skeleton capabilities document that contains the mandatory elements only.
126         * 
127         * @throws IOException
128         * @throws SAXException
129         */
130        public void createEmptyDocument()
131                                         throws IOException, SAXException {
132            URL url = WPVSCapabilitiesDocument.class.getResource( XML_TEMPLATE );
133            if ( url == null ) {
134                throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." );
135            }
136            load( url );
137        }
138    
139        /**
140         * @see org.deegree.ogcwebservices.getcapabilities.OGCCapabilitiesDocument#parseCapabilities()
141         */
142        @Override
143        public OGCCapabilities parseCapabilities()
144                                                  throws InvalidCapabilitiesException {
145            WPVSCapabilities wpvsCapabilities = null;
146    
147            try {
148                wpvsCapabilities = new WPVSCapabilities( parseVersion(),
149                                                         parseUpdateSequence(),
150                                                         getServiceIdentification(),
151                                                         getServiceProvider(),
152                                                         parseOperationsMetadata( null ),
153                                                         null,
154                                                         getDataset() );
155    
156            } catch ( XMLParsingException e ) {
157                throw new InvalidCapabilitiesException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) );
158    
159            } catch ( MissingParameterValueException e ) {
160                throw new InvalidCapabilitiesException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) );
161    
162            } catch ( InvalidParameterValueException e ) {
163                throw new InvalidCapabilitiesException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) );
164    
165            } catch ( OGCWebServiceException e ) {
166                throw new InvalidCapabilitiesException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) );
167            }
168    
169            return wpvsCapabilities;
170        }
171    
172        /**
173         * Gets the <code>Dataset</code> object from the root element of the WPVSCapabilities element.
174         * 
175         * 
176         * @return Returns the Dataset object form root element.
177         * @throws XMLParsingException
178         * @throws OGCWebServiceException
179         * @throws InvalidParameterValueException
180         * @throws MissingParameterValueException
181         */
182        private Dataset getDataset()
183                                    throws XMLParsingException, MissingParameterValueException,
184                                    InvalidParameterValueException, OGCWebServiceException {
185    
186            Element datasetElement = (Element) XMLTools.getRequiredNode( getRootElement(), PRE_WPVS + "Dataset", nsContext );
187            Dataset dataset = parseDataset( datasetElement, null, null, null );
188    
189            return dataset;
190        }
191    
192        /**
193         * Creates and returns a new <code>Dataset</code> object from the given <code>Element</code> and the parent
194         * <code>Dataset</code> object.
195         * 
196         * @param datasetElement
197         * @param parent
198         *            may be null if root node
199         * @param defaultCoordinateSystem
200         * @param defaultElevationModel
201         * @return Returns a new Dataset object.
202         * @throws XMLParsingException
203         * @throws OGCWebServiceException
204         * @throws InvalidParameterValueException
205         */
206        private Dataset parseDataset( Element datasetElement, Dataset parent, CoordinateSystem defaultCoordinateSystem,
207                                      ElevationModel defaultElevationModel )
208                                                                            throws XMLParsingException,
209                                                                            InvalidParameterValueException,
210                                                                            OGCWebServiceException {
211    
212            // attributes are all optional
213            boolean queryable = XMLTools.getNodeAsBoolean( datasetElement, "@queryable", nsContext, false );
214            boolean opaque = XMLTools.getNodeAsBoolean( datasetElement, "@opaque", nsContext, false );
215            boolean noSubsets = XMLTools.getNodeAsBoolean( datasetElement, "@noSubsets", nsContext, false );
216            int fixedWidth = XMLTools.getNodeAsInt( datasetElement, "@fixedWidth", nsContext, 0 );
217            int fixedHeight = XMLTools.getNodeAsInt( datasetElement, "@fixedHeight", nsContext, 0 );
218    
219            // elements
220            String name = XMLTools.getNodeAsString( datasetElement, PRE_WPVS + "Name/text()", nsContext, null );
221            String title = XMLTools.getRequiredNodeAsString( datasetElement, PRE_WPVS + "Title/text()", nsContext );
222            String abstract_ = XMLTools.getNodeAsString( datasetElement, PRE_WPVS + "Abstract/text()", nsContext, null );
223            // keywords == optional
224            Keywords[] keywords = getKeywords( XMLTools.getNodes( datasetElement, PRE_OWS + "Keywords", nsContext ) );
225            // crsstrings == optional
226            String[] crsStrings = XMLTools.getNodesAsStrings( datasetElement, PRE_WPVS + "CRS/text()", nsContext );
227            List<CoordinateSystem> crsList = parseCoordinateSystems( crsStrings );
228            ElevationModel elevationModel = parseElevationModel( datasetElement, defaultElevationModel );
229            // create a default ElevationModel if not exists allready, a little HACK to circumvent the
230            // optional deegree:dataset:ElevationModel mapping onto the mandatory
231            // ogc:dataset:ElevationModel
232            if ( defaultElevationModel == null && elevationModel != null ) {
233                defaultElevationModel = elevationModel;
234                // found an ElevationModel setting it to default
235                // and update the parents of this dataset, until we have the root,
236    
237                if ( parent != null ) {
238                    // first find root parent
239                    Dataset tmpParent = parent;
240                    while ( tmpParent.getParent() != null ) {
241                        tmpParent = tmpParent.getParent();
242                    }
243                    // now iterate over all so far created children to set an default elevationmodel
244                    tmpParent.setElevationModel( defaultElevationModel );
245                    Queue<Dataset> children = new LinkedBlockingQueue<Dataset>( Arrays.asList( tmpParent.getDatasets() ) );
246                    while ( !children.isEmpty() ) {
247                        Dataset child = children.poll();
248                        if ( child != null ) {
249                            child.setElevationModel( defaultElevationModel );
250                            for ( Dataset dataset : child.getDatasets() ) {
251                                children.offer( dataset );
252                            }
253                        }
254                    }
255                }
256            }
257            // now find a defaultcoordinatesystem to use if no crs is given in a child dataset
258            if ( parent == null ) { // root dataset
259                if ( crsList.size() == 0 || crsList.get( 0 ) == null ) {
260                    throw new InvalidCapabilitiesException( Messages.getMessage( "WPVS_NO_TOPLEVEL_DATASET_CRS", title ) );
261                }
262                defaultCoordinateSystem = crsList.get( 0 );
263            }
264    
265            String[] format = XMLTools.getRequiredNodesAsStrings( datasetElement, PRE_WPVS + "Format/text()", nsContext );
266            // wgs84 == mandatory
267            Element boundingBoxElement = (Element) XMLTools.getRequiredNode( datasetElement,
268                                                                             PRE_OWS + "WGS84BoundingBox",
269                                                                             nsContext );
270            Envelope wgs84BoundingBox = getWGS84BoundingBoxType( boundingBoxElement );
271    
272            // boundingboxes can be used to make a more precise specification of the useable area of
273            // this dataset in it's native crs's, the wgs84 bbox can be inaccurate
274            Envelope[] boundingBoxes = getBoundingBoxes( datasetElement, defaultCoordinateSystem );
275    
276            // optional
277            Dimension[] dimensions = parseDimensions( datasetElement );
278    
279            // optional
280            DataProvider dataProvider = parseDataProvider( datasetElement );
281    
282            // mandatory
283            Identifier identifier = parseDatasetIdentifier( datasetElement, PRE_WPVS + "Identifier" );
284    
285            // optional
286            MetaData[] metaData = parseMetaData( datasetElement );
287    
288            // optional
289            DatasetReference[] datasetRefs = parseDatasetReferences( datasetElement );
290    
291            // optional
292            FeatureListReference[] featureListRefs = parseFeatureListReferences( datasetElement );
293    
294            // optional
295            Style[] style = parseStyles( datasetElement );
296    
297            // mandatory
298            double minScaleDenom = XMLTools.getRequiredNodeAsDouble( datasetElement,
299                                                                     PRE_WPVS + "MinimumScaleDenominator/text()",
300                                                                     nsContext );
301            // mandatory
302            double maxScaleDenom = XMLTools.getRequiredNodeAsDouble( datasetElement,
303                                                                     PRE_WPVS + "MaximumScaleDenominator/text()",
304                                                                     nsContext );
305    
306            if ( minScaleDenom > maxScaleDenom ) {
307                throw new InvalidCapabilitiesException( Messages.getMessage( "WPVS_WRONG_SCALE_DENOMINATORS" ) );
308            }
309    
310            // create new root dataset
311            Dataset dataset = new Dataset( queryable,
312                                           opaque,
313                                           noSubsets,
314                                           fixedWidth,
315                                           fixedHeight,
316                                           name,
317                                           title,
318                                           abstract_,
319                                           keywords,
320                                           crsList,
321                                           format,
322                                           wgs84BoundingBox,
323                                           boundingBoxes,
324                                           dimensions,
325                                           dataProvider,
326                                           identifier,
327                                           metaData,
328                                           datasetRefs,
329                                           featureListRefs,
330                                           style,
331                                           minScaleDenom,
332                                           maxScaleDenom,
333                                           null,
334                                           elevationModel,
335                                           null,
336                                           parent );
337    
338            // get child datasets
339            List nl = XMLTools.getNodes( datasetElement, PRE_WPVS + "Dataset", nsContext );
340            Dataset[] childDatasets = new Dataset[nl.size()];
341            for ( int i = 0; i < childDatasets.length; i++ ) {
342                childDatasets[i] = parseDataset( (Element) nl.get( i ),
343                                                 dataset,
344                                                 defaultCoordinateSystem,
345                                                 defaultElevationModel );
346            }
347    
348            // set child datasets
349            dataset.setDatasets( childDatasets );
350    
351            return dataset;
352        }
353    
354        /**
355         * @param coordinateStrings
356         *            the Strings to create the coordinates from
357         * @return a List of coordinatesystems, if no coordinateString were given (null || length==0 ) an emtpy list is
358         *         returned.
359         */
360        protected List<CoordinateSystem> parseCoordinateSystems( String[] coordinateStrings ) {
361            if ( coordinateStrings == null )
362                return new ArrayList<CoordinateSystem>();
363            ArrayList<CoordinateSystem> crsList = new ArrayList<CoordinateSystem>( coordinateStrings.length );
364            for ( String tmpCRS : coordinateStrings ) {
365                try {
366                    CoordinateSystem crs = CRSFactory.create( tmpCRS );
367                    crsList.add( crs );
368                } catch ( UnknownCRSException e ) {
369                    // fail configuration notify the user
370                    LOG.logError( e.getLocalizedMessage(), e );
371                }
372            }
373            return crsList;
374        }
375    
376        /**
377         * Creates and returns a new <code>ElevationModel</code> object from the given <code>Element</code>.
378         * 
379         * This OGC ElevationModel contains only a String. ATTENTION ogc elevation model is mandatory, we IGNORE this and
380         * say it's mandatory.
381         * 
382         * @param datasetElement
383         * @param defaultElevationModel
384         *            the defaultElevationModel will be used if no elevationmodel was defined in this dataset(for example
385         *            the topdatasets dgm-name)
386         * @return Returns the ElevationModel object or <code>null</code> if none defined (optional)
387         * @throws XMLParsingException
388         * @throws InvalidCapabilitiesException
389         */
390        private ElevationModel parseElevationModel( Element datasetElement, ElevationModel defaultElevationModel )
391                                                                                                                  throws XMLParsingException {
392            // ATTENTION ogc elevation model is mandatory, we IGNORE it for the capabilities.
393            String name = XMLTools.getNodeAsString( datasetElement, PRE_WPVS + "ElevationModel/text()", nsContext, null );
394            if ( name == null ) {
395                if ( defaultElevationModel == null ) {
396                    return null;
397                }
398                return defaultElevationModel;
399            }
400            ElevationModel elevationModel = new ElevationModel( name );
401    
402            return elevationModel;
403        }
404    
405        /**
406         * Creates and returns a new array of <code>Style</code> objects from the given <code>Element</code>.
407         * 
408         * @param datasetElement
409         * @return Returns a new array of Style objects or <code>null</code> if none were defined
410         * @throws XMLParsingException
411         * @throws InvalidCapabilitiesException
412         */
413        protected Style[] parseStyles( Element datasetElement )
414                                                               throws XMLParsingException, InvalidCapabilitiesException {
415    
416            List styleList = XMLTools.getNodes( datasetElement, PRE_WPVS + "Style", nsContext );
417            // optional therefore return null if not present
418            if ( styleList.size() == 0 ) {
419                return null;
420            }
421    
422            Style[] styles = new Style[styleList.size()];
423    
424            for ( int i = 0; i < styles.length; i++ ) {
425    
426                Element styleElement = (Element) styleList.get( i );
427    
428                String name = XMLTools.getRequiredNodeAsString( styleElement, PRE_WPVS + "Name/text()", nsContext );
429                String title = XMLTools.getRequiredNodeAsString( styleElement, PRE_WPVS + "Title/text()", nsContext );
430                String abstract_ = XMLTools.getRequiredNodeAsString( styleElement, PRE_WPVS + "Abstract/text()", nsContext );
431                // optional
432                Keywords[] keywords = getKeywords( XMLTools.getNodes( styleElement, PRE_OWS + "Keywords", nsContext ) );
433                // mandatory
434                Identifier identifier = parseStyleIdentifier( styleElement, PRE_WPVS + "Identifier" );
435    
436                // optional
437                LegendURL[] legendURLs = parseLegendURLs( styleElement );
438    
439                // optional
440                StyleSheetURL styleSheetURL = parseStyleSheetURL( styleElement );
441                StyleURL styleURL = parseStyleURL( styleElement );
442    
443                styles[i] = new Style( name, title, abstract_, keywords, identifier, legendURLs, styleSheetURL, styleURL );
444            }
445    
446            return styles;
447        }
448    
449        /**
450         * Creates and returns a new <code>StyleURL</code> object from the given <code>Element</code>.
451         * 
452         * @param styleElement
453         * @return Returns a new StyleURL object or <code>null</code> if not defined (optional)
454         * @throws XMLParsingException
455         * @throws InvalidCapabilitiesException
456         */
457        private StyleURL parseStyleURL( Element styleElement )
458                                                              throws XMLParsingException, InvalidCapabilitiesException {
459    
460            Element styleURLElement = (Element) XMLTools.getNode( styleElement, PRE_WPVS + "StyleURL", nsContext );
461            if ( styleURLElement == null ) {
462                return null;
463            }
464            String format = XMLTools.getRequiredNodeAsString( styleURLElement, PRE_WPVS + "Format/text()", nsContext );
465    
466            // optional
467            URI onlineResourceURI = XMLTools.getNodeAsURI( styleURLElement,
468                                                           PRE_WPVS + "OnlineResource/@xlink:href",
469                                                           nsContext,
470                                                           null );
471            URL onlineResource = null;
472            if ( onlineResourceURI != null ) {
473                try {
474                    onlineResource = onlineResourceURI.toURL();
475                } catch ( MalformedURLException e ) {
476                    throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: "
477                                                            + e.getMessage() );
478                }
479            }
480            return new StyleURL( format, onlineResource );
481        }
482    
483        /**
484         * Creates and returns a new <code>StyleSheetURL</code> object from the given <code>Element</code>.
485         * 
486         * @param styleElement
487         * @return Returns a new StyleSheetURL object or <code>null</code> if no stylSheetURL was given (optional)
488         * @throws XMLParsingException
489         * @throws InvalidCapabilitiesException
490         */
491        private StyleSheetURL parseStyleSheetURL( Element styleElement )
492                                                                        throws XMLParsingException,
493                                                                        InvalidCapabilitiesException {
494    
495            Element styleSheetURLElement = (Element) XMLTools.getNode( styleElement, PRE_WPVS + "StyleSheetURL", nsContext );
496            if ( styleSheetURLElement == null ) {
497                return null;
498            }
499            String format = XMLTools.getRequiredNodeAsString( styleSheetURLElement, PRE_WPVS + "Format/text()", nsContext );
500    
501            // optional onlineResource
502            URI onlineResourceURI = XMLTools.getNodeAsURI( styleSheetURLElement,
503                                                           PRE_WPVS + "OnlineResource/@xlink:href",
504                                                           nsContext,
505                                                           null );
506            URL onlineResource = null;
507            if ( onlineResourceURI != null ) {
508                try {
509                    onlineResource = onlineResourceURI.toURL();
510                } catch ( MalformedURLException e ) {
511                    throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: "
512                                                            + e.getMessage() );
513                }
514            }
515    
516            return new StyleSheetURL( format, onlineResource );
517        }
518    
519        /**
520         * Creates and returns a new array of <code>LegendURL</code> objects from the given <code>Element</code>.
521         * 
522         * @param styleElement
523         * @return Returns a new array of LegendURL objects or <code>null</code> if none were defined (optional).
524         * @throws XMLParsingException
525         * @throws InvalidCapabilitiesException
526         */
527        private LegendURL[] parseLegendURLs( Element styleElement )
528                                                                   throws XMLParsingException, InvalidCapabilitiesException {
529    
530            List legendList = XMLTools.getNodes( styleElement, PRE_WPVS + "LegendURL", nsContext );
531            if ( legendList.size() == 0 ) {
532                return null;
533            }
534    
535            LegendURL[] legendURLs = new LegendURL[legendList.size()];
536    
537            for ( int i = 0; i < legendURLs.length; i++ ) {
538    
539                Element legendURLElement = (Element) legendList.get( i );
540    
541                int width = XMLTools.getRequiredNodeAsInt( legendURLElement, "@width", nsContext );
542                int height = XMLTools.getRequiredNodeAsInt( legendURLElement, "@height", nsContext );
543                if ( width < 0 || height < 0 ) {
544                    throw new InvalidCapabilitiesException( "The attributes width and height of '" + legendURLElement.getNodeName()
545                                                            + "' must be positive!" );
546                }
547    
548                String format = XMLTools.getRequiredNodeAsString( legendURLElement, PRE_WPVS + "Format/text()", nsContext );
549                // optional
550                URI onlineResourceURI = XMLTools.getNodeAsURI( legendURLElement,
551                                                               PRE_WPVS + "OnlineResource/@xlink:href",
552                                                               nsContext,
553                                                               null );
554    
555                URL onlineResource = null;
556                if ( onlineResourceURI != null ) {
557                    try {
558                        onlineResource = onlineResourceURI.toURL();
559                    } catch ( MalformedURLException e ) {
560                        throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: "
561                                                                + e.getMessage() );
562                    }
563                }
564    
565                legendURLs[i] = new LegendURL( width, height, format, onlineResource );
566            }
567            return legendURLs;
568        }
569    
570        /**
571         * Creates and returns a new array of <code>FeatureListReference</code> objects from the given
572         * <code>Element</code>.
573         * 
574         * @param datasetElement
575         * @return Returns an array of FeatureListReference instances or <code>null</code> if none were defined
576         *         (optional).
577         * @throws XMLParsingException
578         * @throws InvalidCapabilitiesException
579         */
580        protected FeatureListReference[] parseFeatureListReferences( Element datasetElement )
581                                                                                             throws XMLParsingException,
582                                                                                             InvalidCapabilitiesException {
583    
584            List featureList = XMLTools.getNodes( datasetElement, PRE_WPVS + "FeatureListReference", nsContext );
585            if ( featureList.size() == 0 ) {
586                return null;
587            }
588            FeatureListReference[] featureRefs = new FeatureListReference[featureList.size()];
589            for ( int i = 0; i < featureRefs.length; i++ ) {
590    
591                Element featureRefElement = (Element) featureList.get( i );
592    
593                String format = XMLTools.getRequiredNodeAsString( featureRefElement, PRE_WPVS + "Format/text()", nsContext );
594    
595                URI onlineResourceURI = XMLTools.getNodeAsURI( featureRefElement,
596                                                               PRE_WPVS + "OnlineResource/@xlink:href",
597                                                               nsContext,
598                                                               null );
599                URL onlineResource = null;
600                if ( onlineResourceURI != null ) {
601                    try {
602                        onlineResource = onlineResourceURI.toURL();
603                    } catch ( MalformedURLException e ) {
604                        throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: "
605                                                                + e.getMessage() );
606                    }
607                }
608                featureRefs[i] = new FeatureListReference( format, onlineResource );
609            }
610            return featureRefs;
611        }
612    
613        /**
614         * Creates and returns a new array of <code>DatasetReference</code> objects from the given <code>Element</code>.
615         * 
616         * @param datasetElement
617         * @return Returns a new array of DatasetReference objects or <code>null</code> if no DatasetReferences are
618         *         specified in this dataset (optional)
619         * @throws XMLParsingException
620         * @throws InvalidCapabilitiesException
621         */
622        protected DatasetReference[] parseDatasetReferences( Element datasetElement )
623                                                                                     throws XMLParsingException,
624                                                                                     InvalidCapabilitiesException {
625    
626            List datasetRefList = XMLTools.getNodes( datasetElement, PRE_WPVS + "DatasetReference", nsContext );
627            if ( datasetRefList == null ) {
628                return null;
629            }
630            DatasetReference[] datasetRefs = new DatasetReference[datasetRefList.size()];
631    
632            for ( int i = 0; i < datasetRefs.length; i++ ) {
633    
634                Element datasetRefElement = (Element) datasetRefList.get( i );
635    
636                String format = XMLTools.getRequiredNodeAsString( datasetRefElement, PRE_WPVS + "Format/text()", nsContext );
637    
638                URI onlineResourceURI = XMLTools.getNodeAsURI( datasetRefElement,
639                                                               PRE_WPVS + "OnlineResource/@xlink:href",
640                                                               nsContext,
641                                                               null );
642                URL onlineResource = null;
643                if ( onlineResourceURI != null ) {
644                    try {
645                        onlineResource = onlineResourceURI.toURL();
646                    } catch ( MalformedURLException e ) {
647                        throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: "
648                                                                + e.getMessage() );
649                    }
650                }
651                datasetRefs[i] = new DatasetReference( format, onlineResource );
652            }
653    
654            return datasetRefs;
655        }
656    
657        /**
658         * Creates and returns a new <code>MetaData</code> object from the given <code>Element</code>.
659         * 
660         * @param datasetElement
661         * @return Returns an array of MetaData objects, or <code>null</code> if no metadata was specified in the dataset
662         *         (optional).
663         * @throws XMLParsingException
664         * @throws InvalidCapabilitiesException
665         */
666        protected MetaData[] parseMetaData( Element datasetElement )
667                                                                    throws XMLParsingException,
668                                                                    InvalidCapabilitiesException {
669    
670            List metaDataList = XMLTools.getNodes( datasetElement, PRE_WPVS + "MetaData", nsContext );
671            if ( metaDataList.size() == 0 ) {
672                return null;
673            }
674            MetaData[] metaData = new MetaData[metaDataList.size()];
675    
676            for ( int i = 0; i < metaData.length; i++ ) {
677    
678                Element metaDataElement = (Element) metaDataList.get( i );
679    
680                String type = XMLTools.getRequiredNodeAsString( metaDataElement, "@type", nsContext );
681    
682                String format = XMLTools.getRequiredNodeAsString( metaDataElement, PRE_WPVS + "Format/text()", nsContext );
683                URI onlineResourceURI = XMLTools.getNodeAsURI( metaDataElement,
684                                                               PRE_WPVS + "OnlineResource/@xlink:href",
685                                                               nsContext,
686                                                               null );
687                URL onlineResource = null;
688                if ( onlineResourceURI != null ) {
689                    try {
690                        onlineResource = onlineResourceURI.toURL();
691                    } catch ( MalformedURLException e ) {
692                        throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: "
693                                                                + e.getMessage() );
694                    }
695                }
696    
697                metaData[i] = new MetaData( type, format, onlineResource );
698            }
699    
700            return metaData;
701        }
702    
703        /**
704         * Creates and returns a new <code>Identifier</code> object from the given <code>Element</code> and the given
705         * <cod>xPathQuery</code>.
706         * 
707         * @param element
708         * @param xPathQuery
709         * @return Returns a new Identifier object.
710         * @throws XMLParsingException
711         * @throws InvalidCapabilitiesException
712         *             if no (valid) identifier is found
713         */
714        protected Identifier parseStyleIdentifier( Element element, String xPathQuery )
715                                                                                       throws XMLParsingException,
716                                                                                       InvalidCapabilitiesException {
717    
718            Element identifierElement = (Element) XMLTools.getRequiredNode( element, xPathQuery, nsContext );
719    
720            String value = XMLTools.getStringValue( identifierElement ).trim();
721            if ( "".equals( value ) ) {
722                throw new InvalidCapabilitiesException( Messages.getMessage( "WPVS_NO_VALID_IDENTIFIER", "style" ) );
723            }
724            URI codeSpace = XMLTools.getNodeAsURI( identifierElement, "@codeSpace", nsContext, null );
725    
726            Identifier id = new Identifier( value, codeSpace );
727            if ( styleIdentifiers.contains( id.toString() ) ) {
728                throw new InvalidCapabilitiesException( Messages.getMessage( "WPVS_NO_UNIQUE_IDENTIFIER",
729                                                                             "styles",
730                                                                             id.toString() ) );
731    
732            }
733            styleIdentifiers.add( id.toString() );
734            return id;
735        }
736    
737        /**
738         * Creates and returns a new <code>Identifier</code> object from the given <code>Element</code> and the given
739         * <cod>xPathQuery</code>.
740         * 
741         * @param element
742         * @param xPathQuery
743         * @return Returns a new Identifier object.
744         * @throws XMLParsingException
745         * @throws InvalidCapabilitiesException
746         *             if no (valid) identifier is found
747         */
748        protected Identifier parseDatasetIdentifier( Element element, String xPathQuery )
749                                                                                         throws XMLParsingException,
750                                                                                         InvalidCapabilitiesException {
751    
752            Element identifierElement = (Element) XMLTools.getRequiredNode( element, xPathQuery, nsContext );
753    
754            String value = XMLTools.getStringValue( identifierElement ).trim();
755            if ( "".equals( value ) ) {
756                throw new InvalidCapabilitiesException( Messages.getMessage( "WPVS_NO_VALID_IDENTIFIER", "dataset" ) );
757            }
758            URI codeSpace = XMLTools.getNodeAsURI( identifierElement, "@codeSpace", nsContext, null );
759            Identifier id = new Identifier( value, codeSpace );
760            if ( datasetIdentifiers.contains( id.toString() ) ) {
761                throw new InvalidCapabilitiesException( Messages.getMessage( "WPVS_NO_UNIQUE_IDENTIFIER",
762                                                                             "datasets",
763                                                                             id.toString() ) );
764    
765            }
766            datasetIdentifiers.add( id.toString() );
767    
768            return id;
769        }
770    
771        /**
772         * Creates and returns a new <code>DataProvider</code> object from the given <code>Element</code>.
773         * 
774         * @param datasetElement
775         * @return Returns a new DataProvider object or <code>null</code>if no provider was defined.
776         * @throws XMLParsingException
777         * @throws InvalidCapabilitiesException
778         */
779        protected DataProvider parseDataProvider( Element datasetElement )
780                                                                          throws XMLParsingException,
781                                                                          InvalidCapabilitiesException {
782    
783            String providerName = null;
784            URL providerSite = null;
785            LogoURL logoURL = null;
786    
787            Element dataProviderElement = (Element) XMLTools.getNode( datasetElement, PRE_WPVS + "DataProvider", nsContext );
788            if ( dataProviderElement == null )
789                return null;
790    
791            providerName = XMLTools.getNodeAsString( dataProviderElement, PRE_WPVS + "ProviderName/text()", nsContext, null );
792            URI providerSiteURI = XMLTools.getNodeAsURI( dataProviderElement,
793                                                         PRE_WPVS + "ProviderSite/@xlink:href",
794                                                         nsContext,
795                                                         null );
796            if ( providerSiteURI != null ) {
797                try {
798                    providerSite = providerSiteURI.toURL();
799                } catch ( MalformedURLException e ) {
800                    throw new InvalidCapabilitiesException( providerSiteURI + " does not represent a valid URL: "
801                                                            + e.getMessage() );
802                }
803            }
804    
805            Node logoURLElement = XMLTools.getNode( dataProviderElement, PRE_WPVS + "LogoURL", nsContext );
806            if ( logoURLElement != null ) {
807    
808                int width = XMLTools.getRequiredNodeAsInt( logoURLElement, "@width", nsContext );
809                int height = XMLTools.getRequiredNodeAsInt( logoURLElement, "@height", nsContext );
810                if ( width < 0 || height < 0 ) {
811                    throw new InvalidCapabilitiesException( "width and height of '" + logoURLElement
812                                                            + "' must be positive!" );
813                }
814    
815                String format = XMLTools.getRequiredNodeAsString( logoURLElement, PRE_WPVS + "Format/text()", nsContext );
816    
817                URI onlineResourceURI = XMLTools.getNodeAsURI( logoURLElement,
818                                                               PRE_WPVS + "OnlineResource/@xlink:href",
819                                                               nsContext,
820                                                               null );
821                URL onlineResource = null;
822                if ( onlineResourceURI != null ) {
823                    try {
824                        onlineResource = onlineResourceURI.toURL();
825                    } catch ( MalformedURLException e ) {
826                        throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: "
827                                                                + e.getMessage() );
828                    }
829                }
830    
831                logoURL = new LogoURL( width, height, format, onlineResource );
832            }
833            return new DataProvider( providerName, providerSite, logoURL );
834        }
835    
836        /**
837         * 
838         * @param element
839         * @return the Dimensions of a given element or <code>null</code> if no dimension is found (optional).
840         * @throws XMLParsingException
841         */
842        protected Dimension[] parseDimensions( Element element )
843                                                                throws XMLParsingException {
844    
845            List nl = XMLTools.getNodes( element, PRE_WPVS + "Dimension", nsContext );
846            if ( nl.size() == 0 ) {
847                return null;
848            }
849            Dimension[] dimensions = new Dimension[nl.size()];
850    
851            for ( int i = 0; i < dimensions.length; i++ ) {
852    
853                String name = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), "@name", nsContext );
854                String units = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), "@units", nsContext );
855                String unitSymbol = XMLTools.getNodeAsString( (Node) nl.get( i ), "@unitSymbol", nsContext, null );
856                String default_ = XMLTools.getNodeAsString( (Node) nl.get( i ), "@default", nsContext, null );
857                Boolean multipleValues = Boolean.valueOf( XMLTools.getNodeAsBoolean( (Node) nl.get( i ),
858                                                                                     "@multipleValues",
859                                                                                     nsContext,
860                                                                                     true ) );
861                Boolean nearestValues = Boolean.valueOf( XMLTools.getNodeAsBoolean( (Node) nl.get( i ),
862                                                                                    "@nearestValues",
863                                                                                    nsContext,
864                                                                                    true ) );
865                Boolean current = Boolean.valueOf( XMLTools.getNodeAsBoolean( (Node) nl.get( i ),
866                                                                              "@current",
867                                                                              nsContext,
868                                                                              true ) );
869                String value = XMLTools.getNodeAsString( (Node) nl.get( i ), ".", nsContext, null );
870    
871                dimensions[i] = new Dimension( name,
872                                               units,
873                                               unitSymbol,
874                                               default_,
875                                               multipleValues,
876                                               nearestValues,
877                                               current,
878                                               value );
879            }
880    
881            return dimensions;
882        }
883    
884        /**
885         * Gets an array of <code>boundingBoxes</code> from the given <code>Element</code>. This method returns all
886         * boundingBoxes together in one array.
887         * 
888         * @param element
889         * @param defaultCoordinateSystem
890         *            to be used for not defined coordinate system attribute in the bbox element
891         * @return Returns an array of boundingBoxes.
892         * @throws XMLParsingException
893         * @throws InvalidParameterValueException
894         */
895        protected Envelope[] getBoundingBoxes( Element element, CoordinateSystem defaultCoordinateSystem )
896                                                                                                          throws XMLParsingException,
897                                                                                                          InvalidParameterValueException {
898    
899            List boundingBoxList = XMLTools.getNodes( element, PRE_OWS + "BoundingBox", nsContext );
900    
901            List<Envelope> bboxesList = new ArrayList<Envelope>( boundingBoxList.size() );
902    
903            for ( int i = 0; i < boundingBoxList.size(); i++ ) {
904                bboxesList.add( parseBoundingBox( (Element) boundingBoxList.get( i ), defaultCoordinateSystem ) );
905            }
906    
907            // The ogc_wpvs schema says: wgs84 is mandatory therefore-> not checking parents to use it's
908            // bboxes.
909    
910            // if ( parent != null ) {
911            // Envelope[] boundingBoxes = parent.getBoundingBoxes();
912            // for ( int i = 0; i < boundingBoxes.length; i++ ) {
913            // bboxesList.add( boundingBoxes[i] );
914            // }
915            // }
916    
917            Envelope[] boxes = bboxesList.toArray( new Envelope[bboxesList.size()] );
918            return boxes;
919        }
920    
921        /**
922         * Usable with any BoundingBox. Changed crs from null to given attribute value of crs. Added check for min values to
923         * be smaler than max values.
924         * 
925         * Creates an <code>Envelope</code> object from the given element of type <code>ows:WGS84BoundingBox</code> or
926         * <code>ows:BoundingBox</code>.
927         * 
928         * @param element
929         * @param defaultCoordinateSystem
930         *            if the crs-attribute of the bbox element is not defined
931         * @return a boundingbox of a dataset
932         * @throws XMLParsingException
933         * @throws InvalidParameterValueException
934         */
935        protected Envelope parseBoundingBox( Element element, CoordinateSystem defaultCoordinateSystem )
936                                                                                                        throws XMLParsingException,
937                                                                                                        InvalidParameterValueException {
938    
939            // Envelope env = getWGS84BoundingBoxType( element );
940    
941            String crsAtt = element.getAttribute( "crs" );
942            CoordinateSystem crs = null;
943            if ( crsAtt == null ) {
944                crs = defaultCoordinateSystem;
945            } else {
946                try {
947                    crs = CRSFactory.create( crsAtt );
948                } catch ( UnknownCRSException e ) {
949                    throw new InvalidParameterValueException( e.getMessage() );
950                }
951            }
952    
953            double[] lowerCorner = XMLTools.getRequiredNodeAsDoubles( element,
954                                                                      PRE_OWS + "LowerCorner/text()",
955                                                                      nsContext,
956                                                                      " " );
957            if ( lowerCorner.length < 2 ) {
958                throw new XMLParsingException( Messages.getMessage( "WPVS_NO_VALID_BBOX_POINT", PRE_OWS + "LowerCorner" ) );
959            }
960            double[] upperCorner = XMLTools.getRequiredNodeAsDoubles( element,
961                                                                      PRE_OWS + "UpperCorner/text()",
962                                                                      nsContext,
963                                                                      " " );
964            if ( upperCorner.length < 2 ) {
965                throw new XMLParsingException( Messages.getMessage( "WPVS_NO_VALID_BBOX_POINT", PRE_OWS + "UpperCorner" ) );
966            }
967            if ( upperCorner.length != lowerCorner.length ) {
968                throw new XMLParsingException( Messages.getMessage( "WPVS_DIFFERENT_BBOX_DIMENSIONS",
969                                                                    PRE_OWS + "LowerCorner",
970                                                                    PRE_OWS + "UpperCorner" ) );
971            }
972    
973            for ( int i = 0; i < upperCorner.length; ++i ) {
974                if ( lowerCorner[i] >= upperCorner[i] ) {
975                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_WRONG_BBOX_POINT_POSITIONS",
976                                                                                   new Integer( i ),
977                                                                                   new Double( lowerCorner[i] ),
978                                                                                   PRE_OWS + "LowerCorner",
979                                                                                   new Double( upperCorner[i] ),
980                                                                                   PRE_OWS + "UpperCorner" ) );
981    
982                }
983            }
984    
985            return GeometryFactory.createEnvelope( lowerCorner[0], lowerCorner[1], upperCorner[0], upperCorner[1], crs );
986    
987        }
988    
989        /**
990         * Creates and returns a new <code>OperationsMetadata</code> object.
991         * 
992         * @param defaultOnlineResource
993         *            to fill in the left out dcp's or <code>null</code> if no default URL was given.
994         * 
995         * @return Returns a new OperationsMetadata object.
996         * @throws XMLParsingException
997         * @throws InvalidCapabilitiesException
998         */
999        protected OperationsMetadata parseOperationsMetadata( OnlineResource defaultOnlineResource )
1000                                                                                                    throws XMLParsingException,
1001                                                                                                    InvalidCapabilitiesException {
1002    
1003            Node operationMetadata = XMLTools.getRequiredNode( getRootElement(), PRE_OWS + "OperationsMetadata", nsContext );
1004            List operationElementList = XMLTools.getNodes( operationMetadata, PRE_OWS + "Operation", nsContext );
1005    
1006            Map<String, Element> operations = new HashMap<String, Element>();
1007            for ( int i = 0; i < operationElementList.size(); i++ ) {
1008                operations.put( XMLTools.getRequiredNodeAsString( (Node) operationElementList.get( i ), "@name", nsContext ),
1009                                (Element) operationElementList.get( i ) );
1010            }
1011    
1012            Operation110 getCapabilities = getOperation110( OperationsMetadata.GET_CAPABILITIES_NAME,
1013                                                            true,
1014                                                            operations,
1015                                                            defaultOnlineResource );
1016            Operation110 getView = getOperation110( WPVSOperationsMetadata.GET_VIEW_NAME,
1017                                                    true,
1018                                                    operations,
1019                                                    defaultOnlineResource );
1020            Operation110 getDescription = getOperation110( WPVSOperationsMetadata.GET_DESCRIPTION_NAME,
1021                                                           false,
1022                                                           operations,
1023                                                           defaultOnlineResource );
1024    
1025            Operation110 get3DFeatureInfo = getOperation110( WPVSOperationsMetadata.GET_3D_FEATURE_INFO,
1026                                                             false,
1027                                                             operations,
1028                                                             defaultOnlineResource );
1029    
1030            Operation110 getLegendGraphics = getOperation110( WPVSOperationsMetadata.GET_LEGEND_GRAPHIC_NAME,
1031                                                              false,
1032                                                              operations,
1033                                                              defaultOnlineResource );
1034    
1035            List parameterElementList = XMLTools.getNodes( operationMetadata, PRE_OWS + "Parameter", nsContext );
1036            OWSDomainType110[] parameters = new OWSDomainType110[parameterElementList.size()];
1037            for ( int i = 0; i < parameters.length; i++ ) {
1038                parameters[i] = getOWSDomainType110( (Element) parameterElementList.get( i ) );
1039            }
1040    
1041            List constraintElementList = XMLTools.getNodes( operationMetadata, PRE_OWS + "Constraint", nsContext );
1042            OWSDomainType110[] constraints = new OWSDomainType110[constraintElementList.size()];
1043            for ( int i = 0; i < constraints.length; i++ ) {
1044                constraints[i] = getOWSDomainType110( (Element) constraintElementList.get( i ) );
1045            }
1046    
1047            List extendedCapsList = XMLTools.getNodes( operationMetadata, PRE_OWS + "ExtendedCapabilities", nsContext );
1048            Object[] extendedCapabilities = new Object[extendedCapsList.size()];
1049            for ( int i = 0; i < extendedCapabilities.length; i++ ) {
1050                extendedCapabilities[i] = extendedCapsList.get( i );
1051            }
1052    
1053            WPVSOperationsMetadata metadata = new WPVSOperationsMetadata( getCapabilities,
1054                                                                          getView,
1055                                                                          getDescription,
1056                                                                          getLegendGraphics,
1057                                                                          parameters,
1058                                                                          constraints,
1059                                                                          extendedCapabilities,
1060                                                                          get3DFeatureInfo );
1061    
1062            return metadata;
1063        }
1064    
1065        /**
1066         * FIXME needs to be handled, when OWSDomainType110 ceases to exist.
1067         * 
1068         * @see org.deegree.owscommon.OWSCommonCapabilitiesDocument#getOperation()
1069         * 
1070         * @param name
1071         * @param isMandatory
1072         * @param operations
1073         * @return the Operation110 with the given name from the map
1074         * @throws XMLParsingException
1075         * @throws InvalidCapabilitiesException
1076         */
1077        private Operation110 getOperation110( String name, boolean isMandatory, Map<String, Element> operations,
1078                                              OnlineResource defaultOnlineResource )
1079                                                                                    throws XMLParsingException,
1080                                                                                    InvalidCapabilitiesException {
1081    
1082            Operation110 operation = null;
1083            Element operationElement = operations.get( name );
1084            if ( operationElement == null ) {
1085                if ( isMandatory ) {
1086                    throw new XMLParsingException( "Mandatory operation '" + name
1087                                                   + "' not defined in "
1088                                                   + "'OperationsMetadata'-section." );
1089                }
1090            } else {
1091                // 'ows:DCP' - elements
1092                DCPType[] dcps = getDCPs( XMLTools.getRequiredNodes( operationElement, PRE_OWS + "DCP", nsContext ) );
1093                //fill in the default online resource if one is missing.
1094                if ( defaultOnlineResource != null ) {
1095                    for ( DCPType dcp : dcps ) {
1096                        Protocol pr = dcp.getProtocol();
1097                        if ( pr != null ) {
1098                            if ( pr instanceof HTTP ) {
1099                                if ( ( (HTTP) pr ).getGetOnlineResources() == null || ( (HTTP) pr ).getGetOnlineResources().length == 0 ) {
1100                                    ( (HTTP) pr ).setGetOnlineResources( new URL[] { defaultOnlineResource.getLinkage()
1101                                                                                                          .getHref() } );
1102                                }
1103                                if ( ( (HTTP) pr ).getPostOnlineResources() == null || ( (HTTP) pr ).getPostOnlineResources().length == 0 ) {
1104                                    ( (HTTP) pr ).setPostOnlineResources( new URL[] { defaultOnlineResource.getLinkage()
1105                                                                                                           .getHref() } );
1106                                }
1107                            }
1108                        }
1109                    }
1110                }
1111    
1112                // 'Parameter' - elements
1113                List parameterList = XMLTools.getNodes( operationElement, PRE_OWS + "Parameter", nsContext );
1114                OWSDomainType110[] parameters = new OWSDomainType110[parameterList.size()];
1115                for ( int i = 0; i < parameters.length; i++ ) {
1116                    parameters[i] = getOWSDomainType110( (Element) parameterList.get( i ) );
1117                }
1118                // 'Constraint' - elements
1119                List constraintList = XMLTools.getNodes( operationElement, PRE_OWS + "Constraint", nsContext );
1120                OWSDomainType110[] constraints = new OWSDomainType110[constraintList.size()];
1121                for ( int i = 0; i < constraintList.size(); i++ ) {
1122                    constraints[i] = getOWSDomainType110( (Element) constraintList.get( i ) );
1123                }
1124                // 'ows:Metadata' - element
1125                List metadataList = XMLTools.getNodes( operationElement, PRE_OWS + "Metadata", nsContext );
1126                OWSMetadata[] metadata = new OWSMetadata[metadataList.size()];
1127                for ( int i = 0; i < metadata.length; i++ ) {
1128                    metadata[i] = getOWSMetadata( operationElement, PRE_OWS + "Metadata", nsContext );
1129                }
1130    
1131                // return new Operation110 object
1132                operation = new Operation110( name, dcps, parameters, constraints, metadata );
1133            }
1134    
1135            return operation;
1136        }
1137    
1138        /**
1139         * FIXME there is a similar method in org.deegree.owscommon.OWSCommonCapabilitiesDocument#getDCP. overrides that
1140         * method!
1141         * 
1142         * Creates a <code>DCPType</code> object from the passed <code>DCP</code> element.
1143         * 
1144         * @param element
1145         * @return created <code>DCPType</code>
1146         * @throws XMLParsingException
1147         * @see org.deegree.ogcwebservices.getcapabilities.OGCStandardCapabilities
1148         */
1149        @Override
1150        protected DCPType getDCP( Element element )
1151                                                   throws XMLParsingException {
1152            DCPType dcpType = null;
1153            Element httpElement = (Element) XMLTools.getRequiredNode( element, PRE_OWS + "HTTP", nsContext );
1154    
1155            try {
1156                List requestList = XMLTools.getNodes( httpElement, PRE_OWS + "Get", nsContext );
1157                OWSRequestMethod[] getRequests = new OWSRequestMethod[requestList.size()];
1158                for ( int i = 0; i < getRequests.length; i++ ) {
1159    
1160                    List constraintList = XMLTools.getNodes( (Node) requestList.get( i ), PRE_OWS + "Constraint", nsContext );
1161                    OWSDomainType110[] constraint = new OWSDomainType110[constraintList.size()];
1162                    for ( int j = 0; j < constraint.length; j++ ) {
1163                        constraint[j] = getOWSDomainType110( (Element) constraintList.get( i ) );
1164                    }
1165    
1166                    SimpleLink link = parseSimpleLink( (Element) requestList.get( i ) );
1167    
1168                    getRequests[i] = new OWSRequestMethod( link, constraint );
1169                }
1170    
1171                requestList = XMLTools.getNodes( httpElement, PRE_OWS + "Post", nsContext );
1172                OWSRequestMethod[] postRequests = new OWSRequestMethod[requestList.size()];
1173                for ( int i = 0; i < postRequests.length; i++ ) {
1174    
1175                    List constraintList = XMLTools.getNodes( (Node) requestList.get( i ), PRE_OWS + "Constraint", nsContext );
1176                    OWSDomainType110[] constraint = new OWSDomainType110[constraintList.size()];
1177                    for ( int j = 0; j < constraint.length; j++ ) {
1178                        constraint[j] = getOWSDomainType110( (Element) constraintList.get( i ) );
1179                    }
1180    
1181                    SimpleLink link = parseSimpleLink( (Element) requestList.get( i ) );
1182    
1183                    postRequests[i] = new OWSRequestMethod( link, constraint );
1184                }
1185    
1186                Protocol protocol = new HTTP110( getRequests, postRequests );
1187                dcpType = new DCPType( protocol );
1188    
1189            } catch ( InvalidCapabilitiesException e ) {
1190                throw new XMLParsingException( "Couldn't parse the OWSDomainType110 within DCPType: " + StringTools.stackTraceToString( e ) );
1191            }
1192    
1193            return dcpType;
1194        }
1195    
1196        /**
1197         * FIXME needs to be handled, when OWSDomainType110 ceases to exist.
1198         * 
1199         * @see org.deegree.owscommon.OWSCommonCapabilitiesDocument#getOWSDomainType()
1200         * 
1201         * @param element
1202         * @return Returns owsDomainType110 object.
1203         * @throws InvalidCapabilitiesException
1204         */
1205        private OWSDomainType110 getOWSDomainType110( Element element )
1206                                                                       throws XMLParsingException,
1207                                                                       InvalidCapabilitiesException {
1208    
1209            // 'name' - attribute
1210            String name = XMLTools.getRequiredNodeAsString( element, "@name", nsContext );
1211    
1212            // 'ows:AllowedValues' - element
1213            Element allowedElement = (Element) XMLTools.getNode( element, PRE_OWS + "AllowedValues", nsContext );
1214            OWSAllowedValues allowedValues = null;
1215            if ( allowedElement != null ) {
1216    
1217                // 'ows:Value' - elements
1218                String[] values = XMLTools.getNodesAsStrings( allowedElement, PRE_OWS + "Value/text()", nsContext );
1219                TypedLiteral[] literals = null;
1220                if ( values != null ) {
1221                    literals = new TypedLiteral[values.length];
1222                    for ( int i = 0; i < literals.length; i++ ) {
1223                        literals[i] = new TypedLiteral( values[i], null );
1224                    }
1225                }
1226    
1227                // 'ows:Range' - elements
1228                List rangeList = XMLTools.getNodes( allowedElement, PRE_OWS + "Range", nsContext );
1229                ValueRange[] ranges = new ValueRange[rangeList.size()];
1230                for ( int i = 0; i < ranges.length; i++ ) {
1231                    String minimum = XMLTools.getNodeAsString( (Node) rangeList.get( i ),
1232                                                               PRE_OWS + "MinimumValue",
1233                                                               nsContext,
1234                                                               null );
1235                    String maximum = XMLTools.getNodeAsString( (Node) rangeList.get( i ),
1236                                                               PRE_OWS + "MaximumValue",
1237                                                               nsContext,
1238                                                               null );
1239                    String spacing = XMLTools.getNodeAsString( (Node) rangeList.get( i ),
1240                                                               PRE_OWS + "Spacing",
1241                                                               nsContext,
1242                                                               null );
1243                    TypedLiteral min = new TypedLiteral( minimum, null );
1244                    TypedLiteral max = new TypedLiteral( maximum, null );
1245                    TypedLiteral space = new TypedLiteral( spacing, null );
1246    
1247                    ranges[i] = new ValueRange( min, max, space );
1248                }
1249    
1250                if ( values.length < 1 && ranges.length < 1 ) {
1251                    throw new XMLParsingException( "At least one 'ows:Value'-element or one 'ows:Range'-element must be defined " + "in each element of type 'ows:AllowedValues'." );
1252                }
1253    
1254                allowedValues = new OWSAllowedValues( literals, ranges );
1255            }
1256    
1257            // FIXME manage elements: ows:AnyValue, ows:NoValues.
1258            boolean anyValue = false;
1259            boolean noValues = false;
1260    
1261            // 'ows:ValuesListReference' - element
1262            OWSMetadata valuesListReference = getOWSMetadata( element, PRE_OWS + "ValuesListReference", nsContext );
1263    
1264            // 'ows:DefaulValue' - element
1265            String defaultValue = XMLTools.getNodeAsString( element, PRE_OWS + "DefaultValue/text()", nsContext, null );
1266    
1267            // 'ows:Meaning' - element
1268            OWSMetadata meaning = getOWSMetadata( element, PRE_OWS + "Meaning", nsContext );
1269    
1270            // 'ows:DataType - element
1271            OWSMetadata dataType = getOWSMetadata( element, PRE_OWS + "DataType", nsContext );
1272    
1273            // choose up to one measurement element
1274            String measurementType = null;
1275            // 'ows:ReferenceSystem' - element
1276            Element referenceElement = (Element) XMLTools.getNode( element, PRE_OWS + "ReferenceSystem", nsContext );
1277            // 'ows:UOM' - element
1278            Element uomElement = (Element) XMLTools.getNode( element, PRE_OWS + "UOM", nsContext );
1279            OWSMetadata measurement = null;
1280    
1281            if ( referenceElement != null && uomElement != null ) {
1282                throw new InvalidCapabilitiesException( "Within an 'ows:DomainType'-Element only one " + "of the following elements is allowed: "
1283                                                        + "'ows:ReferenceSystem' OR 'ows:UOM'." );
1284            } else if ( referenceElement != null ) {
1285                measurementType = OWSDomainType110.REFERENCE_SYSTEM;
1286                measurement = getOWSMetadata( element, PRE_OWS + "ReferenceSystem", nsContext );
1287            } else if ( uomElement != null ) {
1288                measurementType = OWSDomainType110.UOM;
1289                measurement = getOWSMetadata( element, PRE_OWS + "UOM", nsContext );
1290            }
1291    
1292            // 'ows:Metadata' - elements
1293            List metaList = XMLTools.getNodes( element, PRE_OWS + "Metadata", nsContext );
1294            OWSMetadata[] metadata = new OWSMetadata[metaList.size()];
1295            for ( int i = 0; i < metadata.length; i++ ) {
1296                metadata[i] = getOWSMetadata( (Element) metaList.get( i ), PRE_OWS + "Metadata", nsContext );
1297            }
1298    
1299            // return new OWSDomainType110
1300            OWSDomainType110 domainType110 = null;
1301            if ( allowedValues != null && !anyValue && !noValues && valuesListReference == null ) {
1302                domainType110 = new OWSDomainType110( allowedValues,
1303                                                      defaultValue,
1304                                                      meaning,
1305                                                      dataType,
1306                                                      measurementType,
1307                                                      measurement,
1308                                                      metadata,
1309                                                      name );
1310            } else if ( ( anyValue || noValues ) && allowedValues == null && valuesListReference == null ) {
1311                domainType110 = new OWSDomainType110( anyValue,
1312                                                      noValues,
1313                                                      defaultValue,
1314                                                      meaning,
1315                                                      dataType,
1316                                                      measurementType,
1317                                                      measurement,
1318                                                      metadata,
1319                                                      name );
1320            } else if ( valuesListReference != null && allowedValues == null && !anyValue && !noValues ) {
1321                domainType110 = new OWSDomainType110( valuesListReference,
1322                                                      defaultValue,
1323                                                      meaning,
1324                                                      dataType,
1325                                                      measurementType,
1326                                                      measurement,
1327                                                      metadata,
1328                                                      name );
1329            } else {
1330                throw new InvalidCapabilitiesException( "Only one of the following elements may be " + "contained within an 'ows:DomainType': 'ows:AllowedValues', 'ows:AnyValue', "
1331                                                        + "'ows:NoValues' or 'ows:ValuesListReference'." );
1332            }
1333    
1334            return domainType110;
1335        }
1336    
1337        /**
1338         * FIXME check, wether the URIs go to the correct address within OWSMetadata. So far, no example was given to check
1339         * this with.
1340         * 
1341         * Creates and returns a new <code>OWSMetadata</code> object (or null) from the given <code>Element</code> at
1342         * the given <code>XPath</code>.
1343         * 
1344         * @param element
1345         * @param xPath
1346         * @param nsContext
1347         * @return Returns a new OWSMetadata object (may be null).
1348         * @throws XMLParsingException
1349         */
1350        private OWSMetadata getOWSMetadata( Element element, String xPath, NamespaceContext nsContext )
1351                                                                                                       throws XMLParsingException {
1352    
1353            Element child = (Element) XMLTools.getNode( element, xPath, nsContext );
1354    
1355            if ( child == null ) {
1356                return null;
1357            }
1358    
1359            // attrib about
1360            URI about = XMLTools.getNodeAsURI( child, "@about", nsContext, null );
1361    
1362            // attribs for SimpleLink
1363            URI href = XMLTools.getNodeAsURI( child, "@xlink:href", nsContext, null );
1364            URI role = XMLTools.getNodeAsURI( child, "@xlink:role", nsContext, null );
1365            URI arcrole = XMLTools.getNodeAsURI( child, "@xlink:arcrole", nsContext, null );
1366            String title = XMLTools.getNodeAsString( child, "@xlink:title", nsContext, null );
1367            String show = XMLTools.getNodeAsString( child, "@xlink:show", nsContext, null );
1368            String actuate = XMLTools.getNodeAsString( child, "@xlink:actuate", nsContext, null );
1369    
1370            // ows:name (ows:AbstractMetaData)
1371            String name = XMLTools.getNodeAsString( child, "text()", nsContext, null );
1372    
1373            SimpleLink link = new SimpleLink( href, role, arcrole, title, show, actuate );
1374    
1375            return new OWSMetadata( about, link, name );
1376        }
1377    
1378    }