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