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