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