001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 }