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