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