001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/configuration/WPVSConfigurationDocument.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2008 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 044 package org.deegree.ogcwebservices.wpvs.configuration; 045 046 import java.awt.Color; 047 import java.net.MalformedURLException; 048 import java.net.URL; 049 import java.util.ArrayList; 050 import java.util.HashMap; 051 import java.util.Iterator; 052 import java.util.List; 053 import java.util.Map; 054 055 import org.deegree.datatypes.QualifiedName; 056 import org.deegree.framework.log.ILogger; 057 import org.deegree.framework.log.LoggerFactory; 058 import org.deegree.framework.util.IDGenerator; 059 import org.deegree.framework.util.KVP2Map; 060 import org.deegree.framework.util.StringTools; 061 import org.deegree.framework.xml.InvalidConfigurationException; 062 import org.deegree.framework.xml.XMLParsingException; 063 import org.deegree.framework.xml.XMLTools; 064 import org.deegree.i18n.Messages; 065 import org.deegree.model.crs.CoordinateSystem; 066 import org.deegree.model.filterencoding.AbstractFilter; 067 import org.deegree.model.filterencoding.Filter; 068 import org.deegree.model.metadata.iso19115.Keywords; 069 import org.deegree.model.metadata.iso19115.OnlineResource; 070 import org.deegree.model.spatialschema.Envelope; 071 import org.deegree.model.spatialschema.GMLGeometryAdapter; 072 import org.deegree.model.spatialschema.Geometry; 073 import org.deegree.model.spatialschema.GeometryException; 074 import org.deegree.model.spatialschema.GeometryFactory; 075 import org.deegree.model.spatialschema.Surface; 076 import org.deegree.ogcbase.CommonNamespaces; 077 import org.deegree.ogcbase.PropertyPath; 078 import org.deegree.ogcwebservices.InvalidParameterValueException; 079 import org.deegree.ogcwebservices.MissingParameterValueException; 080 import org.deegree.ogcwebservices.OGCWebServiceException; 081 import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException; 082 import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage; 083 import org.deegree.ogcwebservices.wms.operation.GetMap; 084 import org.deegree.ogcwebservices.wpvs.capabilities.DataProvider; 085 import org.deegree.ogcwebservices.wpvs.capabilities.Dataset; 086 import org.deegree.ogcwebservices.wpvs.capabilities.DatasetReference; 087 import org.deegree.ogcwebservices.wpvs.capabilities.Dimension; 088 import org.deegree.ogcwebservices.wpvs.capabilities.ElevationModel; 089 import org.deegree.ogcwebservices.wpvs.capabilities.FeatureListReference; 090 import org.deegree.ogcwebservices.wpvs.capabilities.Identifier; 091 import org.deegree.ogcwebservices.wpvs.capabilities.MetaData; 092 import org.deegree.ogcwebservices.wpvs.capabilities.OWSCapabilities; 093 import org.deegree.ogcwebservices.wpvs.capabilities.Style; 094 import org.deegree.ogcwebservices.wpvs.capabilities.WPVSCapabilitiesDocument; 095 import org.w3c.dom.Element; 096 import org.w3c.dom.Node; 097 import org.w3c.dom.Text; 098 099 /** 100 * Parser for WPVS configuration documents. 101 * 102 * @author <a href="mailto:mays@lat-lon.de">Judit Mays</a> 103 * @author last edited by: $Author: apoth $ 104 * 105 * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $ 106 */ 107 public class WPVSConfigurationDocument extends WPVSCapabilitiesDocument { 108 109 private static final long serialVersionUID = 1511898601495679163L; 110 111 private static final ILogger LOG = LoggerFactory.getLogger( WPVSConfigurationDocument.class ); 112 113 private static String PRE_DWPVS = CommonNamespaces.DEEGREEWPVS_PREFIX + ":"; 114 115 private static String PRE_OWS = CommonNamespaces.OWS_PREFIX + ":"; 116 117 // The smallestMinimalScaleDenomiator is needed to calculate the smallest resolutionstripe 118 // possible 119 private double smallestMinimalScaleDenominator = Double.MAX_VALUE; 120 121 /** 122 * Creates a class representation of the <code>WPVSConfiguration</code> document. 123 * 124 * @return Returns a WPVSConfiguration object. 125 * @throws InvalidConfigurationException 126 */ 127 public WPVSConfiguration parseConfiguration() 128 throws InvalidConfigurationException { 129 WPVSConfiguration wpvsConfiguration = null; 130 try { 131 132 // TODO 'contents' field not verified, therefore null! Check spec. 133 Element requestedNode = (Element) XMLTools.getRequiredNode( getRootElement(), 134 PRE_DWPVS + "deegreeParams", 135 nsContext ); 136 WPVSDeegreeParams wpvsDeegreeParams = parseDeegreeParams( requestedNode ); 137 138 requestedNode = (Element) XMLTools.getRequiredNode( getRootElement(), PRE_DWPVS + "Dataset", nsContext ); 139 Dataset rootDataset = parseDataset( requestedNode, 140 null, 141 null, 142 0, 143 9E9, 144 wpvsDeegreeParams.getMinimalWCS_DGMResolution() ); 145 146 wpvsConfiguration = new WPVSConfiguration( parseVersion(), 147 parseUpdateSequence(), 148 getServiceIdentification(), 149 getServiceProvider(), 150 parseOperationsMetadata( wpvsDeegreeParams.getDefaultOnlineResource() ), 151 null, 152 rootDataset, 153 wpvsDeegreeParams, 154 ( Double.isInfinite( smallestMinimalScaleDenominator ) ? 1.0 155 : smallestMinimalScaleDenominator ) ); 156 157 } catch ( XMLParsingException e ) { 158 throw new InvalidConfigurationException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) ); 159 160 } catch ( MissingParameterValueException e ) { 161 throw new InvalidConfigurationException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) ); 162 163 } catch ( InvalidParameterValueException e ) { 164 throw new InvalidConfigurationException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) ); 165 166 } catch ( OGCWebServiceException e ) { 167 throw new InvalidConfigurationException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) ); 168 169 } catch ( InvalidConfigurationException e ) { 170 throw new InvalidConfigurationException( e.getMessage() + "\n" + StringTools.stackTraceToString( e ) ); 171 172 } 173 return wpvsConfiguration; 174 } 175 176 /** 177 * Creates and returns a new <code>WPVSDeegreeParams</code> object from the given <code>Node</code>. 178 * 179 * @param deegreeNode 180 * @return Returns a new WPVSDeegreeParams object. 181 * @throws XMLParsingException 182 * @throws InvalidConfigurationException 183 */ 184 private WPVSDeegreeParams parseDeegreeParams( Node deegreeNode ) 185 throws XMLParsingException, 186 InvalidConfigurationException { 187 188 Element deegreeElement = (Element) XMLTools.getRequiredNode( deegreeNode, 189 PRE_DWPVS + "DefaultOnlineResource", 190 nsContext ); 191 OnlineResource defaultOnlineResource = parseOnLineResource( deegreeElement ); 192 193 int cacheSize = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "CacheSize", nsContext, 100 ); 194 195 int maxLifeTime = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "MaxLifeTime", nsContext, 3600 ); 196 197 int reqTimeLimit = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "RequestTimeLimit", nsContext, 60 ); 198 reqTimeLimit *= 1000; 199 200 int maxTextureDimension = XMLTools.getNodeAsInt( deegreeNode, 201 PRE_DWPVS + "MaxTextureDimension", 202 nsContext, 203 Integer.MAX_VALUE ); 204 205 int quadMergeCount = XMLTools.getNodeAsInt( deegreeNode, 206 PRE_DWPVS + "QuadMergeCount", 207 nsContext, 10 ); 208 209 float viewQuality = (float) XMLTools.getNodeAsDouble( deegreeNode, PRE_DWPVS + "ViewQuality", nsContext, 0.95f ); 210 211 int maxMapWidth = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "MaxViewWidth", nsContext, 1000 ); 212 213 int maxMapHeight = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "MaxViewHeight", nsContext, 1000 ); 214 215 String charSet = XMLTools.getNodeAsString( deegreeNode, PRE_DWPVS + "CharacterSet", nsContext, "UTF-8" ); 216 217 Node copyrightNode = XMLTools.getNode( deegreeNode, PRE_DWPVS + "Copyright", nsContext ); 218 String copyright = null; 219 boolean isWatermarked = false; 220 if ( copyrightNode != null ) { 221 222 Node copyTextNode = XMLTools.getNode( copyrightNode, PRE_DWPVS + "Text", nsContext ); 223 Node copyURLNode = XMLTools.getNode( copyrightNode, PRE_DWPVS + "ImageURL/@xlink:href", nsContext ); 224 225 if ( copyTextNode != null ) { 226 copyright = XMLTools.getRequiredNodeAsString( copyrightNode, PRE_DWPVS + "Text/text()", nsContext ); 227 } else if ( copyURLNode != null ) { 228 copyright = XMLTools.getRequiredNodeAsString( copyrightNode, 229 PRE_DWPVS + "ImageURL/@xlink:href", 230 nsContext ); 231 232 isWatermarked = XMLTools.getNodeAsBoolean( copyrightNode, 233 PRE_DWPVS + "ImageURL/@watermark", 234 nsContext, 235 isWatermarked ); 236 237 try { 238 copyright = resolve( copyright ).toString(); 239 } catch ( MalformedURLException e ) { 240 throw new InvalidConfigurationException( "Copyright/ImageURL '" + copyright 241 + "' doesn't seem to be a valid URL!" ); 242 } 243 244 } else { 245 throw new InvalidConfigurationException( "Copyright must contain either " + "a Text-Element or an ImageURL-Element!" ); 246 } 247 } 248 249 Map<String, URL> backgroundMap = new HashMap<String, URL>( 10 ); 250 Element backgrounds = (Element) XMLTools.getNode( deegreeNode, PRE_DWPVS + "BackgroundList", nsContext ); 251 if ( backgrounds != null ) { 252 List backgroundList = XMLTools.getNodes( backgrounds, PRE_DWPVS + "Background", nsContext ); 253 for ( Iterator iter = backgroundList.iterator(); iter.hasNext(); ) { 254 Element background = (Element) iter.next(); 255 256 String bgName = background.getAttribute( "name" ); 257 String bgHref = background.getAttribute( "href" ); 258 259 if ( bgName == null || bgName.length() == 0 || bgHref == null || bgHref.length() == 0 ) 260 throw new InvalidConfigurationException( "Background must contain a 'name' and a " + " 'href' attribute, both if which must contain non-empty strings." ); 261 262 try { 263 264 backgroundMap.put( bgName, resolve( bgHref ) ); 265 } catch ( MalformedURLException e ) { 266 throw new InvalidConfigurationException( "Background", e.getMessage() ); 267 } 268 } 269 270 } 271 272 boolean quality = XMLTools.getNodeAsBoolean( deegreeNode, 273 PRE_DWPVS + "RequestQualityPreferred", 274 nsContext, 275 true ); 276 double maximumFarClippingPlane = XMLTools.getNodeAsDouble( deegreeNode, 277 PRE_DWPVS + "RequestsMaximumFarClippingPlane", 278 nsContext, 279 15000 ); 280 281 double nearClippingPlane = XMLTools.getNodeAsDouble( deegreeNode, PRE_DWPVS + "NearClippingPlane", nsContext, 2 ); 282 283 String defaultSplitter = XMLTools.getNodeAsString( deegreeNode, 284 PRE_DWPVS + "DefaultSplitter", 285 nsContext, 286 "QUAD" ).toUpperCase(); 287 288 double minimalTerrainHeight = XMLTools.getNodeAsDouble( deegreeNode, 289 PRE_DWPVS + "MinimalTerrainHeight", 290 nsContext, 291 0 ); 292 293 double minimalWCS_DGMResolution = XMLTools.getNodeAsDouble( deegreeNode, 294 PRE_DWPVS + "MinimalWCSElevationModelResolution", 295 nsContext, 296 0 ); 297 298 double extendRequestPercentage = XMLTools.getNodeAsDouble( deegreeNode, 299 PRE_DWPVS + "ExtendRequestPercentage", 300 nsContext, 301 0 ); 302 if ( extendRequestPercentage > 100 ) { 303 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_EXTEND_REQUEST_PERCENTAGE", 304 Double.valueOf( extendRequestPercentage ), 305 Double.valueOf( 100 ) ) ); 306 extendRequestPercentage = 100d; 307 } else if ( extendRequestPercentage < -0.00000001 ) { 308 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_EXTEND_REQUEST_PERCENTAGE", 309 Double.valueOf( extendRequestPercentage ), 310 Double.valueOf( 0 ) ) ); 311 extendRequestPercentage = 0d; 312 } 313 WPVSDeegreeParams wpvsDeegreeParams = new WPVSDeegreeParams( defaultOnlineResource, 314 cacheSize, 315 reqTimeLimit, 316 charSet, 317 copyright, 318 isWatermarked, 319 maxLifeTime, 320 viewQuality, 321 backgroundMap, 322 maxMapWidth, 323 maxMapHeight, 324 quality, 325 maximumFarClippingPlane, 326 nearClippingPlane, 327 defaultSplitter, 328 minimalTerrainHeight, 329 minimalWCS_DGMResolution, 330 extendRequestPercentage * 0.01, 331 maxTextureDimension, quadMergeCount ); 332 333 return wpvsDeegreeParams; 334 } 335 336 /** 337 * Creates and returns a new <code>Dataset</code> object from the given <code>Element</code> and the parent 338 * <code>Dataset</code> object. 339 * 340 * @param datasetElement 341 * @param parent 342 * may be null if root Dataset 343 * @return Returns a new Dataset object. 344 * @throws XMLParsingException 345 * @throws MissingParameterValueException 346 * @throws InvalidParameterValueException 347 * @throws OGCWebServiceException 348 * @throws InvalidConfigurationException 349 */ 350 private Dataset parseDataset( Element datasetElement, Dataset parent, CoordinateSystem defaultCoordinateSystem, 351 double defaultMinScaleDonominator, double defaultMaxScaleDenominator, 352 double minimalWCS_DGMResolution ) 353 throws XMLParsingException, 354 MissingParameterValueException, 355 InvalidParameterValueException, 356 OGCWebServiceException, 357 InvalidConfigurationException { 358 // attributes 359 boolean queryable = XMLTools.getNodeAsBoolean( datasetElement, "@queryable", nsContext, false ); 360 boolean opaque = XMLTools.getNodeAsBoolean( datasetElement, "@opaque", nsContext, false ); 361 boolean noSubsets = XMLTools.getNodeAsBoolean( datasetElement, "@noSubsets", nsContext, false ); 362 int fixedWidth = XMLTools.getNodeAsInt( datasetElement, "@fixedWidth", nsContext, 0 ); 363 int fixedHeight = XMLTools.getNodeAsInt( datasetElement, "@fixedHeight", nsContext, 0 ); 364 365 // elements 366 String name = XMLTools.getNodeAsString( datasetElement, PRE_DWPVS + "Name/text()", nsContext, null ); 367 String title = XMLTools.getRequiredNodeAsString( datasetElement, PRE_DWPVS + "Title/text()", nsContext ); 368 String abstract_ = XMLTools.getNodeAsString( datasetElement, PRE_DWPVS + "Abstract/text()", nsContext, null ); 369 Keywords[] keywords = getKeywords( XMLTools.getNodes( datasetElement, PRE_OWS + "Keywords", nsContext ) ); 370 String[] crsStrings = XMLTools.getNodesAsStrings( datasetElement, PRE_DWPVS + "CRS/text()", nsContext ); 371 List<CoordinateSystem> crsList = parseCoordinateSystems( crsStrings ); 372 373 if ( parent == null ) { // root dataset 374 if ( crsList.size() == 0 || crsList.get( 0 ) == null ) { 375 throw new InvalidCapabilitiesException( Messages.getMessage( "WPVS_NO_TOPLEVEL_DATASET_CRS", title ) ); 376 } 377 defaultCoordinateSystem = crsList.get( 0 ); 378 } 379 380 String[] format = XMLTools.getRequiredNodesAsStrings( datasetElement, PRE_DWPVS + "Format/text()", nsContext ); 381 // wgs84 == mandatory 382 Element boundingBoxElement = (Element) XMLTools.getRequiredNode( datasetElement, 383 PRE_OWS + "WGS84BoundingBox", 384 nsContext ); 385 Envelope wgs84BoundingBox = getWGS84BoundingBoxType( boundingBoxElement ); 386 387 Envelope[] boundingBoxes = getBoundingBoxes( datasetElement, defaultCoordinateSystem ); 388 Dimension[] dimensions = parseDimensions( datasetElement ); 389 DataProvider dataProvider = parseDataProvider( datasetElement ); 390 Identifier identifier = parseDatasetIdentifier( datasetElement, PRE_DWPVS + "Identifier" ); 391 MetaData[] metaData = parseMetaData( datasetElement ); 392 DatasetReference[] datasetRefs = parseDatasetReferences( datasetElement ); 393 FeatureListReference[] featureListRefs = parseFeatureListReferences( datasetElement ); 394 Style[] style = parseStyles( datasetElement ); 395 double minScaleDenom = XMLTools.getNodeAsDouble( datasetElement, 396 PRE_DWPVS + "MinimumScaleDenominator/text()", 397 nsContext, 398 defaultMinScaleDonominator ); 399 400 // update the smallestMinimalScaleDenomiator 401 if ( minScaleDenom < smallestMinimalScaleDenominator ) { 402 smallestMinimalScaleDenominator = minScaleDenom; 403 } 404 405 double maxScaleDenom = XMLTools.getNodeAsDouble( datasetElement, 406 PRE_DWPVS + "MaximumScaleDenominator/text()", 407 nsContext, 408 defaultMaxScaleDenominator ); 409 410 if ( parent == null ) {// toplevel dataset sets the default minScaleDenominator 411 defaultMinScaleDonominator = minScaleDenom; 412 defaultMaxScaleDenominator = maxScaleDenom; 413 } 414 415 if ( minScaleDenom >= maxScaleDenom ) { 416 throw new InvalidCapabilitiesException( "MinimumScaleDenominator must be " + "less than MaximumScaleDenominator!" ); 417 } 418 CoordinateSystem currentCRS = defaultCoordinateSystem; 419 if ( crsList.size() > 0 && crsList.get( 0 ) != null ) { 420 currentCRS = crsList.get( 0 ); 421 } 422 ElevationModel elevationModel = parseElevationModel( datasetElement, 423 name, 424 minimalWCS_DGMResolution, 425 currentCRS, 426 defaultMinScaleDonominator, 427 defaultMaxScaleDenominator ); 428 AbstractDataSource[] dataSources = parseAbstractDatasources( datasetElement, 429 name, 430 defaultMinScaleDonominator, 431 defaultMaxScaleDenominator, 432 currentCRS ); 433 434 // create new root dataset 435 Dataset dataset = new Dataset( queryable, 436 opaque, 437 noSubsets, 438 fixedWidth, 439 fixedHeight, 440 name, 441 title, 442 abstract_, 443 keywords, 444 crsList, 445 format, 446 wgs84BoundingBox, 447 boundingBoxes, 448 dimensions, 449 dataProvider, 450 identifier, 451 metaData, 452 datasetRefs, 453 featureListRefs, 454 style, 455 minScaleDenom, 456 maxScaleDenom, 457 null, 458 elevationModel, 459 dataSources, 460 parent ); 461 462 // get child datasets 463 List nl = XMLTools.getNodes( datasetElement, PRE_DWPVS + "Dataset", nsContext ); 464 Dataset[] childDatasets = new Dataset[nl.size()]; 465 for ( int i = 0; i < childDatasets.length; i++ ) { 466 childDatasets[i] = parseDataset( (Element) nl.get( i ), 467 dataset, 468 defaultCoordinateSystem, 469 defaultMinScaleDonominator, 470 defaultMaxScaleDenominator, 471 minimalWCS_DGMResolution ); 472 473 } 474 475 // set child datasets 476 dataset.setDatasets( childDatasets ); 477 478 return dataset; 479 } 480 481 /** 482 * Creates and returns a new <code>ElevationModel</code> object from the given <code>Element</code> and the 483 * parent <code>Dataset</code>. 484 * 485 * The OGC ElevationModel contains only a String. The Deegree ElevationModel additionaly contains a complex 486 * dataSource. 487 * 488 * @param datasetElement 489 * @param parent 490 * @return Returns the ElevationModel object. 491 * @throws XMLParsingException 492 * @throws OGCWebServiceException 493 * @throws InvalidParameterValueException 494 * @throws MissingParameterValueException 495 * @throws InvalidConfigurationException 496 */ 497 private ElevationModel parseElevationModel( Element datasetElement, String parentName, 498 double minimalWCS_DGMResolution, CoordinateSystem defaultCRS, 499 double defaultMinScaleDenominator, double defaultMaxScaleDenominator ) 500 throws XMLParsingException, 501 MissingParameterValueException, 502 InvalidParameterValueException, 503 OGCWebServiceException, 504 InvalidConfigurationException { 505 506 Element elevationElement = null; 507 String name = null; 508 ElevationModel elevationModel = null; 509 510 elevationElement = (Element) XMLTools.getNode( datasetElement, PRE_DWPVS + "ElevationModel", nsContext ); 511 512 AbstractDataSource[] dataSources = null; 513 if ( elevationElement != null ) { 514 515 name = XMLTools.getRequiredNodeAsString( elevationElement, PRE_DWPVS + "Name/text()", nsContext ); 516 517 dataSources = parseAbstractDatasources( elevationElement, 518 parentName, 519 defaultMinScaleDenominator, 520 defaultMaxScaleDenominator, 521 defaultCRS ); 522 if ( dataSources.length < 1 ) { 523 throw new InvalidCapabilitiesException( "Each '" + elevationElement.getNodeName() 524 + "' must contain at least one data source!" ); 525 } 526 if ( !Double.isNaN( minimalWCS_DGMResolution ) ) { 527 // little trick to know which dgm datasources have a configured minimal resolution, 528 // if the minimalWCS_DGMResolution is not set (e.g Double.nan) nothing has to be 529 // done (a value of 0d is presumed) 530 for ( AbstractDataSource source : dataSources ) { 531 if ( source.getServiceType() == AbstractDataSource.LOCAL_WCS || source.getServiceType() == AbstractDataSource.REMOTE_WCS ) { 532 ( (LocalWCSDataSource) source ).setConfiguredMinimalDGMResolution( minimalWCS_DGMResolution ); 533 } 534 } 535 } 536 } 537 538 elevationModel = new ElevationModel( name, dataSources ); 539 540 return elevationModel; 541 } 542 543 /** 544 * Creates and returns a new array of <code>AbstractDataSource</code> objects from the given <code>Element</code>. 545 * 546 * If the objects are used within an ElevationModel object, they may be of the following types: LocalWCSDataSource, 547 * RemoteWCSDataSource, LocalWFSDataSource, RemoteWFSDataSource. If the objects are used within a Dataset object, 548 * they may additionaly be of the types: LocalWMSDataSource, RemoteWMSDataSource. 549 * 550 * @param element 551 * @return Returns a new array of AbstractDataSource objects. 552 * @throws XMLParsingException 553 * @throws OGCWebServiceException 554 * @throws InvalidConfigurationException 555 */ 556 private AbstractDataSource[] parseAbstractDatasources( Element element, String parentName, 557 double defaultMinScaleDenominator, 558 double defaultMaxScaleDenominator, 559 CoordinateSystem defaultCRS ) 560 throws XMLParsingException, 561 OGCWebServiceException, 562 InvalidConfigurationException { 563 564 List abstractDataSources = XMLTools.getNodes( element, "*", nsContext ); 565 List<AbstractDataSource> tempDataSources = new ArrayList<AbstractDataSource>( abstractDataSources.size() ); 566 567 for ( int i = 0; i < abstractDataSources.size(); i++ ) { 568 569 Element dataSourceElement = (Element) abstractDataSources.get( i ); 570 571 // String nodeName = dataSourceElement.getNodeName(); 572 String nodeName = dataSourceElement.getLocalName(); 573 574 if ( nodeName != null && nodeName.endsWith( "DataSource" ) ) { 575 QualifiedName pn = null; 576 if ( parentName != null ) { 577 pn = new QualifiedName( PRE_DWPVS, parentName, nsContext.getURI( PRE_DWPVS ) ); 578 } 579 QualifiedName name = XMLTools.getNodeAsQualifiedName( dataSourceElement, 580 PRE_DWPVS + "Name/text()", 581 nsContext, 582 pn ); 583 584 OWSCapabilities owsCapabilities = parseOWSCapabilities( dataSourceElement ); 585 586 double minScaleDenom = XMLTools.getNodeAsDouble( dataSourceElement, 587 PRE_DWPVS + "MinimumScaleDenominator/text()", 588 nsContext, 589 defaultMinScaleDenominator ); 590 591 // update the smallestMinimalScaleDenomiator 592 if ( minScaleDenom < smallestMinimalScaleDenominator ) 593 smallestMinimalScaleDenominator = minScaleDenom; 594 595 double maxScaleDenom = XMLTools.getNodeAsDouble( dataSourceElement, 596 PRE_DWPVS + "MaximumScaleDenominator/text()", 597 nsContext, 598 defaultMaxScaleDenominator ); 599 600 Surface validArea = parseValidArea( dataSourceElement, defaultCRS ); 601 AbstractDataSource dataSource = null; 602 603 if ( nodeName.equals( "LocalWCSDataSource" ) || "RemoteWCSDataSource".equals( nodeName ) ) { 604 Element filterElement = (Element) XMLTools.getRequiredNode( dataSourceElement, 605 PRE_DWPVS + "FilterCondition", 606 nsContext ); 607 GetCoverage getCoverage = parseWCSFilterCondition( filterElement ); 608 Color[] transparentColors = parseTransparentColors( dataSourceElement ); 609 610 if ( "RemoteWCSDataSource".equals( nodeName ) ) { 611 dataSource = new RemoteWCSDataSource( name, 612 owsCapabilities, 613 validArea, 614 minScaleDenom, 615 maxScaleDenom, 616 getCoverage, 617 transparentColors ); 618 LOG.logDebug( "created remote wcs with name: " + name ); 619 } else { 620 dataSource = new LocalWCSDataSource( name, 621 owsCapabilities, 622 validArea, 623 minScaleDenom, 624 maxScaleDenom, 625 getCoverage, 626 transparentColors ); 627 LOG.logDebug( "created local wcs with name: " + name ); 628 } 629 } else if ( "RemoteWFSDataSource".equals( nodeName ) || "LocalWFSDataSource".equals( nodeName ) ) { 630 Text geoPropNode = (Text) XMLTools.getRequiredNode( dataSourceElement, 631 PRE_DWPVS + "GeometryProperty/text()", 632 nsContext ); 633 PropertyPath geometryProperty = parsePropertyPath( geoPropNode ); 634 635 Element filterElement = (Element) XMLTools.getNode( dataSourceElement, 636 PRE_DWPVS + "FilterCondition/ogc:Filter", 637 nsContext ); 638 639 int maxFeatures = XMLTools.getNodeAsInt( dataSourceElement, PRE_DWPVS + "MaxFeatures", nsContext, -1 ); 640 641 Filter filterCondition = null; 642 if ( filterElement != null ) { 643 filterCondition = AbstractFilter.buildFromDOM( filterElement, false ); 644 } 645 646 // FeatureCollectionAdapter adapter = createFCAdapterFromAdapterClassName( 647 // dataSourceElement ); 648 649 if( "LocalWFSDataSource".equals( nodeName ) ){ 650 dataSource = new LocalWFSDataSource( name, 651 owsCapabilities, 652 validArea, 653 minScaleDenom, 654 maxScaleDenom, 655 geometryProperty, 656 filterCondition, 657 maxFeatures ); 658 LOG.logDebug( "created local wfs with name: " + name ); 659 } else { 660 dataSource = new RemoteWFSDataSource( name, 661 owsCapabilities, 662 validArea, 663 minScaleDenom, 664 maxScaleDenom, 665 geometryProperty, 666 filterCondition, maxFeatures ); 667 LOG.logDebug( "created remote wfs with name: " + name ); 668 } 669 } else if ( nodeName.equals( "LocalWMSDataSource" ) ) { 670 if ( element.getNodeName().endsWith( "ElevationModel" ) ) { 671 throw new InvalidConfigurationException( "An ElevationModel cannot " + "contain a LocalWMSDataSource!" ); 672 } 673 Element filterElement = (Element) XMLTools.getRequiredNode( dataSourceElement, 674 PRE_DWPVS + "FilterCondition", 675 nsContext ); 676 GetMap getMap = parseWMSFilterCondition( filterElement ); 677 678 Color[] transparentColors = parseTransparentColors( dataSourceElement ); 679 680 dataSource = new LocalWMSDataSource( name, 681 owsCapabilities, 682 validArea, 683 minScaleDenom, 684 maxScaleDenom, 685 getMap, 686 transparentColors ); 687 LOG.logDebug( "created local wms with name: " + name ); 688 689 } else if ( nodeName.equals( "RemoteWMSDataSource" ) ) { 690 if ( element.getNodeName().endsWith( "ElevationModel" ) ) { 691 throw new InvalidConfigurationException( "An ElevationModel cannot " + "contain a LocalWMSDataSource!" ); 692 } 693 Element filterElement = (Element) XMLTools.getRequiredNode( dataSourceElement, 694 PRE_DWPVS + "FilterCondition", 695 nsContext ); 696 GetMap getMap = parseWMSFilterCondition( filterElement ); 697 698 Color[] transparentColors = parseTransparentColors( dataSourceElement ); 699 700 dataSource = new RemoteWMSDataSource( name, 701 owsCapabilities, 702 validArea, 703 minScaleDenom, 704 maxScaleDenom, 705 getMap, 706 transparentColors ); 707 LOG.logDebug( "created remote wms with name: " + name ); 708 } else { 709 throw new InvalidCapabilitiesException( "Unknown data source: '" + nodeName + "'" ); 710 } 711 712 tempDataSources.add( dataSource ); 713 } 714 } 715 716 AbstractDataSource[] dataSources = tempDataSources.toArray( new AbstractDataSource[tempDataSources.size()] ); 717 718 return dataSources; 719 } 720 721 /** 722 * FIXME check content of StringBuffer and Map! This is an adapted copy from: 723 * org.deegree.ogcwebservices.wms.configuration#parseWMSFilterCondition(Node) 724 * 725 * Creates and returns a new <code>GetMap</code> object from the given <code>Element</code>. 726 * 727 * @param filterElement 728 * @return a partial wms GetMap request instance 729 * @throws XMLParsingException 730 */ 731 private GetMap parseWMSFilterCondition( Element filterElement ) 732 throws XMLParsingException { 733 734 GetMap getMap = null; 735 736 String wmsRequest = XMLTools.getRequiredNodeAsString( filterElement, PRE_DWPVS + "WMSRequest/text()", nsContext ); 737 738 StringBuffer sd = new StringBuffer( 1000 ); 739 sd.append( "REQUEST=GetMap&LAYERS=%default%&STYLES=&SRS=EPSG:4326&" ); 740 sd.append( "BBOX=0,0,1,1&WIDTH=1&HEIGHT=1&FORMAT=%default%" ); 741 742 Map<String, String> map1 = KVP2Map.toMap( sd.toString() ); 743 744 Map<String, String> map2 = KVP2Map.toMap( wmsRequest ); 745 if ( map2.get( "VERSION" ) == null && map2.get( "WMTVER" ) == null ) { 746 map2.put( "VERSION", "1.1.1" ); 747 } 748 // if no service is set use WMS as default 749 if ( map2.get( "SERVICE" ) == null ) { 750 map2.put( "SERVICE", "WMS" ); 751 } 752 753 map1.putAll( map2 ); 754 755 String id = Long.toString( IDGenerator.getInstance().generateUniqueID() ); 756 map1.put( "ID", id ); 757 try { 758 getMap = GetMap.create( map1 ); 759 } catch ( Exception e ) { 760 throw new XMLParsingException( "could not create GetMap from WMS FilterCondition", e ); 761 } 762 763 return getMap; 764 } 765 766 /** 767 * FIXME check content of StringBuffer ! This is an adapted copy from: 768 * org.deegree.ogcwebservices.wms.configuration#parseWCSFilterCondition(Node) 769 * 770 * Creates and returns a new <code>GetCoverage</code> object from the given <code>Element</code>. 771 * 772 * @param filterElement 773 * @return a partial GetCoverage request 774 * @throws XMLParsingException 775 */ 776 private GetCoverage parseWCSFilterCondition( Element filterElement ) 777 throws XMLParsingException { 778 779 GetCoverage coverage = null; 780 781 String wcsRequest = XMLTools.getRequiredNodeAsString( filterElement, PRE_DWPVS + "WCSRequest/text()", nsContext ); 782 783 StringBuffer sd = new StringBuffer( 1000 ); 784 sd.append( "version=1.0.0&Coverage=%default%&CRS=EPSG:4326&BBOX=0,0,1,1" ); 785 sd.append( "&Width=1&Height=1&Format=%default%&" ); 786 sd.append( wcsRequest ); 787 788 String id = "" + IDGenerator.getInstance().generateUniqueID(); 789 790 try { 791 coverage = GetCoverage.create( id, sd.toString() ); 792 } catch ( Exception e ) { 793 throw new XMLParsingException( "Could not create GetCoverage " + "from WPVS FilterCondition", e ); 794 } 795 796 return coverage; 797 } 798 799 /** 800 * Creates and returns a new <code>OWSCapabilities</code> object from the given <code>Element</code>. 801 * 802 * @param element 803 * @return Returns a new OWSCapabilities object. 804 * @throws XMLParsingException 805 * @throws InvalidCapabilitiesException 806 */ 807 private OWSCapabilities parseOWSCapabilities( Element element ) 808 throws XMLParsingException, 809 InvalidCapabilitiesException { 810 811 Element owsCapabilitiesElement = (Element) XMLTools.getRequiredNode( element, 812 PRE_DWPVS + "OWSCapabilities", 813 nsContext ); 814 815 String format = null; 816 817 // FIXME 818 // schema has onlineResourceType as not optional, so it should be mandatory. 819 // but in other examples onlineResource is never created with this onlineResourceType. 820 // therefore it gets omitted here, too. 821 822 // String onlineResourceType = XMLTools.getRequiredNodeAsString( 823 // owsCapabilitiesElement, PRE_DWPVS+"OnlineResource/@xlink:type", nsContext ); 824 825 String onlineResourceURI = XMLTools.getRequiredNodeAsString( owsCapabilitiesElement, 826 PRE_DWPVS + "OnlineResource/@xlink:href", 827 nsContext ); 828 829 URL onlineResource; 830 try { 831 onlineResource = resolve( onlineResourceURI ); 832 } catch ( MalformedURLException e ) { 833 throw new InvalidCapabilitiesException( onlineResourceURI + " does not represent a valid URL: " 834 + e.getMessage() ); 835 } 836 LOG.logDebug( "found following onlineResource: " + onlineResource ); 837 return new OWSCapabilities( format, onlineResource ); 838 839 // FIXME 840 // if onlineResourceType is going to be used, the returned new OnlineResource should be 841 // created with different constructor: 842 // return new OWSCapabilities( format, onlineResourceType, onlineResource ); 843 } 844 845 /** 846 * Creates and returns a new <code>Geometry</code> object from the given Element. 847 * 848 * @param dataSource 849 * @return Returns a new Geometry object. 850 * @throws XMLParsingException 851 * @throws InvalidConfigurationException 852 */ 853 private Surface parseValidArea( Element dataSource, CoordinateSystem defaultCRS ) 854 throws XMLParsingException, 855 InvalidConfigurationException { 856 List nl = XMLTools.getNodes( dataSource, PRE_DWPVS + "ValidArea/*", nsContext ); 857 if ( nl.size() == 0 ) { 858 return null; 859 } 860 861 if ( nl.size() > 1 ) { 862 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_NUMBER_OF_VALID_AREAS", 863 GMLNS.toASCIIString(), 864 dataSource.getLocalName() ) ); 865 return null; 866 } 867 Surface validArea = null; 868 if ( ( (Node) nl.get( 0 ) ).getNamespaceURI().equals( GMLNS.toASCIIString() ) ) { 869 try { 870 String srsName = XMLTools.getNodeAsString( (Node) nl.get( 0 ), "@srsName", nsContext, null ); 871 if ( srsName == null ) { 872 srsName = defaultCRS.getFormattedString(); 873 } 874 875 Geometry geom = GMLGeometryAdapter.wrap( (Element) nl.get( 0 ), srsName ); 876 if ( !( geom instanceof Surface ) ) { 877 throw new InvalidConfigurationException( Messages.getMessage( "WPVS_WRONG_GEOMTERY_VALID_AREA", 878 dataSource.getLocalName() ) ); 879 } 880 validArea = (Surface) geom; 881 } catch ( GeometryException e ) { 882 throw new InvalidConfigurationException( Messages.getMessage( "WPVS_WRONG_GEOMTERY_VALID_AREA", 883 dataSource.getLocalName() ) + "\n" 884 + e.getMessage(), 885 886 e ); 887 } 888 889 } else if ( ( (Node) nl.get( 0 ) ).getNamespaceURI().equals( CommonNamespaces.OWSNS ) ) { 890 try { 891 Element bbox = (Element) nl.get( 0 ); 892 if ( !"BoundingBox".equals( bbox.getLocalName() ) ) { 893 throw new InvalidConfigurationException( Messages.getMessage( "WPVS_WRONG_GEOMTERY_VALID_AREA", 894 dataSource.getLocalName() ) ); 895 } 896 Envelope env = parseBoundingBox( (Element) nl.get( 0 ), null ); 897 validArea = GeometryFactory.createSurface( env, env.getCoordinateSystem() ); 898 } catch ( GeometryException e ) { 899 throw new InvalidConfigurationException( Messages.getMessage( "WPVS_WRONG_GEOMTERY_VALID_AREA", 900 dataSource.getLocalName() ) + "\n" 901 + e.getMessage(), e ); 902 } catch ( InvalidParameterValueException e ) { 903 throw new InvalidConfigurationException( Messages.getMessage( "WPVS_WRONG_GEOMTERY_VALID_AREA", 904 dataSource.getLocalName() ) + "\n" 905 + e.getMessage(), e ); 906 } 907 } else { 908 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_GEOMTERY_VALID_AREA", dataSource.getLocalName() ) ); 909 return null; 910 } 911 return validArea; 912 } 913 914 /** 915 * Creates and returns a new array of <code>Color</code> objects from the given Element. 916 * 917 * @param dataSourceElement 918 * @return Returns a new array of Color objects. 919 * @throws XMLParsingException 920 * @throws InvalidCapabilitiesException 921 */ 922 private Color[] parseTransparentColors( Element dataSourceElement ) 923 throws XMLParsingException { 924 925 List colorList = XMLTools.getNodes( dataSourceElement, 926 PRE_DWPVS + "TransparentColors/" + PRE_DWPVS + "Color", 927 nsContext ); 928 929 Color[] transparentColors = null; 930 if ( colorList != null ) { 931 transparentColors = new Color[colorList.size()]; 932 933 for ( int i = 0; i < transparentColors.length; i++ ) { 934 935 Element colorElement = (Element) colorList.get( i ); 936 String color = XMLTools.getRequiredNodeAsString( colorElement, "text()", nsContext ); 937 938 transparentColors[i] = Color.decode( color ); 939 } 940 } 941 942 return transparentColors; 943 } 944 945 }