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