001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wms/configuration/WMSConfigurationDocument.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstraße 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041     
042     ---------------------------------------------------------------------------*/
043    package org.deegree.ogcwebservices.wms.configuration;
044    
045    import java.awt.Color;
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    
056    import javax.xml.transform.TransformerException;
057    
058    import org.deegree.datatypes.QualifiedName;
059    import org.deegree.enterprise.Proxy;
060    import org.deegree.framework.log.ILogger;
061    import org.deegree.framework.log.LoggerFactory;
062    import org.deegree.framework.util.BootLogger;
063    import org.deegree.framework.util.IDGenerator;
064    import org.deegree.framework.util.KVP2Map;
065    import org.deegree.framework.util.StringTools;
066    import org.deegree.framework.xml.InvalidConfigurationException;
067    import org.deegree.framework.xml.XMLFragment;
068    import org.deegree.framework.xml.XMLParsingException;
069    import org.deegree.framework.xml.XMLTools;
070    import org.deegree.framework.xml.XSLTDocument;
071    import org.deegree.i18n.Messages;
072    import org.deegree.model.crs.UnknownCRSException;
073    import org.deegree.model.metadata.iso19115.OnlineResource;
074    import org.deegree.model.spatialschema.Envelope;
075    import org.deegree.model.spatialschema.GMLGeometryAdapter;
076    import org.deegree.model.spatialschema.Geometry;
077    import org.deegree.model.spatialschema.GeometryException;
078    import org.deegree.ogcbase.CommonNamespaces;
079    import org.deegree.ogcwebservices.OGCWebService;
080    import org.deegree.ogcwebservices.getcapabilities.MetadataURL;
081    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
082    import org.deegree.ogcwebservices.wcs.WCService;
083    import org.deegree.ogcwebservices.wcs.configuration.WCSConfiguration;
084    import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage;
085    import org.deegree.ogcwebservices.wfs.RemoteWFService;
086    import org.deegree.ogcwebservices.wfs.WFServiceFactory;
087    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
088    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument;
089    import org.deegree.ogcwebservices.wfs.configuration.WFSConfiguration;
090    import org.deegree.ogcwebservices.wfs.configuration.WFSConfigurationDocument;
091    import org.deegree.ogcwebservices.wfs.operation.Query;
092    import org.deegree.ogcwebservices.wms.RemoteWMService;
093    import org.deegree.ogcwebservices.wms.capabilities.Attribution;
094    import org.deegree.ogcwebservices.wms.capabilities.AuthorityURL;
095    import org.deegree.ogcwebservices.wms.capabilities.DataURL;
096    import org.deegree.ogcwebservices.wms.capabilities.Dimension;
097    import org.deegree.ogcwebservices.wms.capabilities.Extent;
098    import org.deegree.ogcwebservices.wms.capabilities.FeatureListURL;
099    import org.deegree.ogcwebservices.wms.capabilities.Identifier;
100    import org.deegree.ogcwebservices.wms.capabilities.Layer;
101    import org.deegree.ogcwebservices.wms.capabilities.LayerBoundingBox;
102    import org.deegree.ogcwebservices.wms.capabilities.LegendURL;
103    import org.deegree.ogcwebservices.wms.capabilities.ScaleHint;
104    import org.deegree.ogcwebservices.wms.capabilities.Style;
105    import org.deegree.ogcwebservices.wms.capabilities.StyleSheetURL;
106    import org.deegree.ogcwebservices.wms.capabilities.StyleURL;
107    import org.deegree.ogcwebservices.wms.capabilities.UserDefinedSymbolization;
108    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
109    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
110    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
111    import org.deegree.ogcwebservices.wms.operation.GetMap;
112    import org.deegree.owscommon_new.OperationsMetadata;
113    import org.deegree.owscommon_new.ServiceIdentification;
114    import org.deegree.owscommon_new.ServiceProvider;
115    import org.w3c.dom.Element;
116    import org.w3c.dom.Node;
117    import org.xml.sax.SAXException;
118    
119    /**
120     * <code>WMSConfigurationDocument</code> is the parser class for a standard 1.1.1 WMS
121     * configuration document, ie, a capabilities document enriched by deegree parameters.
122     * 
123     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
124     * @author last edited by: $Author: apoth $
125     * 
126     * @version 2.0, $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
127     * 
128     * @since 2.0
129     */
130    public class WMSConfigurationDocument extends WMSCapabilitiesDocument {
131    
132        private static final long serialVersionUID = 2320990982989322325L;
133    
134        protected static final URI DEEGREEWMSNS = CommonNamespaces.DEEGREEWMS;
135    
136        private static final String XML_TEMPLATE = "WMSConfigurationTemplate.xml";
137    
138        private static final String XSLT_TEMPLATE_NAME = "WMSConfigurationTransform.xsl";
139    
140        private static XSLTDocument XSLT_TEMPLATE;
141    
142        private static Map<URL, OGCCapabilities> capaCache = new HashMap<URL, OGCCapabilities>();
143    
144        private static final ILogger LOG = LoggerFactory.getLogger( WMSConfigurationDocument.class );
145    
146        private static final QualifiedName DEFAULT_GEO_PROP = new QualifiedName(
147                                                                                 "app",
148                                                                                 "GEOM",
149                                                                                 CommonNamespaces.buildNSURI( "http://www.deegree.org/app" ) );
150    
151        static {
152            XSLT_TEMPLATE = new XSLTDocument();
153            try {
154                XSLT_TEMPLATE.load( WMSConfigurationDocument.class.getResource( XSLT_TEMPLATE_NAME ) );
155            } catch ( Exception e ) {
156                BootLogger.logError( "Error loading XSLT sheet in WMSConfigurationDocument.", e );
157            }
158        }
159        
160        /**
161         * 
162         */
163        public static void resetCapabilitiesCache() {
164            capaCache.clear();
165        }
166    
167        /**
168         * Creates a skeleton capabilities document that contains the mandatory elements only.
169         * 
170         * @throws IOException
171         * @throws SAXException
172         */
173        @Override
174        public void createEmptyDocument()
175                                throws IOException, SAXException {
176            URL url = WMSConfigurationDocument.class.getResource( XML_TEMPLATE );
177            if ( url == null ) {
178                throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." );
179            }
180            load( url );
181        }
182    
183        /**
184         * Creates a class representation of the document.
185         * 
186         * @return class representation of the configuration document
187         * @throws InvalidConfigurationException
188         */
189        public WMSConfiguration parseConfiguration()
190                                throws InvalidConfigurationException {
191    
192            try {
193                // transform document to fill missing elements and attributes with
194                // default values
195                XMLFragment frag = XSLT_TEMPLATE.transform( this );
196                this.setRootElement( frag.getRootElement() );
197            } catch ( TransformerException e ) {
198                String msg = Messages.getMessage( "WMS_CONFIGURATION_TRANSFORM" );
199                LOG.logError( msg, e );
200                throw new InvalidConfigurationException( msg, e );
201            }
202    
203            ServiceIdentification serviceIdentification = null;
204            ServiceProvider serviceProvider = null;
205            OperationsMetadata metadata = null;
206            Layer layer = null;
207            UserDefinedSymbolization uds = null;
208            WMSDeegreeParams params = null;
209            Element root = getRootElement();
210            String version = root.getAttribute( "version" );
211            String updateSeq = root.getAttribute( "updateSequence" );
212            List<String> exceptions;
213    
214            try {
215                Node node = XMLTools.getRequiredNode( getRootElement(), "./deegreewms:DeegreeParam", nsContext );
216                params = parseDeegreeParams( node );
217    
218                serviceIdentification = parseServiceIdentification();
219                serviceProvider = parseServiceProvider();
220                metadata = parseOperationsMetadata();
221    
222                Element exceptionElement = XMLTools.getRequiredElement( getRootElement(), "Capability/Exception", nsContext );
223                exceptions = parseExceptionFormats( exceptionElement );
224    
225                uds = parseUserDefinedSymbolization();
226                Element layerElem = (Element) XMLTools.getRequiredNode( getRootElement(), "./Capability/Layer", nsContext );
227                layer = parseLayers( layerElem, null, null );
228    
229            } catch ( XMLParsingException e ) {
230                e.printStackTrace();
231                throw new InvalidConfigurationException( e.getMessage() + StringTools.stackTraceToString( e ) );
232            } catch ( MalformedURLException e ) {
233                throw new InvalidConfigurationException( e.getMessage() + " - " + StringTools.stackTraceToString( e ) );
234            } catch ( UnknownCRSException e ) {
235                throw new InvalidConfigurationException( e.getMessage() + " - " + StringTools.stackTraceToString( e ) );
236            }
237    
238            WMSConfiguration wmsConfiguration = new WMSConfiguration( version, updateSeq, serviceIdentification,
239                                                                      serviceProvider, uds, metadata, layer, params,
240                                                                      getSystemId(), exceptions );
241    
242            return wmsConfiguration;
243        }
244    
245        /**
246         * Creates a class representation of the <code>deegreeParams</code>- section.
247         * 
248         * @param root
249         * 
250         * @return the deegree params
251         * @throws XMLParsingException
252         * @throws MalformedURLException
253         */
254        public WMSDeegreeParams parseDeegreeParams( Node root )
255                                throws XMLParsingException, MalformedURLException {
256    
257            Element elem = (Element) XMLTools.getRequiredNode( root, "./deegreewms:DefaultOnlineResource", nsContext );
258            OnlineResource ol = parseOnLineResource( elem );
259            int cache = XMLTools.getNodeAsInt( root, "./deegreewms:CacheSize", nsContext, 100 );
260            int maxLifeTime = XMLTools.getNodeAsInt( root, "./deegreewms:MaxLifeTime", nsContext, 3600 );
261            int reqTimeLimit = XMLTools.getNodeAsInt( root, "./deegreewms:RequestTimeLimit", nsContext, 15 );
262            reqTimeLimit *= 1000;
263            double mapQuality = XMLTools.getNodeAsDouble( root, "./deegreewms:MapQuality", nsContext, 0.95 );
264            int maxMapWidth = XMLTools.getNodeAsInt( root, "./deegreewms:MaxMapWidth", nsContext, 1000 );
265            int maxMapHeight = XMLTools.getNodeAsInt( root, "./deegreewms:MaxMapHeight", nsContext, 1000 );
266            int featureInfoRadius = XMLTools.getNodeAsInt( root, "./deegreewms:FeatureInfoRadius", nsContext, 5 );
267            String copyright = XMLTools.getNodeAsString( root, "./deegreewms:Copyright", nsContext, "" );
268    
269            URL dtdLocation = null;
270            if ( XMLTools.getNode( root, "deegreewms:DTDLocation", nsContext ) != null ) {
271                elem = (Element) XMLTools.getRequiredNode( root, "./deegreewms:DTDLocation/deegreewms:OnlineResource",
272                                                           nsContext );
273                OnlineResource olr = parseOnLineResource( elem );
274                dtdLocation = olr.getLinkage().getHref();
275            } else {
276                dtdLocation = new URL( "http://schemas.opengis.net/wms/1.1.1/WMS_MS_Capabilities.dtd" );
277            }
278    
279            URL featureSchemaLocation = null;
280            String featureSchemaNamespace = null;
281            if ( XMLTools.getNode( root, "deegreewms:FeatureInfoSchema", nsContext ) != null ) {
282                featureSchemaNamespace = XMLTools.getRequiredNodeAsString(
283                                                                           root,
284                                                                           "deegreewms:FeatureInfoSchema/deegreewms:Namespace",
285                                                                           nsContext );
286                elem = (Element) XMLTools.getRequiredNode( root, "deegreewms:FeatureInfoSchema/deegreewms:OnlineResource",
287                                                           nsContext );
288                OnlineResource link = parseOnLineResource( elem );
289                featureSchemaLocation = link.getLinkage().getHref();
290            }
291    
292            boolean antiAliased = XMLTools.getNodeAsBoolean( root, "./deegreewms:AntiAliased", nsContext, true );
293    
294            Proxy proxy = parseProxy( root );
295    
296            List<String> supportedVersions = parseSupportedVersions( root );
297    
298            WMSDeegreeParams deegreeParams = new WMSDeegreeParams( cache, maxLifeTime, reqTimeLimit, (float) mapQuality,
299                                                                   ol, maxMapWidth, maxMapHeight, antiAliased,
300                                                                   featureInfoRadius, copyright, null, dtdLocation, proxy,
301                                                                   supportedVersions, featureSchemaLocation,
302                                                                   featureSchemaNamespace );
303    
304            return deegreeParams;
305        }
306    
307        // returns the list of supported versions
308        private List<String> parseSupportedVersions( Node root )
309                                throws XMLParsingException {
310    
311            String[] versions = XMLTools.getNodesAsStrings( root, "./deegreewms:SupportedVersion", nsContext );
312    
313            if ( versions != null )
314                return Arrays.asList( versions );
315    
316            return new ArrayList<String>();
317    
318        }
319    
320        /**
321         * @param root
322         * @return the proxy
323         * @throws XMLParsingException
324         */
325        private Proxy parseProxy( Node root )
326                                throws XMLParsingException {
327    
328            Proxy proxy = null;
329            Node pro = XMLTools.getNode( root, "./deegreewms:Proxy", nsContext );
330            if ( pro != null ) {
331                String proxyHost = XMLTools.getRequiredNodeAsString( pro, "./@proxyHost", nsContext );
332                String proxyPort = XMLTools.getRequiredNodeAsString( pro, "./@proxyPort", nsContext );
333                proxy = new Proxy( proxyHost, proxyPort );
334            }
335    
336            return proxy;
337        }
338    
339        /**
340         * returns the layers offered by the WMS
341         * 
342         * @throws XMLParsingException
343         * @throws UnknownCRSException
344         */
345        @Override
346        protected Layer parseLayers( Element layerElem, Layer parent, ScaleHint scaleHint )
347                                throws XMLParsingException, UnknownCRSException {
348    
349            boolean queryable = XMLTools.getNodeAsBoolean( layerElem, "./@queryable", nsContext, false );
350            int cascaded = XMLTools.getNodeAsInt( layerElem, "./@cascaded", nsContext, 0 );
351            boolean opaque = XMLTools.getNodeAsBoolean( layerElem, "./@opaque", nsContext, false );
352            boolean noSubsets = XMLTools.getNodeAsBoolean( layerElem, "./@noSubsets", nsContext, false );
353            int fixedWidth = XMLTools.getNodeAsInt( layerElem, "./@fixedWidth", nsContext, 0 );
354            int fixedHeight = XMLTools.getNodeAsInt( layerElem, "./@fixedHeight", nsContext, 0 );
355            String name = XMLTools.getNodeAsString( layerElem, "./Name", nsContext, null );
356            String title = XMLTools.getRequiredNodeAsString( layerElem, "./Title", nsContext );
357            String layerAbstract = XMLTools.getNodeAsString( layerElem, "./Abstract", nsContext, null );
358            String[] keywords = XMLTools.getNodesAsStrings( layerElem, "./KeywordList/Keyword", nsContext );
359            String[] srs = XMLTools.getNodesAsStrings( layerElem, "./SRS", nsContext );
360    
361            List<Element> nl = XMLTools.getElements( layerElem, "./BoundingBox", nsContext );
362            // TODO
363            // substitue with Envelope
364            LayerBoundingBox[] bboxes = null;
365            if ( nl.size() == 0 && parent != null ) {
366                // inherit BoundingBoxes from parent layer
367                bboxes = parent.getBoundingBoxes();
368            } else {
369                bboxes = parseLayerBoundingBoxes( nl );
370            }
371    
372            Element llBox = (Element) XMLTools.getNode( layerElem, "./LatLonBoundingBox", nsContext );
373            Envelope llBoundingBox = null;
374            if ( llBox == null && parent != null ) {
375                // inherit LatLonBoundingBox parent layer
376                llBoundingBox = parent.getLatLonBoundingBox();
377            } else {
378                llBoundingBox = parseLatLonBoundingBox( llBox );
379            }
380    
381            Dimension[] dimensions = parseDimensions( layerElem );
382            Extent[] extents = parseExtents( layerElem );
383    
384            Attribution attribution = parseAttribution( layerElem );
385    
386            AuthorityURL[] authorityURLs = parseAuthorityURLs( layerElem );
387    
388            MetadataURL[] metadataURLs = parseMetadataURLs( layerElem );
389    
390            DataURL[] dataURLs = parseDataURL( layerElem );
391    
392            Identifier[] identifiers = parseIdentifiers( layerElem );
393    
394            FeatureListURL[] featureListURLs = parseFeatureListURL( layerElem );
395    
396            Style[] styles = parseStyles( layerElem );
397    
398            scaleHint = parseScaleHint( layerElem, scaleHint );
399    
400            AbstractDataSource[] ds = parseDataSources( layerElem, name, scaleHint );
401    
402            Layer layer = new Layer( queryable, cascaded, opaque, noSubsets, fixedWidth, fixedHeight, name, title,
403                                     layerAbstract, llBoundingBox, attribution, scaleHint, keywords, srs, bboxes,
404                                     dimensions, extents, authorityURLs, identifiers, metadataURLs, dataURLs,
405                                     featureListURLs, styles, null, ds, parent );
406    
407            // get Child layers
408            nl = XMLTools.getElements( layerElem, "./Layer", nsContext );
409            Layer[] layers = new Layer[nl.size()];
410            for ( int i = 0; i < layers.length; i++ ) {
411                layers[i] = parseLayers( nl.get( i ), layer, scaleHint );
412            }
413    
414            // set child layers
415            layer.setLayer( layers );
416    
417            return layer;
418        }
419    
420        /**
421         * 
422         * @param layerElem
423         * @return the data sources
424         * @throws XMLParsingException
425         */
426        protected AbstractDataSource[] parseDataSources( Element layerElem, String layerName, ScaleHint scaleHint )
427                                throws XMLParsingException {
428    
429            List<Node> nl = XMLTools.getNodes( layerElem, "./deegreewms:DataSource", nsContext );
430    
431            AbstractDataSource[] ds = new AbstractDataSource[nl.size()];
432            for ( int i = 0; i < ds.length; i++ ) {
433                boolean failOnEx = XMLTools.getNodeAsBoolean( nl.get( i ), "./@failOnException", nsContext, true );
434                boolean queryable = XMLTools.getNodeAsBoolean( nl.get( i ), "./@queryable", nsContext, false );
435                QualifiedName name = XMLTools.getNodeAsQualifiedName( nl.get( i ), "./deegreewms:Name/text()", nsContext,
436                                                                      new QualifiedName( layerName ) );
437                String stype = XMLTools.getRequiredNodeAsString( nl.get( i ), "./deegreewms:Type", nsContext );
438    
439                int reqTimeLimit = XMLTools.getNodeAsInt( nl.get( i ), "./deegreewms:RequestTimeLimit/text()", nsContext,
440                                                          30 );
441    
442                scaleHint = parseDSScaleHint( (Element) nl.get( i ), scaleHint );
443    
444                String s = "./deegreewms:OWSCapabilities/deegreewms:OnlineResource";
445                Node node = XMLTools.getRequiredNode( nl.get( i ), s, nsContext );
446    
447                URL url = parseOnLineResource( (Element) node ).getLinkage().getHref();
448    
449                Geometry validArea = parseValidArea( nl.get( i ) );
450    
451                try {
452                    if ( "LOCALWFS".equals( stype ) ) {
453                        ds[i] = createLocalWFSDataSource( nl.get( i ), failOnEx, queryable, name, url, scaleHint,
454                                                          validArea, reqTimeLimit );
455                    } else if ( "LOCALWCS".equals( stype ) ) {
456                        ds[i] = createLocalWCSDataSource( nl.get( i ), failOnEx, queryable, name, url, scaleHint,
457                                                          validArea, reqTimeLimit );
458                    } else if ( "REMOTEWFS".equals( stype ) ) {
459                        ds[i] = createRemoteWFSDataSource( nl.get( i ), failOnEx, queryable, name, url, scaleHint,
460                                                           validArea, reqTimeLimit );
461                    } else if ( "REMOTEWCS".equals( stype ) ) {
462                        // int type = AbstractDataSource.REMOTEWCS;
463                        // GetCoverage getCoverage =
464                        parseWCSFilterCondition( nl.get( i ) );
465                        // Color[] colors =
466                        parseTransparentColors( nl.get( i ) );
467                        // TODO
468                        throw new XMLParsingException( "REMOTEWCS is not supported yet!" );
469                    } else if ( "REMOTEWMS".equals( stype ) ) {
470                        ds[i] = createRemoteWMSDataSource( nl.get( i ), failOnEx, queryable, name, url, scaleHint,
471                                                           validArea, reqTimeLimit );
472                    } else {
473                        throw new XMLParsingException( "invalid DataSource type: " + stype + " defined "
474                                                       + "in deegree WMS configuration for DataSource: " + name );
475                    }
476                } catch ( Exception e ) {
477                    LOG.logError( e.getMessage(), e );
478                    throw new XMLParsingException( "could not create service instance for WMS " + "datasource: " + name, e );
479                }
480            }
481    
482            return ds;
483        }
484    
485        /**
486         * parses the ScaleHint for a Datasource
487         * 
488         * @param layerElem
489         * @param scaleHint
490         * @return the scale hint for the datasource
491         * @throws XMLParsingException
492         */
493        protected ScaleHint parseDSScaleHint( Element layerElem, ScaleHint scaleHint )
494                                throws XMLParsingException {
495    
496            Node scNode = XMLTools.getNode( layerElem, "./deegreewms:ScaleHint", nsContext );
497            if ( scNode != null ) {
498                double mn = XMLTools.getNodeAsDouble( scNode, "./@min", nsContext, 0 );
499                double mx = XMLTools.getNodeAsDouble( scNode, "./@max", nsContext, Double.MAX_VALUE );
500                scaleHint = new ScaleHint( mn, mx );
501            }
502    
503            if ( scaleHint == null ) {
504                // set default value to avoid NullPointerException
505                // when accessing a layers scalehint
506                scaleHint = new ScaleHint( 0, Double.MAX_VALUE );
507            }
508    
509            return scaleHint;
510        }
511    
512        /**
513         * returns the area a data source is valid. If the optional element <ValidArea>is not defined in
514         * the configuration <code>null</code>.
515         * 
516         * @param node
517         * @return the geometry
518         * @throws Exception
519         */
520        private Geometry parseValidArea( Node node )
521                                throws XMLParsingException {
522    
523            Geometry geom = null;
524    
525            List<Node> nl = XMLTools.getNodes( node, "./deegreewms:ValidArea/*", nsContext );
526            if ( node != null ) {
527    
528                try {
529                    for ( int i = 0; i < nl.size(); i++ ) {
530    
531                        if ( nl.get( 0 ).getNamespaceURI().equals( GMLNS.toString() ) ) {
532    
533                            geom = GMLGeometryAdapter.wrap( (Element) nl.get( 0 ), null );
534                            break;
535                        }
536                    }
537                } catch ( GeometryException e ) {
538                    e.printStackTrace();
539                    throw new XMLParsingException( "couldn't parse/create valid aera of a datasource", e );
540                }
541            }
542    
543            return geom;
544        }
545    
546        /**
547         * @param vendor
548         * @return the parsed list
549         * @throws XMLParsingException
550         */
551        static List<String> parsePassedParameters( Node vendor )
552                                throws XMLParsingException {
553            List<String> passedParameters = new ArrayList<String>( 10 );
554    
555            if ( vendor == null ) {
556                return passedParameters;
557            }
558    
559            List<Node> nl = XMLTools.getNodes( vendor, "deegreewms:PassedVendorspecificParameter/deegreewms:Name",
560                                               nsContext );
561    
562            for ( Object obj : nl ) {
563                passedParameters.add( ( (Node) obj ).getTextContent().toUpperCase() );
564            }
565    
566            return passedParameters;
567        }
568    
569        /**
570         * @param vendor
571         * @return the parsed map
572         * @throws XMLParsingException
573         */
574        static Map<String, String> parseAddedParameters( Node vendor )
575                                throws XMLParsingException {
576            Map<String, String> addedParameters = new HashMap<String, String>( 10 );
577    
578            if ( vendor == null ) {
579                return addedParameters;
580            }
581    
582            List<Node> nl = XMLTools.getNodes(
583                                               vendor,
584                                               "deegreewms:AddedVendorspecificParameter/deegreewms:VendorspecificParameter",
585                                               nsContext );
586    
587            for ( Object obj : nl ) {
588                String pName = XMLTools.getRequiredNodeAsString( (Node) obj, "deegreewms:Name", nsContext );
589                String pValue = XMLTools.getRequiredNodeAsString( (Node) obj, "deegreewms:Value", nsContext );
590    
591                addedParameters.put( pName, pValue );
592            }
593            return addedParameters;
594        }
595    
596        /**
597         * @param node
598         * @param failOnEx
599         * @param queryable
600         * @param name
601         * @param geoProp
602         * @param url
603         * @param scaleHint
604         * @throws Exception
605         */
606        private RemoteWMSDataSource createRemoteWMSDataSource( Node node, boolean failOnEx, boolean queryable,
607                                                               QualifiedName name, URL url, ScaleHint scaleHint,
608                                                               Geometry validArea, int reqTimeLimit )
609                                throws Exception {
610            int type = AbstractDataSource.REMOTEWMS;
611    
612            String s = "./deegreewms:FeatureInfoTransformation/deegreewms:OnlineResource";
613            Node fitNode = XMLTools.getNode( node, s, nsContext );
614            URL fitURL = null;
615            if ( fitNode != null ) {
616                fitURL = parseOnLineResource( (Element) fitNode ).getLinkage().getHref();
617            }
618    
619            GetMap getMap = parseWMSFilterCondition( node );
620            Color[] colors = parseTransparentColors( node );
621            WMSCapabilities wCapa = null;
622            if ( capaCache.get( url ) != null ) {
623                wCapa = (WMSCapabilities) capaCache.get( url );
624            } else {
625                WMSCapabilitiesDocument doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( url );
626                LOG.logDebug( "Fetching remote WMS capabilities from URL " + url + " succeeded." );
627                wCapa = (WMSCapabilities) doc.parseCapabilities();
628                capaCache.put( url, wCapa );
629            }
630            OGCWebService ows = new RemoteWMService( wCapa );
631    
632            // parse added/passed parameter map/list
633            Node vendor = XMLTools.getNode( node,
634                                            "deegreewms:FilterCondition/deegreewms:VendorspecificParameterDefinition",
635                                            nsContext );
636    
637            List<String> passedParameters = parsePassedParameters( vendor );
638            Map<String, String> addedParameters = parseAddedParameters( vendor );
639    
640            return new RemoteWMSDataSource( queryable, failOnEx, name, type, ows, url, scaleHint, validArea, getMap,
641                                            colors, fitURL, reqTimeLimit, passedParameters, addedParameters );
642        }
643    
644        /**
645         * @param node
646         * @param failOnEx
647         * @param queryable
648         * @param name
649         * @param geoProp
650         * @param url
651         * @param scaleHint
652         * @throws Exception
653         */
654        private RemoteWFSDataSource createRemoteWFSDataSource( Node node, boolean failOnEx, boolean queryable,
655                                                               QualifiedName name, URL url, ScaleHint scaleHint,
656                                                               Geometry validArea, int reqTimeLimit )
657                                throws Exception {
658            int type = AbstractDataSource.REMOTEWFS;
659            String s = "./deegreewms:FeatureInfoTransformation/deegreewms:OnlineResource";
660            Node fitNode = XMLTools.getNode( node, s, nsContext );
661            URL fitURL = null;
662            if ( fitNode != null ) {
663                fitURL = parseOnLineResource( (Element) fitNode ).getLinkage().getHref();
664            }
665            Query query = parseWFSFilterCondition( node );
666    
667            WFSCapabilities wfsCapa = null;
668            if ( capaCache.get( url ) != null ) {
669                wfsCapa = (WFSCapabilities) capaCache.get( url );
670            } else {
671                WFSCapabilitiesDocument wfsDoc = new WFSCapabilitiesDocument();
672                wfsDoc.load( url );
673                wfsCapa = (WFSCapabilities) wfsDoc.parseCapabilities();
674                capaCache.put( url, wfsCapa );
675            }
676            OGCWebService ows = new RemoteWFService( wfsCapa );
677            // OGCWebService ows = null;
678    
679            Node geoPropNode = XMLTools.getNode( node, "deegreewms:GeometryProperty/text()", nsContext );
680            QualifiedName geoProp = DEFAULT_GEO_PROP;
681            if ( geoPropNode != null ) {
682                geoProp = parseQualifiedName( geoPropNode );
683            }
684    
685            return new RemoteWFSDataSource( queryable, failOnEx, name, type, geoProp, ows, url, scaleHint, validArea,
686                                            query, fitURL, reqTimeLimit );
687    
688        }
689    
690        /**
691         * @param node
692         * @param failOnEx
693         * @param queryable
694         * @param name
695         * @param geoProp
696         * @param url
697         * @param scaleHint
698         * @throws Exception
699         */
700        private LocalWCSDataSource createLocalWCSDataSource( Node node, boolean failOnEx, boolean queryable,
701                                                             QualifiedName name, URL url, ScaleHint scaleHint,
702                                                             Geometry validArea, int reqTimeLimit )
703                                throws Exception {
704            int type = AbstractDataSource.LOCALWCS;
705            GetCoverage getCoverage = parseWCSFilterCondition( node );
706            Color[] colors = parseTransparentColors( node );
707            WCSConfiguration configuration = null;
708            if ( capaCache.get( url ) != null ) {
709                configuration = (WCSConfiguration) capaCache.get( url );
710            } else {
711                configuration = WCSConfiguration.create( url );
712                capaCache.put( url, configuration );
713            }
714    
715            OGCWebService ows = new WCService( configuration );
716    
717            return new LocalWCSDataSource( queryable, failOnEx, name, type, ows, url, scaleHint, validArea, getCoverage,
718                                           colors, reqTimeLimit );
719        }
720    
721        /**
722         * @param node
723         * @param failOnEx
724         * @param queryable
725         * @param name
726         * @param geoProp
727         * @param url
728         * @param scaleHint
729         * @throws Exception
730         */
731        private LocalWFSDataSource createLocalWFSDataSource( Node node, boolean failOnEx, boolean queryable,
732                                                             QualifiedName name, URL url, ScaleHint scaleHint,
733                                                             Geometry validArea, int reqTimeLimit )
734                                throws Exception {
735            int type = AbstractDataSource.LOCALWFS;
736            String s = "./deegreewms:FeatureInfoTransformation/deegreewms:OnlineResource";
737            Node fitNode = XMLTools.getNode( node, s, nsContext );
738            URL fitURL = null;
739            if ( fitNode != null ) {
740                fitURL = parseOnLineResource( (Element) fitNode ).getLinkage().getHref();
741            }
742            Query query = parseWFSFilterCondition( node );
743            WFSConfiguration wfsCapa = null;
744            if ( capaCache.get( url ) != null ) {
745                wfsCapa = (WFSConfiguration) capaCache.get( url );
746            } else {
747                WFSConfigurationDocument wfsDoc = new WFSConfigurationDocument();
748                wfsDoc.load( url );
749                wfsCapa = wfsDoc.getConfiguration();
750                // wfsCapa = new WFSCapabilitiesDocument( url ).createCapabilities();
751                capaCache.put( url, wfsCapa );
752            }
753            // OGCWebService ows = WFServiceFactory.getUncachedService( wfsCapa );
754            OGCWebService ows = WFServiceFactory.createInstance( wfsCapa );
755    
756            Node geoPropNode = XMLTools.getNode( node, "deegreewms:GeometryProperty/text()", nsContext );
757            QualifiedName geoProp = DEFAULT_GEO_PROP;
758            if ( geoPropNode != null ) {
759                geoProp = parseQualifiedName( geoPropNode );
760            }
761    
762            LOG.logDebug( "geometry property", geoProp );
763    
764            return new LocalWFSDataSource( queryable, failOnEx, name, type, geoProp, ows, url, scaleHint, validArea, query,
765                                           fitURL, reqTimeLimit );
766        }
767    
768        /**
769         * @param nl
770         * @param type
771         * @throws XMLParsingException
772         */
773        private Color[] parseTransparentColors( Node node )
774                                throws XMLParsingException {
775    
776            String s = "./deegreewms:TransparentColors/deegreewms:Color";
777            List<Node> clnl = XMLTools.getNodes( node, s, nsContext );
778            Color[] colors = new Color[clnl.size()];
779            for ( int j = 0; j < colors.length; j++ ) {
780                colors[j] = Color.decode( XMLTools.getStringValue( clnl.get( j ) ) );
781            }
782    
783            return colors;
784        }
785    
786        /**
787         * 
788         * @param node
789         * @return the query
790         * @throws XMLParsingException
791         */
792        private Query parseWFSFilterCondition( Node node )
793                                throws XMLParsingException {
794    
795            Query o = null;
796    
797            Node queryNode = XMLTools.getNode( node, "./deegreewms:FilterCondition/wfs:Query", nsContext );
798            if ( queryNode != null ) {
799                try {
800                    o = Query.create( (Element) queryNode );
801                } catch ( Exception e ) {
802                    throw new XMLParsingException( StringTools.stackTraceToString( e ) );
803                }
804            }
805    
806            return o;
807        }
808    
809        /**
810         * 
811         * @param node
812         * @return the request
813         * @throws XMLParsingException
814         */
815        private GetCoverage parseWCSFilterCondition( Node node )
816                                throws XMLParsingException {
817    
818            GetCoverage o = null;
819    
820            String id = "" + IDGenerator.getInstance().generateUniqueID();
821    
822            StringBuffer sd = new StringBuffer( 1000 );
823            sd.append( "version=1.0.0&Coverage=%default%&" );
824            sd.append( "CRS=EPSG:4326&BBOX=0,0,1,1&Width=1" );
825            sd.append( "&Height=1&Format=%default%&" );
826            String s = XMLTools.getNodeAsString( node, "./deegreewms:FilterCondition/deegreewms:WCSRequest", nsContext, "" );
827            sd.append( s );
828            try {
829                o = GetCoverage.create( id, sd.toString() );
830            } catch ( Exception e ) {
831                throw new XMLParsingException( "could not create GetCoverage from layer FilterCondition", e );
832            }
833    
834            return o;
835        }
836    
837        /**
838         * 
839         * @param node
840         * @return the request
841         * @throws XMLParsingException
842         */
843        private GetMap parseWMSFilterCondition( Node node )
844                                throws XMLParsingException {
845    
846            GetMap o = null;
847    
848            String id = "" + IDGenerator.getInstance().generateUniqueID();
849    
850            StringBuffer sd = new StringBuffer( 1000 );
851            sd.append( "REQUEST=GetMap&LAYERS=%default%&" );
852            sd.append( "STYLES=&SRS=EPSG:4326&BBOX=0,0,1,1&WIDTH=1&" );
853            sd.append( "HEIGHT=1&FORMAT=%default%" );
854            Map<String, String> map1 = KVP2Map.toMap( sd.toString() );
855            String s = XMLTools.getRequiredNodeAsString( node, "./deegreewms:FilterCondition/deegreewms:WMSRequest",
856                                                         nsContext );
857            Map<String, String> map2 = KVP2Map.toMap( s );
858            if ( map2.get( "VERSION" ) == null && map2.get( "WMTVER" ) == null ) {
859                map2.put( "VERSION", "1.1.1" );
860            }
861            // if no service is set use WMS as default
862            if ( map2.get( "SERVICE" ) == null ) {
863                map2.put( "SERVICE", "WMS" );
864            }
865            map1.putAll( map2 );
866            try {
867                map1.put( "ID", id );
868                o = GetMap.create( map1 );
869            } catch ( Exception e ) {
870                throw new XMLParsingException( "could not create GetMap from layer FilterCondition", e );
871            }
872    
873            return o;
874        }
875    
876        /**
877         * 
878         * @param layerElem
879         * @throws XMLParsingException
880         */
881        @Override
882        protected Style[] parseStyles( Element layerElem )
883                                throws XMLParsingException {
884    
885            List<Node> nl = XMLTools.getNodes( layerElem, "./Style", nsContext );
886            Style[] styles = new Style[nl.size()];
887            for ( int i = 0; i < styles.length; i++ ) {
888                String name = XMLTools.getRequiredNodeAsString( nl.get( i ), "./Name", nsContext );
889                String title = XMLTools.getNodeAsString( nl.get( i ), "./Title", nsContext, null );
890                String styleAbstract = XMLTools.getNodeAsString( nl.get( i ), "./Abstract", nsContext, null );
891                LegendURL[] legendURLs = parseLegendURL( nl.get( i ) );
892                StyleURL styleURL = parseStyleURL( nl.get( i ) );
893                StyleSheetURL styleSheetURL = parseStyleSheetURL( nl.get( i ) );
894                String styleResource = XMLTools.getNodeAsString( nl.get( i ), "deegreewms:StyleResource", nsContext,
895                                                                 "styles.xml" );
896                URL sr = null;
897                try {
898                    sr = resolve( styleResource );
899                } catch ( MalformedURLException e ) {
900                    throw new XMLParsingException( "could not parse style resource of style: " + name, e );
901                }
902    
903                String layerName = XMLTools.getRequiredNodeAsString( layerElem, "Name", nsContext );
904                if ( name == null || name.length() == 0 ) {
905                    name = "default:" + layerName;
906                }
907                if ( name.equals( "default" ) ) {
908                    name += ":" + layerName;
909                }
910                if ( name.equals( "default:" ) ) {
911                    name += layerName;
912                }
913    
914                styles[i] = new Style( name, title, styleAbstract, legendURLs, styleSheetURL, styleURL, sr );
915            }
916    
917            return styles;
918        }
919    
920    }