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