001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wmps/configuration/WMPSConfigurationDocument.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.wmps.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.HashMap;
052    import java.util.List;
053    import java.util.Map;
054    
055    import javax.xml.transform.TransformerException;
056    
057    import org.deegree.datatypes.QualifiedName;
058    import org.deegree.enterprise.Proxy;
059    import org.deegree.framework.log.ILogger;
060    import org.deegree.framework.log.LoggerFactory;
061    import org.deegree.framework.util.BootLogger;
062    import org.deegree.framework.util.IDGenerator;
063    import org.deegree.framework.util.KVP2Map;
064    import org.deegree.framework.util.StringTools;
065    import org.deegree.framework.xml.InvalidConfigurationException;
066    import org.deegree.framework.xml.XMLFragment;
067    import org.deegree.framework.xml.XMLParsingException;
068    import org.deegree.framework.xml.XMLTools;
069    import org.deegree.framework.xml.XSLTDocument;
070    import org.deegree.model.crs.UnknownCRSException;
071    import org.deegree.model.metadata.iso19115.OnlineResource;
072    import org.deegree.model.spatialschema.Envelope;
073    import org.deegree.model.spatialschema.GMLGeometryAdapter;
074    import org.deegree.model.spatialschema.Geometry;
075    import org.deegree.model.spatialschema.GeometryException;
076    import org.deegree.ogcbase.CommonNamespaces;
077    import org.deegree.ogcwebservices.OGCWebService;
078    import org.deegree.ogcwebservices.getcapabilities.MetadataURL;
079    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
080    import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification;
081    import org.deegree.ogcwebservices.getcapabilities.ServiceProvider;
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.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.wmps.capabilities.WMPSCapabilitiesDocument;
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.GazetteerParam;
100    import org.deegree.ogcwebservices.wms.capabilities.Identifier;
101    import org.deegree.ogcwebservices.wms.capabilities.Layer;
102    import org.deegree.ogcwebservices.wms.capabilities.LayerBoundingBox;
103    import org.deegree.ogcwebservices.wms.capabilities.LegendURL;
104    import org.deegree.ogcwebservices.wms.capabilities.ScaleHint;
105    import org.deegree.ogcwebservices.wms.capabilities.Style;
106    import org.deegree.ogcwebservices.wms.capabilities.StyleSheetURL;
107    import org.deegree.ogcwebservices.wms.capabilities.StyleURL;
108    import org.deegree.ogcwebservices.wms.capabilities.UserDefinedSymbolization;
109    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
110    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
111    import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
112    import org.deegree.ogcwebservices.wms.configuration.LocalWCSDataSource;
113    import org.deegree.ogcwebservices.wms.configuration.LocalWFSDataSource;
114    import org.deegree.ogcwebservices.wms.configuration.RemoteWFSDataSource;
115    import org.deegree.ogcwebservices.wms.configuration.RemoteWMSDataSource;
116    import org.deegree.ogcwebservices.wms.configuration.WMSConfigurationDocument;
117    import org.deegree.ogcwebservices.wms.operation.GetMap;
118    import org.w3c.dom.Element;
119    import org.w3c.dom.Node;
120    import org.xml.sax.SAXException;
121    
122    /**
123     * Represents an XML configuration document for a deegree WMPS 1.0 instance, i.e. it consists of all
124     * sections common to an OGC WMS 1.1.1 capabilities document plus a deegree specific section named
125     * <code>deegreeParams</code> and... TODO
126     * 
127     * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh</a>
128     * @author last edited by: $Author: jmays $
129     * 
130     * @version 2.0, $Revision: 7860 $, $Date: 2007-07-26 17:08:10 +0200 (Do, 26 Jul 2007) $
131     */
132    public class WMPSConfigurationDocument extends WMPSCapabilitiesDocument {
133    
134        private static final long serialVersionUID = -7940857863171829848L;
135    
136        private static final ILogger LOG = LoggerFactory.getLogger( WMPSConfigurationDocument.class );
137    
138        protected static final URI DEEGREEWPSNS = CommonNamespaces.DEEGREEWMPS;
139    
140        private static final String XML_TEMPLATE = "WMPSConfigurationTemplate.xml";
141    
142        private static final String XSLT_TEMPLATE_NAME = "WMPSConfigurationTransform.xsl";
143    
144        private static XSLTDocument XSLT_TEMPLATE;
145    
146        private static Map<URL, Object> capaCache = new HashMap<URL, Object>();
147    
148        static {
149            XSLT_TEMPLATE = new XSLTDocument();
150            try {
151                XSLT_TEMPLATE.load( WMPSConfigurationDocument.class.getResource( XSLT_TEMPLATE_NAME ) );
152            } catch ( Exception e ) {
153                BootLogger.logError( "Error loading XSLT sheet in WMPSConfigurationDocument.", e );
154            }
155        }
156    
157        /**
158         * Creates a skeleton capabilities document that contains the mandatory elements only.
159         * 
160         * @throws IOException
161         * @throws SAXException
162         */
163        @Override
164        public void createEmptyDocument()
165                                throws IOException, SAXException {
166            URL url = WMPSConfigurationDocument.class.getResource( XML_TEMPLATE );
167            if ( url == null ) {
168                throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." );
169            }
170            load( url );
171        }
172    
173        /**
174         * Creates a class representation of the document.
175         * 
176         * @return class representation of the configuration document
177         * @throws InvalidConfigurationException
178         */
179        public WMPSConfiguration parseConfiguration()
180                                throws InvalidConfigurationException {
181    
182            try {
183                // transform document to fill missing elements and attributes with default values
184                XMLFragment frag = XSLT_TEMPLATE.transform( this );
185                this.setRootElement( frag.getRootElement() );
186            } catch ( TransformerException e ) {
187                String msg = "Error transforming WMPS configuration document (in order to fill " + "in default value). "
188                             + e.getMessage();
189                LOG.logError( msg, e );
190                throw new InvalidConfigurationException( msg, e );
191            }
192    
193            ServiceIdentification serviceIdentification = null;
194            ServiceProvider serviceProvider = null;
195            UserDefinedSymbolization uds = null;
196            OperationsMetadata metadata = null;
197            Layer layer = null;
198            WMPSDeegreeParams params = null;
199            String version = parseVersion();
200            try {
201                Node node = XMLTools.getRequiredNode( getRootElement(), "deegreewmps:DeegreeParam", nsContext );
202                params = parseDeegreeParams( node );
203                serviceIdentification = parseServiceIdentification();
204                serviceProvider = parseServiceProvider();
205                uds = parseUserDefinedSymbolization();
206                metadata = parseOperationsMetadata();
207                Element layerElem = (Element) XMLTools.getRequiredNode( getRootElement(), "./Capability/Layer", nsContext );
208                layer = parseLayers( layerElem, null );
209            } catch ( XMLParsingException e ) {
210                e.printStackTrace();
211                throw new InvalidConfigurationException( e.getMessage() + StringTools.stackTraceToString( e ) );
212            } catch ( MalformedURLException e ) {
213                throw new InvalidConfigurationException( e.getMessage() + " - " + StringTools.stackTraceToString( e ) );
214            } catch ( UnknownCRSException e ) {
215                throw new InvalidConfigurationException( getClass().getName(), e.getMessage() );
216            }
217            WMPSConfiguration wmpsConfiguration = new WMPSConfiguration( version, serviceIdentification, serviceProvider,
218                                                                         uds, metadata, layer, params, getSystemId() );
219    
220            return wmpsConfiguration;
221        }
222    
223        /**
224         * Creates a class representation of the <code>deegreeParams</code>- section.
225         * 
226         * @param root
227         * @return WMPSDeegreeParams
228         * @throws XMLParsingException
229         * @throws MalformedURLException
230         */
231        public WMPSDeegreeParams parseDeegreeParams( Node root )
232                                throws XMLParsingException, MalformedURLException {
233    
234            String xPath = "./deegreewmps:DefaultOnlineResource";
235            Element elem = (Element) XMLTools.getRequiredNode( root, xPath, nsContext );
236    
237            OnlineResource ol = parseOnLineResource( elem );
238            xPath = "./deegreewmps:CacheSize";
239            int cache = XMLTools.getNodeAsInt( root, xPath, nsContext, 100 );
240            xPath = "./deegreewmps:MaxLifeTime";
241            int maxLifeTime = XMLTools.getNodeAsInt( root, xPath, nsContext, 3600 );
242            xPath = "./deegreewmps:RequestTimeLimit";
243            int reqTimeLimit = XMLTools.getNodeAsInt( root, xPath, nsContext, 15 );
244            reqTimeLimit *= 1000;
245            xPath = "./deegreewmps:MapQuality";
246            double mapQuality = XMLTools.getNodeAsDouble( root, xPath, nsContext, 0.95 );
247            xPath = "./deegreewmps:MaxMapWidth";
248            int maxMapWidth = XMLTools.getNodeAsInt( root, xPath, nsContext, 1000 );
249            xPath = "./deegreewmps:MaxMapHeight";
250            int maxMapHeight = XMLTools.getNodeAsInt( root, xPath, nsContext, 1000 );
251            xPath = "./deegreewmps:FeatureInfoRadius";
252            int featureInfoRadius = XMLTools.getNodeAsInt( root, xPath, nsContext, 5 );
253            xPath = "./deegreewmps:Copyright";
254            String copyright = XMLTools.getNodeAsString( root, xPath, nsContext, "" );
255            URL dtdLocation = null;
256            xPath = "deegreewmps:DTDLocation";
257            if ( XMLTools.getNode( root, xPath, nsContext ) != null ) {
258                xPath = "./deegreewmps:DTDLocation/deegreewmps:OnlineResource";
259                elem = (Element) XMLTools.getRequiredNode( root, xPath, 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            xPath = "./deegreewmps:AntiAliased";
266            boolean antiAliased = XMLTools.getNodeAsBoolean( root, xPath, nsContext, true );
267            xPath = "./deegreewmps:GazetteerParameter";
268            elem = (Element) XMLTools.getNode( root, xPath, nsContext );
269            GazetteerParam gazetteer = null;
270            if ( elem != null ) {
271                gazetteer = parseGazetteerParameter( elem );
272            }
273    
274            Proxy proxy = parseProxy( root );
275    
276            List<String> synchList = parseSynchTemplates( root );
277    
278            CacheDatabase cacheDatabase = parseCacheDatabase( root );
279    
280            PrintMapParam printMapParam = parsePrintMapParam( root );
281    
282            WMPSDeegreeParams deegreeParams = new WMPSDeegreeParams( cache, maxLifeTime, reqTimeLimit, (float) mapQuality,
283                                                                     ol, maxMapWidth, maxMapHeight, antiAliased,
284                                                                     featureInfoRadius, copyright, gazetteer, null,
285                                                                     dtdLocation, proxy, synchList, cacheDatabase,
286                                                                     printMapParam );
287    
288            return deegreeParams;
289        }
290    
291        /**
292         * Parse the cache database parameters used by the wmps to store the asynchronous requests.
293         * 
294         * @param root
295         * @return CacheDatabase
296         * @throws XMLParsingException
297         */
298        private CacheDatabase parseCacheDatabase( Node root )
299                                throws XMLParsingException {
300    
301            CacheDatabase cacheDatabase = null;
302            String xPath = "./deegreewmps:CacheDatabase";
303            Node cacheDb = XMLTools.getNode( root, xPath, nsContext );
304            if ( cacheDb != null ) {
305                xPath = "./deegreewmps:JDBCConnection";
306                Node jdbcConnection = XMLTools.getRequiredNode( cacheDb, xPath, nsContext );
307                String driver = XMLTools.getRequiredNodeAsString( jdbcConnection, "./deegreewmps:Driver", nsContext );
308                String url = XMLTools.getRequiredNodeAsString( jdbcConnection, "./deegreewmps:Url", nsContext );
309                String user = XMLTools.getRequiredNodeAsString( jdbcConnection, "./deegreewmps:User", nsContext );
310                String password = XMLTools.getRequiredNodeAsString( jdbcConnection, "./deegreewmps:Password", nsContext );
311                cacheDatabase = new CacheDatabase( driver, url, user, password );
312                LOG.logDebug( "Successfully parsed the deegree wmps cache database parameters." );
313            }
314    
315            return cacheDatabase;
316        }
317    
318        /**
319         * Parse the PrintMapParam node and retrieve the (jasper reports)template directory, the default
320         * template name if none is specified in the request. Also parse the output directory location
321         * and the location of the printed image output directory.
322         * 
323         * @param root
324         * @return PrintMapParam
325         * @throws XMLParsingException
326         * @throws MalformedURLException
327         */
328        private PrintMapParam parsePrintMapParam( Node root )
329                                throws XMLParsingException, MalformedURLException {
330    
331            Node printParam = XMLTools.getRequiredNode( root, "./deegreewmps:PrintMapParam", nsContext );
332            // set default as pdf
333            String format = XMLTools.getNodeAsString( printParam, "./deegreewmps:Format", nsContext, "pdf" );
334            Node templ = XMLTools.getRequiredNode( printParam, "./deegreewmps:Template", nsContext );
335            String templateDirectory = XMLTools.getRequiredNodeAsString( templ, "./deegreewmps:Directory", nsContext );
336    
337            templateDirectory = this.resolve( templateDirectory ).toExternalForm();
338            if ( !templateDirectory.endsWith( "/" ) ) {
339                templateDirectory = templateDirectory + '/';
340            }
341            String plotDirectory = XMLTools.getRequiredNodeAsString( printParam, "./deegreewmps:PlotDirectory", nsContext );
342            plotDirectory = this.resolve( plotDirectory ).toExternalForm();
343            String onlineResource = XMLTools.getRequiredNodeAsString( printParam, "./deegreewmps:OnlineResource", nsContext );
344            String plotImgDir = XMLTools.getRequiredNodeAsString( printParam, "./deegreewmps:PlotImageDirectory", nsContext );
345            plotImgDir = this.resolve( plotImgDir ).toExternalForm();
346            String adminMail = XMLTools.getRequiredNodeAsString( printParam, "./deegreewmps:AdministratorEMailAddress",
347                                                                 nsContext );
348            String mailHost = XMLTools.getRequiredNodeAsString( printParam, "./deegreewmps:MailHost", nsContext );
349    
350            String mailTextTemplate = XMLTools.getNodeAsString( printParam, "./deegreewmps:MailTextTemplate", nsContext,
351                                                                "You can access the printMap result at {1}" );
352    
353            int targetRes = XMLTools.getNodeAsInt( printParam, "./deegreewmps:TargetResolution", nsContext, 300 );
354    
355            PrintMapParam printMapParam = new PrintMapParam( format, templateDirectory, onlineResource, plotDirectory,
356                                                             plotImgDir, adminMail, mailHost, mailTextTemplate, targetRes );
357    
358            return printMapParam;
359        }
360    
361        /**
362         * parses the list of templates that shall be handled synchronously
363         * 
364         * @param root
365         * @return List
366         * @throws XMLParsingException
367         */
368        private List<String> parseSynchTemplates( Node root )
369                                throws XMLParsingException {
370    
371            String xPath = "./deegreewmps:SynchronousTemplates/deegreewmps:Template";
372            String[] nodes = XMLTools.getNodesAsStrings( root, xPath, nsContext );
373            List<String> list = new ArrayList<String>( nodes.length );
374            for ( int i = 0; i < nodes.length; i++ ) {
375                list.add( nodes[i] );
376            }
377    
378            return list;
379        }
380    
381        /**
382         * @param root
383         * @return Proxy
384         * @throws XMLParsingException
385         */
386        private Proxy parseProxy( Node root )
387                                throws XMLParsingException {
388    
389            Proxy proxy = null;
390            Node pro = XMLTools.getNode( root, "./deegreewmps:Proxy", nsContext );
391            if ( pro != null ) {
392                String proxyHost = XMLTools.getRequiredNodeAsString( pro, "./@proxyHost", nsContext );
393                String proxyPort = XMLTools.getRequiredNodeAsString( pro, "./@proxyPort", nsContext );
394                proxy = new Proxy( proxyHost, proxyPort );
395            }
396    
397            return proxy;
398        }
399    
400        /**
401         * creates an object that describes the access to a gazetteer if one have been defined at the
402         * <DeegreeParam>section of the capabilities/configuration
403         * 
404         * @param element
405         * @return GazetteerParam
406         * @throws XMLParsingException
407         */
408        private GazetteerParam parseGazetteerParameter( Element element )
409                                throws XMLParsingException {
410    
411            GazetteerParam gazetteer = null;
412    
413            if ( element != null ) {
414                String xPath = "./deegreewmps:OnlineResource";
415                Element elem = (Element) XMLTools.getRequiredNode( element, xPath, nsContext );
416                OnlineResource olr = parseOnLineResource( elem );
417                URL onlineResource = olr.getLinkage().getHref();
418                // optional: <LocationRadius>, default: 10
419                double radius = XMLTools.getNodeAsDouble( element, "LocationRadius", nsContext, 10 );
420                gazetteer = new GazetteerParam( onlineResource, radius );
421            }
422    
423            return gazetteer;
424        }
425    
426        /**
427         * returns the layers offered by the WMS
428         * 
429         * @param layerElem
430         * @param parent
431         * @return Layer
432         * @throws XMLParsingException
433         * @throws UnknownCRSException
434         */
435        @Override
436        protected Layer parseLayers( Element layerElem, Layer parent )
437                                throws XMLParsingException, UnknownCRSException {
438    
439            boolean queryable = XMLTools.getNodeAsBoolean( layerElem, "./@queryable", nsContext, false );
440            int cascaded = XMLTools.getNodeAsInt( layerElem, "./@cascaded", nsContext, 0 );
441            boolean opaque = XMLTools.getNodeAsBoolean( layerElem, "./@opaque", nsContext, false );
442            boolean noSubsets = XMLTools.getNodeAsBoolean( layerElem, "./@noSubsets", nsContext, false );
443            int fixedWidth = XMLTools.getNodeAsInt( layerElem, "./@fixedWidth", nsContext, 0 );
444            int fixedHeight = XMLTools.getNodeAsInt( layerElem, "./@fixedHeight", nsContext, 0 );
445            String name = XMLTools.getNodeAsString( layerElem, "./Name", nsContext, null );
446            String title = XMLTools.getRequiredNodeAsString( layerElem, "./Title", nsContext );
447            String layerAbstract = XMLTools.getNodeAsString( layerElem, "./Abstract", nsContext, null );
448            String[] keywords = XMLTools.getNodesAsStrings( layerElem, "./KeywordList/Keyword", nsContext );
449            String[] srs = XMLTools.getNodesAsStrings( layerElem, "./SRS", nsContext );
450            List nl = XMLTools.getNodes( layerElem, "./BoundingBox", nsContext );
451            // substitue with Envelope
452            LayerBoundingBox[] bboxes = null;
453            if ( nl.size() == 0 && parent != null ) {
454                // inherit BoundingBoxes from parent layer
455                bboxes = parent.getBoundingBoxes();
456            } else {
457                bboxes = parseLayerBoundingBoxes( nl );
458            }
459    
460            Element llBox = (Element) XMLTools.getNode( layerElem, "./LatLonBoundingBox", nsContext );
461            Envelope llBoundingBox = null;
462            if ( llBox == null && parent != null ) {
463                // inherit LatLonBoundingBox parent layer
464                llBoundingBox = parent.getLatLonBoundingBox();
465            } else {
466                llBoundingBox = parseLatLonBoundingBox( llBox );
467            }
468    
469            Dimension[] dimensions = parseDimensions( layerElem );
470            Extent[] extents = parseExtents( layerElem );
471            Attribution attribution = parseAttribution( layerElem );
472            AuthorityURL[] authorityURLs = parseAuthorityURLs( layerElem );
473            MetadataURL[] metadataURLs = parseMetadataURLs( layerElem );
474            DataURL[] dataURLs = parseDataURL( layerElem );
475            Identifier[] identifiers = parseIdentifiers( layerElem );
476            FeatureListURL[] featureListURLs = parseFeatureListURL( layerElem );
477            Style[] styles = parseStyles( layerElem );
478            ScaleHint scaleHint = parseScaleHint( layerElem );
479            AbstractDataSource[] ds = parseDataSources( layerElem, name );
480    
481            Layer layer = new Layer( queryable, cascaded, opaque, noSubsets, fixedWidth, fixedHeight, name, title,
482                                     layerAbstract, llBoundingBox, attribution, scaleHint, keywords, srs, bboxes,
483                                     dimensions, extents, authorityURLs, identifiers, metadataURLs, dataURLs,
484                                     featureListURLs, styles, null, ds, parent );
485    
486            // get Child layers
487            nl = XMLTools.getNodes( layerElem, "./Layer", nsContext );
488            Layer[] layers = new Layer[nl.size()];
489            for ( int i = 0; i < layers.length; i++ ) {
490                layers[i] = parseLayers( (Element) nl.get( i ), layer );
491            }
492            // set child layers
493            layer.setLayer( layers );
494    
495            return layer;
496        }
497    
498        /**
499         * Parse the Datasources element
500         * 
501         * @param layerElem
502         * @param layerName
503         * @return AbstractDataSource[]
504         * @throws XMLParsingException
505         */
506        private AbstractDataSource[] parseDataSources( Element layerElem, String layerName )
507                                throws XMLParsingException {
508    
509            List nl = XMLTools.getNodes( layerElem, "./deegreewmps:DataSource", nsContext );
510    
511            AbstractDataSource[] ds = new AbstractDataSource[nl.size()];
512            for ( int i = 0; i < ds.length; i++ ) {
513    
514                boolean failOnEx = XMLTools.getNodeAsBoolean( (Node) nl.get( i ), "./@failOnException", nsContext, true );
515    
516                boolean queryable = XMLTools.getNodeAsBoolean( (Node) nl.get( i ), "./@queryable", nsContext, false );
517    
518                QualifiedName name = XMLTools.getNodeAsQualifiedName( (Node) nl.get( i ), "./deegreewmps:Name/text()",
519                                                                      nsContext, new QualifiedName( layerName ) );
520    
521                String stype = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), "./deegreewmps:Type", nsContext );
522    
523                String xPath = "./deegreewmps:OWSCapabilities/deegreewmps:OnlineResource";
524                Node node = XMLTools.getRequiredNode( (Node) nl.get( i ), xPath, nsContext );
525    
526                URL url = parseOnLineResource( (Element) node ).getLinkage().getHref();
527                ScaleHint scaleHint = parseScaleHint( (Node) nl.get( i ) );
528                Geometry validArea = parseValidArea( (Node) nl.get( i ) );
529    
530                try {
531                    if ( "LOCALWFS".equals( stype ) ) {
532                        ds[i] = createLocalWFSDataSource( (Node) nl.get( i ), failOnEx, queryable, name, url, scaleHint,
533                                                          validArea, 60 );
534                    } else if ( "LOCALWCS".equals( stype ) ) {
535                        ds[i] = createLocalWCSDataSource( (Node) nl.get( i ), failOnEx, queryable, name, url, scaleHint,
536                                                          validArea, 60 );
537                    } else if ( "REMOTEWFS".equals( stype ) ) {
538                        ds[i] = createRemoteWFSDataSource( (Node) nl.get( i ), failOnEx, queryable, name, url, scaleHint,
539                                                           validArea, 60 );
540                    } else if ( "REMOTEWCS".equals( stype ) ) {
541                        // TODO
542                        // int type = AbstractDataSource.REMOTEWCS;
543                        // GetCoverage getCoverage = parseWCSFilterCondition( (Node) nl.get( i ) );
544                        // Color[] colors = parseTransparentColors( (Node) nl.get( i ) );
545                        throw new UnsupportedOperationException( "REMOTEWCS is not supported as yet!" );
546                    } else if ( "REMOTEWMS".equals( stype ) ) {
547                        ds[i] = createRemoteWMSDataSource( (Node) nl.get( i ), failOnEx, queryable, name, url, scaleHint,
548                                                           validArea, 60 );
549                    } else {
550                        throw new XMLParsingException( "invalid DataSource type: " + stype + " defined in deegree WMS "
551                                                       + "configuration for DataSource: " + name );
552                    }
553                } catch ( Exception e ) {
554                    throw new XMLParsingException( "could not create service instance for " + "WMPS datasource: " + name, e );
555                }
556            }
557    
558            return ds;
559        }
560    
561        /**
562         * returns the area a data source is valid. If the optional element <ValidArea>is not defined in
563         * the configuration returns <code>null</code>.
564         * 
565         * @param node
566         * @return Geometry
567         * @throws XMLParsingException
568         */
569        private Geometry parseValidArea( Node node )
570                                throws XMLParsingException {
571    
572            Geometry geom = null;
573            List nl = XMLTools.getNodes( node, "./deegreewmps:ValidArea/*", nsContext );
574            if ( node != null ) {
575                try {
576                    for ( int i = 0; i < nl.size(); i++ ) {
577                        if ( ( (Node) nl.get( 0 ) ).getNamespaceURI().equals( GMLNS ) ) {
578                            geom = GMLGeometryAdapter.wrap( (Element) nl.get( 0 ), null );
579                            break;
580                        }
581                    }
582                } catch ( GeometryException e ) {
583                    throw new XMLParsingException( "couldn't parse/create valid area of a " + "datasource", e );
584                }
585            }
586    
587            return geom;
588        }
589    
590        /**
591         * Create a RemoteWMS datasource.
592         * 
593         * @param node
594         * @param failOnEx
595         * @param queryable
596         * @param name
597         * @param url
598         * @param scaleHint
599         * @param validArea
600         * @param reqTimeLimit
601         * @return XMLParsingException
602         * @throws Exception
603         */
604        private RemoteWMSDataSource createRemoteWMSDataSource( Node node, boolean failOnEx, boolean queryable,
605                                                               QualifiedName name, URL url, ScaleHint scaleHint,
606                                                               Geometry validArea, int reqTimeLimit )
607                                throws Exception {
608    
609            int type = AbstractDataSource.REMOTEWMS;
610            String xPath = "./deegreewmps:FeatureInfoTransformation/deegreewmps:OnlineResource";
611            Node fitNode = XMLTools.getNode( node, xPath, nsContext );
612            URL fitURL = null;
613            if ( fitNode != null ) {
614                fitURL = parseOnLineResource( (Element) fitNode ).getLinkage().getHref();
615            }
616    
617            GetMap getMap = parseWMSFilterCondition( node );
618            Color[] colors = parseTransparentColors( node );
619            WMSCapabilities wCapa = null;
620            try {
621                if ( capaCache.get( url ) != null ) {
622                    wCapa = (WMSCapabilities) capaCache.get( url );
623                } else {
624                    WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
625                    doc.load( url );
626                    wCapa = (WMSCapabilities) doc.parseCapabilities();
627                    capaCache.put( url, wCapa );
628                }
629            } catch ( Exception e ) {
630                LOG.logError( "could not connet: " + url, e );
631            }
632            OGCWebService ows = new RemoteWMService( wCapa );
633    
634            // parse added/passed parameter map/list
635            Node vendor = XMLTools.getNode( node,
636                                            "deegreewmps:FilterCondition/deegreewmps:VendorspecificParameterDefinition",
637                                            nsContext );
638    
639            List<String> passedParameters = parsePassedParameters( vendor );
640            Map<String, String> addedParameters = parseAddedParameters( vendor );
641    
642            return new RemoteWMSDataSource( queryable, failOnEx, name, type, ows, url, scaleHint, validArea, getMap,
643                                            colors, fitURL, reqTimeLimit, passedParameters, addedParameters );
644        }
645        
646        /**
647         * @param vendor
648         * @return the parsed list
649         * @throws XMLParsingException
650         */
651        private static List<String> parsePassedParameters( Node vendor )
652                                throws XMLParsingException {
653            List<String> passedParameters = new ArrayList<String>( 10 );
654    
655            if ( vendor == null ) {
656                return passedParameters;
657            }
658    
659            List<Node> nl = XMLTools.getNodes( vendor, "deegreewmps:PassedVendorspecificParameter/deegreewmps:Name",
660                                               nsContext );
661    
662            for ( Object obj : nl ) {
663                passedParameters.add( ( (Node) obj ).getTextContent().toUpperCase() );
664            }
665    
666            return passedParameters;
667        }
668    
669        /**
670         * @param vendor
671         * @return the parsed map
672         * @throws XMLParsingException
673         */
674        private static Map<String, String> parseAddedParameters( Node vendor )
675                                throws XMLParsingException {
676            Map<String, String> addedParameters = new HashMap<String, String>( 10 );
677    
678            if ( vendor == null ) {
679                return addedParameters;
680            }
681    
682            List<Node> nl = XMLTools.getNodes( vendor,
683                                               "deegreewmps:AddedVendorspecificParameter/deegreewmps:VendorspecificParameter",
684                                               nsContext );
685    
686            for ( Object obj : nl ) {
687                String pName = XMLTools.getRequiredNodeAsString( (Node) obj, "deegreewmps:Name", nsContext );
688                String pValue = XMLTools.getRequiredNodeAsString( (Node) obj, "deegreewmps:Value", nsContext );
689    
690                addedParameters.put( pName, pValue );
691            }
692            return addedParameters;
693        }
694    
695    
696        /**
697         * Create a Remote WFS datasource.
698         * 
699         * @param node
700         * @param failOnEx
701         * @param queryable
702         * @param name
703         * @param url
704         * @param scaleHint
705         * @param validArea
706         * @param reqTimeLimit
707         * @return RemoteWFSDataSource
708         * @throws Exception
709         */
710        private RemoteWFSDataSource createRemoteWFSDataSource( Node node, boolean failOnEx, boolean queryable,
711                                                               QualifiedName name, URL url, ScaleHint scaleHint,
712                                                               Geometry validArea, int reqTimeLimit )
713                                throws Exception {
714    
715            int type = AbstractDataSource.REMOTEWFS;
716            String xPath = "./deegreewmps:FeatureInfoTransformation/deegreewmps:OnlineResource";
717            Node fitNode = XMLTools.getNode( node, xPath, nsContext );
718            URL fitURL = null;
719            if ( fitNode != null ) {
720                fitURL = parseOnLineResource( (Element) fitNode ).getLinkage().getHref();
721            }
722            Query query = parseWFSFilterCondition( node );
723    
724            WFSCapabilities wfsCapa = null;
725            if ( capaCache.get( url ) != null ) {
726                wfsCapa = (WFSCapabilities) capaCache.get( url );
727            } else {
728                WFSCapabilitiesDocument wfsDoc = new WFSCapabilitiesDocument();
729                wfsDoc.load( url );
730                wfsCapa = (WFSCapabilities) wfsDoc.parseCapabilities();
731                capaCache.put( url, wfsCapa );
732            }
733            // OGCWebService ows = new RemoteWFService( wfsCapa );
734            OGCWebService ows = null;
735            xPath = "./deegreewmps:GeometryProperty/text()";
736            QualifiedName geom = new QualifiedName( "app", "GEOM", new URI( "http://www.deegree.org/app" ) );
737            QualifiedName geoProp = XMLTools.getNodeAsQualifiedName( node, xPath, nsContext, geom );
738    
739            return new RemoteWFSDataSource( queryable, failOnEx, name, type, geoProp, ows, url, scaleHint, validArea,
740                                            query, fitURL, reqTimeLimit );
741    
742        }
743    
744        /**
745         * Create a Local WCS Datasource
746         * 
747         * @param node
748         * @param failOnEx
749         * @param queryable
750         * @param name
751         * @param url
752         * @param scaleHint
753         * @param validArea
754         * @param reqTimeLimit
755         * @return RemoteWFSDataSource
756         * @throws Exception
757         */
758        private LocalWCSDataSource createLocalWCSDataSource( Node node, boolean failOnEx, boolean queryable,
759                                                             QualifiedName name, URL url, ScaleHint scaleHint,
760                                                             Geometry validArea, int reqTimeLimit )
761                                throws Exception {
762    
763            int type = AbstractDataSource.LOCALWCS;
764            GetCoverage getCoverage = parseWCSFilterCondition( node );
765            Color[] colors = parseTransparentColors( node );
766            WCSConfiguration configuration = null;
767            if ( capaCache.get( url ) != null ) {
768                configuration = (WCSConfiguration) capaCache.get( url );
769            } else {
770                configuration = WCSConfiguration.create( url );
771                capaCache.put( url, configuration );
772            }
773    
774            OGCWebService ows = new WCService( configuration );
775    
776            return new LocalWCSDataSource( queryable, failOnEx, name, type, ows, url, scaleHint, validArea, getCoverage,
777                                           colors, reqTimeLimit );
778        }
779    
780        /**
781         * Create a Local WFS Datasource
782         * 
783         * @param node
784         * @param failOnEx
785         * @param queryable
786         * @param name
787         * @param url
788         * @param scaleHint
789         * @param validArea
790         * @param reqTimeLimit
791         * @return LocalWFSDataSource
792         * @throws Exception
793         */
794        private LocalWFSDataSource createLocalWFSDataSource( Node node, boolean failOnEx, boolean queryable,
795                                                             QualifiedName name, URL url, ScaleHint scaleHint,
796                                                             Geometry validArea, int reqTimeLimit )
797                                throws Exception {
798    
799            int type = AbstractDataSource.LOCALWFS;
800            String xPath = null;
801            Query query = parseWFSFilterCondition( node );
802            WFSConfiguration wfsCapa = null;
803            if ( capaCache.get( url ) != null ) {
804                wfsCapa = (WFSConfiguration) capaCache.get( url );
805            } else {
806                WFSConfigurationDocument wfsDoc = new WFSConfigurationDocument();
807                wfsDoc.load( url );
808                wfsCapa = wfsDoc.getConfiguration();
809                capaCache.put( url, wfsCapa );
810            }
811            // OGCWebService ows = WFServiceFactory.getUncachedService( wfsCapa );
812            OGCWebService ows = WFServiceFactory.createInstance( wfsCapa );
813    
814            QualifiedName geom = new QualifiedName( "app", "GEOM", new URI( "http://www.deegree.org/app" ) );
815            xPath = "./deegreewmps:GeometryProperty/text()";
816            QualifiedName geoProp = XMLTools.getNodeAsQualifiedName( node, xPath, nsContext, geom );
817    
818            return new LocalWFSDataSource( queryable, failOnEx, name, type, geoProp, ows, url, scaleHint, validArea, query,
819                                           null, reqTimeLimit );
820        }
821    
822        /**
823         * Parse trasparent colors.
824         * 
825         * @param node
826         * @return Color[]
827         * @throws XMLParsingException
828         */
829        private Color[] parseTransparentColors( Node node )
830                                throws XMLParsingException {
831    
832            String xPath = "./deegreewmps:TransparentColors/deegreewmps:Color";
833            List clnl = XMLTools.getNodes( node, xPath, nsContext );
834            Color[] colors = new Color[clnl.size()];
835            for ( int i = 0; i < colors.length; i++ ) {
836                colors[i] = Color.decode( XMLTools.getStringValue( (Node) clnl.get( i ) ) );
837            }
838    
839            return colors;
840        }
841    
842        /**
843         * Parse Scale hint
844         * 
845         * @param node
846         * @return ScaleHint
847         * @throws XMLParsingException
848         */
849        private ScaleHint parseScaleHint( Node node )
850                                throws XMLParsingException {
851    
852            String xPath = "./deegreewmps:ScaleHint/@min";
853            double minScale = XMLTools.getNodeAsDouble( node, xPath, nsContext, 0 );
854            xPath = "./deegreewmps:ScaleHint/@max";
855            double maxScale = XMLTools.getNodeAsDouble( node, xPath, nsContext, Double.MAX_VALUE );
856    
857            return new ScaleHint( minScale, maxScale );
858        }
859    
860        /**
861         * Parse WFS Filter condition
862         * 
863         * @param node
864         * @return Query
865         * @throws XMLParsingException
866         */
867        private Query parseWFSFilterCondition( Node node )
868                                throws XMLParsingException {
869    
870            Query query = null;
871            String xPath = "./deegreewmps:FilterCondition/wfs:Query";
872            Node queryNode = XMLTools.getNode( node, xPath, nsContext );
873            if ( queryNode != null ) {
874                try {
875                    query = Query.create( (Element) queryNode );
876                } catch ( Exception e ) {
877                    throw new XMLParsingException( StringTools.stackTraceToString( e ) );
878                }
879            }
880    
881            return query;
882        }
883    
884        /**
885         * Parse WCS Filter Condition
886         * 
887         * @param node
888         * @return GetCoverage
889         * @throws XMLParsingException
890         */
891        private GetCoverage parseWCSFilterCondition( Node node )
892                                throws XMLParsingException {
893    
894            GetCoverage getCoverage = null;
895    
896            String id = "" + IDGenerator.getInstance().generateUniqueID();
897    
898            StringBuffer sd = new StringBuffer( 1000 );
899            sd.append( "version=1.0.0&Coverage=%default%&" );
900            sd.append( "CRS=EPSG:4326&BBOX=0,0,1,1&Width=1" );
901            sd.append( "&Height=1&Format=%default%&" );
902            String xPath = "./deegreewmps:FilterCondition/deegreewmps:WCSRequest";
903            String s = XMLTools.getNodeAsString( node, xPath, nsContext, "" );
904            sd.append( s );
905            try {
906                getCoverage = GetCoverage.create( id, sd.toString() );
907            } catch ( Exception e ) {
908                throw new XMLParsingException( "could not create GetCoverage from WMS " + "FilterCondition", e );
909            }
910    
911            return getCoverage;
912        }
913    
914        /**
915         * Returns a GetMap instance , parsing the WMS Filter condition
916         * 
917         * @param node
918         * @return GetMap
919         * @throws XMLParsingException
920         */
921        private GetMap parseWMSFilterCondition( Node node )
922                                throws XMLParsingException {
923    
924            GetMap getMap = null;
925    
926            String id = "" + IDGenerator.getInstance().generateUniqueID();
927    
928            StringBuffer sd = new StringBuffer( 1000 );
929            sd.append( "REQUEST=GetMap&LAYERS=%default%&" );
930            sd.append( "STYLES=&SRS=EPSG:4326&BBOX=0,0,1,1&WIDTH=1&" );
931            sd.append( "HEIGHT=1&FORMAT=%default%" );
932            Map<String, String> map1 = KVP2Map.toMap( sd.toString() );
933            String xPath = "./deegreewmps:FilterCondition/deegreewmps:WMSRequest";
934            String s = XMLTools.getRequiredNodeAsString( node, xPath, nsContext );
935            Map<String, String> map2 = KVP2Map.toMap( s );
936            if ( map2.get( "VERSION" ) == null && map2.get( "WMTVER" ) == null ) {
937                map2.put( "VERSION", "1.1.1" );
938            }
939            // if no service is set use WMS as default
940            if ( map2.get( "SERVICE" ) == null ) {
941                map2.put( "SERVICE", "WMS" );
942            }
943            map1.putAll( map2 );
944            try {
945                map1.put( "ID", id );
946                getMap = GetMap.create( map1 );
947            } catch ( Exception e ) {
948                throw new XMLParsingException( "could not create GetCoverage from WMS " + "FilterCondition", e );
949            }
950    
951            return getMap;
952        }
953    
954        /**
955         * Returns a list of Style elements, parsing the style element
956         * 
957         * @param layerElem
958         * @return Style[]
959         * @throws XMLParsingException
960         */
961        @Override
962        protected Style[] parseStyles( Element layerElem )
963                                throws XMLParsingException {
964    
965            List nl = XMLTools.getNodes( layerElem, "./Style", nsContext );
966            Style[] styles = new Style[nl.size()];
967            for ( int i = 0; i < styles.length; i++ ) {
968                String name = XMLTools.getRequiredNodeAsString( (Node) nl.get( i ), "./Name", nsContext );
969                String title = XMLTools.getNodeAsString( (Node) nl.get( i ), "./Title", nsContext, null );
970                String styleAbstract = XMLTools.getNodeAsString( (Node) nl.get( i ), "./Abstract", nsContext, null );
971                LegendURL[] legendURLs = parseLegendURL( (Node) nl.get( i ) );
972                StyleURL styleURL = parseStyleURL( (Node) nl.get( i ) );
973                StyleSheetURL styleSheetURL = parseStyleSheetURL( (Node) nl.get( i ) );
974                String xPath = "deegreewmps:StyleResource";
975                String styleResource = XMLTools.getNodeAsString( (Node) nl.get( i ), xPath, nsContext, "styles.xml" );
976                URL sr = null;
977                try {
978                    sr = resolve( styleResource );
979                } catch ( MalformedURLException e ) {
980                    throw new XMLParsingException( "could not parse style resource of " + "style: " + name, e );
981                }
982                styles[i] = new Style( name, title, styleAbstract, legendURLs, styleSheetURL, styleURL, sr );
983            }
984    
985            return styles;
986        }
987    
988    }