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