001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/configuration/WPVSConfigurationDocument.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2006 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: rbezema $ 104 * 105 * @version $Revision: 7952 $, $Date: 2007-08-09 11:57:34 +0200 (Do, 09 Aug 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( 134 getRootElement(), 135 PRE_DWPVS + "deegreeParams", 136 nsContext ); 137 WPVSDeegreeParams wpvsDeegreeParams = parseDeegreeParams( requestedNode ); 138 139 requestedNode = (Element) XMLTools.getRequiredNode( getRootElement(), PRE_DWPVS 140 + "Dataset", 141 nsContext ); 142 Dataset rootDataset = parseDataset( requestedNode, null, null, 143 wpvsDeegreeParams.getMinimalWCS_DGMResolution() ); 144 145 wpvsConfiguration = new WPVSConfiguration( 146 parseVersion(), 147 parseUpdateSequence(), 148 getServiceIdentification(), 149 getServiceProvider(), 150 parseOperationsMetadata(), 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" 159 + StringTools.stackTraceToString( e ) ); 160 161 } catch ( MissingParameterValueException e ) { 162 throw new InvalidConfigurationException( e.getMessage() + "\n" 163 + StringTools.stackTraceToString( e ) ); 164 165 } catch ( InvalidParameterValueException e ) { 166 throw new InvalidConfigurationException( e.getMessage() + "\n" 167 + StringTools.stackTraceToString( e ) ); 168 169 } catch ( OGCWebServiceException e ) { 170 throw new InvalidConfigurationException( e.getMessage() + "\n" 171 + StringTools.stackTraceToString( e ) ); 172 173 } catch ( InvalidConfigurationException e ) { 174 throw new InvalidConfigurationException( e.getMessage() + "\n" 175 + StringTools.stackTraceToString( e ) ); 176 177 } 178 return wpvsConfiguration; 179 } 180 181 /** 182 * Creates and returns a new <code>WPVSDeegreeParams</code> object from the given 183 * <code>Node</code>. 184 * 185 * @param deegreeNode 186 * @return Returns a new WPVSDeegreeParams object. 187 * @throws XMLParsingException 188 * @throws InvalidConfigurationException 189 */ 190 private WPVSDeegreeParams parseDeegreeParams( Node deegreeNode ) 191 throws XMLParsingException, InvalidConfigurationException { 192 193 Element deegreeElement = (Element) XMLTools.getRequiredNode( 194 deegreeNode, 195 PRE_DWPVS 196 + "DefaultOnlineResource", 197 nsContext ); 198 OnlineResource online = parseOnLineResource( deegreeElement ); 199 200 int cacheSize = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "CacheSize", nsContext, 100 ); 201 202 int maxLifeTime = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "MaxLifeTime", nsContext, 203 3600 ); 204 205 int reqTimeLimit = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "RequestTimeLimit", 206 nsContext, 60 ); 207 reqTimeLimit *= 1000; 208 209 float viewQuality = (float) XMLTools.getNodeAsDouble( deegreeNode, PRE_DWPVS 210 + "ViewQuality", 211 nsContext, 0.95f ); 212 213 int maxMapWidth = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "MaxViewWidth", 214 nsContext, 1000 ); 215 216 int maxMapHeight = XMLTools.getNodeAsInt( deegreeNode, PRE_DWPVS + "MaxViewHeight", 217 nsContext, 1000 ); 218 219 String charSet = XMLTools.getNodeAsString( deegreeNode, PRE_DWPVS + "CharacterSet", 220 nsContext, "UTF-8" ); 221 222 Node copyrightNode = XMLTools.getNode( deegreeNode, PRE_DWPVS + "Copyright", nsContext ); 223 224 Node copyTextNode = XMLTools.getNode( copyrightNode, PRE_DWPVS + "Text", nsContext ); 225 Node copyURLNode = XMLTools.getNode( copyrightNode, PRE_DWPVS + "ImageURL/@xlink:href", 226 nsContext ); 227 228 boolean isWatermarked = false; 229 230 String copyright; 231 if ( copyTextNode != null ) { 232 copyright = XMLTools.getRequiredNodeAsString( copyrightNode, PRE_DWPVS + "Text/text()", 233 nsContext ); 234 } else if ( copyURLNode != null ) { 235 copyright = XMLTools.getRequiredNodeAsString( copyrightNode, PRE_DWPVS 236 + "ImageURL/@xlink:href", 237 nsContext ); 238 239 isWatermarked = XMLTools.getNodeAsBoolean( copyrightNode, PRE_DWPVS 240 + "ImageURL/@watermark", 241 nsContext, isWatermarked ); 242 243 try { 244 copyright = resolve( copyright ).toString(); 245 } catch ( MalformedURLException e ) { 246 throw new InvalidConfigurationException( "Copyright/ImageURL '" + copyright 247 + "' doesn't seem to be a valid URL!" ); 248 } 249 250 } else { 251 throw new InvalidConfigurationException( "Copyright must contain either " 252 + "a Text-Element or an ImageURL-Element!" ); 253 } 254 255 Map<String, URL> backgroundMap = new HashMap<String, URL>( 10 ); 256 Element backgrounds = (Element) XMLTools.getNode( deegreeNode, 257 PRE_DWPVS + "BackgroundList", nsContext ); 258 if ( backgrounds != null ) { 259 List backgroundList = XMLTools.getNodes( backgrounds, PRE_DWPVS + "Background", 260 nsContext ); 261 for ( Iterator iter = backgroundList.iterator(); iter.hasNext(); ) { 262 Element background = (Element) iter.next(); 263 264 String bgName = background.getAttribute( "name" ); 265 String bgHref = background.getAttribute( "href" ); 266 267 if ( bgName == null || bgName.length() == 0 || bgHref == null 268 || bgHref.length() == 0 ) 269 throw new InvalidConfigurationException( 270 "Background must contain a 'name' and a " 271 + " 'href' attribute, both if which must contain non-empty strings." ); 272 273 try { 274 275 backgroundMap.put( bgName, resolve( bgHref ) ); 276 } catch ( MalformedURLException e ) { 277 throw new InvalidConfigurationException( "Background", e.getMessage() ); 278 } 279 } 280 281 } 282 283 boolean quality = XMLTools.getNodeAsBoolean( deegreeNode, PRE_DWPVS 284 + "RequestQualityPreferred", 285 nsContext, true ); 286 double maximumFarClippingPlane = XMLTools.getNodeAsDouble( 287 deegreeNode, 288 PRE_DWPVS 289 + "RequestsMaximumFarClippingPlane", 290 nsContext, 15000 ); 291 292 double nearClippingPlane = XMLTools.getNodeAsDouble( 293 deegreeNode, 294 PRE_DWPVS 295 + "NearClippingPlane", 296 nsContext, 2 ); 297 298 String defaultSplitter = XMLTools.getNodeAsString( deegreeNode, 299 PRE_DWPVS + "DefaultSplitter", 300 nsContext, "QUAD" ).toUpperCase(); 301 302 double minimalTerrainHeight = XMLTools.getNodeAsDouble( deegreeNode, 303 PRE_DWPVS + "MinimalTerrainHeight", 304 nsContext, 0 ); 305 306 double minimalWCS_DGMResolution = XMLTools.getNodeAsDouble( 307 deegreeNode, 308 PRE_DWPVS 309 + "MinimalWCSElevationModelResolution", 310 nsContext, 0 ); 311 312 double extendRequestPercentage = XMLTools.getNodeAsDouble( 313 deegreeNode, 314 PRE_DWPVS 315 + "ExtendRequestPercentage", 316 nsContext, 0 ); 317 if ( extendRequestPercentage > 100 ) { 318 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_EXTEND_REQUEST_PERCENTAGE", 319 Double.valueOf( extendRequestPercentage ), 320 Double.valueOf( 100 ) ) ); 321 extendRequestPercentage = 100d; 322 } else if ( extendRequestPercentage < -0.00000001 ) { 323 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_EXTEND_REQUEST_PERCENTAGE", 324 Double.valueOf( extendRequestPercentage ), 325 Double.valueOf( 0 ) ) ); 326 extendRequestPercentage = 0d; 327 } 328 WPVSDeegreeParams wpvsDeegreeParams = new WPVSDeegreeParams( online, 329 cacheSize, 330 reqTimeLimit, 331 charSet, 332 copyright, 333 isWatermarked, 334 maxLifeTime, 335 viewQuality, 336 backgroundMap, 337 maxMapWidth, 338 maxMapHeight, 339 quality, 340 maximumFarClippingPlane, 341 nearClippingPlane, 342 defaultSplitter, 343 minimalTerrainHeight, 344 minimalWCS_DGMResolution, 345 extendRequestPercentage * 0.01 ); 346 347 return wpvsDeegreeParams; 348 } 349 350 // /** 351 // * Gets the <code>Dataset</code> object from the <code>WPVSConfiguration</code> element. 352 // * 353 // * @return Returns the Dataset object form root element. 354 // * @throws XMLParsingException 355 // * @throws OGCWebServiceException 356 // * @throws InvalidParameterValueException 357 // * @throws MissingParameterValueException 358 // * @throws InvalidConfigurationException 359 // */ 360 // private Dataset getDataset( Deegree) 361 // throws XMLParsingException, MissingParameterValueException, 362 // InvalidParameterValueException, OGCWebServiceException, 363 // InvalidConfigurationException { 364 // 365 // Element datasetElement = (Element) XMLTools.getRequiredNode( getRootElement(), PRE_DWPVS 366 // + "Dataset", 367 // nsContext ); 368 // Dataset dataset = parseDataset( datasetElement, null, null ); 369 // 370 // return dataset; 371 // } 372 373 /** 374 * Creates and returns a new <code>Dataset</code> object from the given <code>Element</code> 375 * and the parent <code>Dataset</code> object. 376 * 377 * @param datasetElement 378 * @param parent 379 * may be null if root Dataset 380 * @return Returns a new Dataset object. 381 * @throws XMLParsingException 382 * @throws MissingParameterValueException 383 * @throws InvalidParameterValueException 384 * @throws OGCWebServiceException 385 * @throws InvalidConfigurationException 386 */ 387 private Dataset parseDataset( Element datasetElement, Dataset parent, 388 CoordinateSystem defaultCoordinateSystem, 389 double minimalWCS_DGMResolution ) 390 throws XMLParsingException, MissingParameterValueException, 391 InvalidParameterValueException, OGCWebServiceException, 392 InvalidConfigurationException { 393 // attributes 394 boolean queryable = XMLTools.getNodeAsBoolean( datasetElement, "@queryable", nsContext, 395 false ); 396 boolean opaque = XMLTools.getNodeAsBoolean( datasetElement, "@opaque", nsContext, false ); 397 boolean noSubsets = XMLTools.getNodeAsBoolean( datasetElement, "@noSubsets", nsContext, 398 false ); 399 int fixedWidth = XMLTools.getNodeAsInt( datasetElement, "@fixedWidth", nsContext, 0 ); 400 int fixedHeight = XMLTools.getNodeAsInt( datasetElement, "@fixedHeight", nsContext, 0 ); 401 402 // elements 403 String name = XMLTools.getNodeAsString( datasetElement, PRE_DWPVS + "Name/text()", 404 nsContext, null ); 405 String title = XMLTools.getRequiredNodeAsString( datasetElement, 406 PRE_DWPVS + "Title/text()", nsContext ); 407 String abstract_ = XMLTools.getNodeAsString( datasetElement, PRE_DWPVS + "Abstract/text()", 408 nsContext, null ); 409 Keywords[] keywords = getKeywords( XMLTools.getNodes( datasetElement, PRE_OWS + "Keywords", 410 nsContext ) ); 411 String[] crsStrings = XMLTools.getNodesAsStrings( datasetElement, PRE_DWPVS + "CRS/text()", 412 nsContext ); 413 List<CoordinateSystem> crsList = parseCoordinateSystems( crsStrings ); 414 415 if ( parent == null ) { // root dataset 416 if ( crsList.size() == 0 || crsList.get( 0 ) == null ) { 417 throw new InvalidCapabilitiesException( 418 Messages.getMessage( 419 "WPVS_NO_TOPLEVEL_DATASET_CRS", 420 title ) ); 421 } 422 defaultCoordinateSystem = crsList.get( 0 ); 423 } 424 425 String[] format = XMLTools.getRequiredNodesAsStrings( datasetElement, PRE_DWPVS 426 + "Format/text()", 427 nsContext ); 428 // wgs84 == mandatory 429 Element boundingBoxElement = (Element) XMLTools.getRequiredNode( 430 datasetElement, 431 PRE_OWS 432 + "WGS84BoundingBox", 433 nsContext ); 434 Envelope wgs84BoundingBox = getWGS84BoundingBoxType( boundingBoxElement ); 435 436 Envelope[] boundingBoxes = getBoundingBoxes( datasetElement, defaultCoordinateSystem ); 437 Dimension[] dimensions = parseDimensions( datasetElement ); 438 DataProvider dataProvider = parseDataProvider( datasetElement ); 439 Identifier identifier = parseDatasetIdentifier( datasetElement, PRE_DWPVS + "Identifier" ); 440 MetaData[] metaData = parseMetaData( datasetElement ); 441 DatasetReference[] datasetRefs = parseDatasetReferences( datasetElement ); 442 FeatureListReference[] featureListRefs = parseFeatureListReferences( datasetElement ); 443 Style[] style = parseStyles( datasetElement ); 444 double minScaleDenom = XMLTools.getNodeAsDouble( 445 datasetElement, 446 PRE_DWPVS 447 + "MinimumScaleDenominator/text()", 448 nsContext, 0 ); 449 450 // update the smallestMinimalScaleDenomiator 451 if ( minScaleDenom < smallestMinimalScaleDenominator ) 452 smallestMinimalScaleDenominator = minScaleDenom; 453 454 double maxScaleDenom = XMLTools.getNodeAsDouble( 455 datasetElement, 456 PRE_DWPVS 457 + "MaximumScaleDenominator/text()", 458 nsContext, 9E9 ); 459 460 if ( minScaleDenom >= maxScaleDenom ) { 461 throw new InvalidCapabilitiesException( "MinimumScaleDenominator must be " 462 + "less than MaximumScaleDenominator!" ); 463 } 464 CoordinateSystem currentCRS = defaultCoordinateSystem; 465 if ( crsList.size() > 0 && crsList.get( 0 ) != null ) { 466 currentCRS = crsList.get( 0 ); 467 } 468 ElevationModel elevationModel = parseElevationModel( datasetElement, name, 469 minimalWCS_DGMResolution, currentCRS ); 470 AbstractDataSource[] dataSources = parseAbstractDatasources( datasetElement, name, 471 currentCRS ); 472 473 // create new root dataset 474 Dataset dataset = new Dataset( queryable, opaque, noSubsets, fixedWidth, fixedHeight, name, 475 title, abstract_, keywords, crsList, format, 476 wgs84BoundingBox, boundingBoxes, dimensions, dataProvider, 477 identifier, metaData, datasetRefs, featureListRefs, style, 478 minScaleDenom, maxScaleDenom, null, elevationModel, 479 dataSources, parent ); 480 481 // get child datasets 482 List nl = XMLTools.getNodes( datasetElement, PRE_DWPVS + "Dataset", nsContext ); 483 Dataset[] childDatasets = new Dataset[nl.size()]; 484 for ( int i = 0; i < childDatasets.length; i++ ) { 485 childDatasets[i] = parseDataset( (Element) nl.get( i ), dataset, 486 defaultCoordinateSystem, minimalWCS_DGMResolution ); 487 488 } 489 490 // set child datasets 491 dataset.setDatasets( childDatasets ); 492 493 return dataset; 494 } 495 496 /** 497 * Creates and returns a new <code>ElevationModel</code> object from the given 498 * <code>Element</code> and the parent <code>Dataset</code>. 499 * 500 * The OGC ElevationModel contains only a String. The Deegree ElevationModel additionaly 501 * contains a complex dataSource. 502 * 503 * @param datasetElement 504 * @param parent 505 * @return Returns the ElevationModel object. 506 * @throws XMLParsingException 507 * @throws OGCWebServiceException 508 * @throws InvalidParameterValueException 509 * @throws MissingParameterValueException 510 * @throws InvalidConfigurationException 511 */ 512 private ElevationModel parseElevationModel( Element datasetElement, String parentName, 513 double minimalWCS_DGMResolution, 514 CoordinateSystem defaultCRS ) 515 throws XMLParsingException, MissingParameterValueException, 516 InvalidParameterValueException, OGCWebServiceException, 517 InvalidConfigurationException { 518 519 Element elevationElement = null; 520 String name = null; 521 ElevationModel elevationModel = null; 522 523 elevationElement = (Element) XMLTools.getNode( datasetElement, 524 PRE_DWPVS + "ElevationModel", nsContext ); 525 526 AbstractDataSource[] dataSources = null; 527 if ( elevationElement != null ) { 528 529 name = XMLTools.getRequiredNodeAsString( elevationElement, PRE_DWPVS + "Name/text()", 530 nsContext ); 531 532 dataSources = parseAbstractDatasources( elevationElement, parentName, defaultCRS ); 533 if ( dataSources.length < 1 ) { 534 throw new InvalidCapabilitiesException( 535 "Each '" 536 + elevationElement.getNodeName() 537 + "' must contain at least one data source!" ); 538 } 539 if ( !Double.isNaN( minimalWCS_DGMResolution ) ) { 540 // little trick to know which dgm datasources have a configured minimal resolution, 541 // if the minimalWCS_DGMResolution is not set (e.g Double.nan) nothing has to be 542 // done (a value of 0d is presumed) 543 for ( AbstractDataSource source : dataSources ) { 544 if ( source.getServiceType() == AbstractDataSource.LOCAL_WCS 545 || source.getServiceType() == AbstractDataSource.REMOTE_WCS ) { 546 ( (LocalWCSDataSource) source ).setConfiguredMinimalDGMResolution( minimalWCS_DGMResolution ); 547 } 548 } 549 } 550 } 551 552 elevationModel = new ElevationModel( name, dataSources ); 553 554 return elevationModel; 555 } 556 557 /** 558 * Creates and returns a new array of <code>AbstractDataSource</code> objects from the given 559 * <code>Element</code>. 560 * 561 * If the objects are used within an ElevationModel object, they may be of the following types: 562 * LocalWCSDataSource, RemoteWCSDataSource, LocalWFSDataSource, RemoteWFSDataSource. If the 563 * objects are used within a Dataset object, they may additionaly be of the types: 564 * LocalWMSDataSource, RemoteWMSDataSource. 565 * 566 * @param element 567 * @return Returns a new array of AbstractDataSource objects. 568 * @throws XMLParsingException 569 * @throws OGCWebServiceException 570 * @throws InvalidConfigurationException 571 */ 572 private AbstractDataSource[] parseAbstractDatasources( Element element, String parentName, 573 CoordinateSystem defaultCRS ) 574 throws XMLParsingException, OGCWebServiceException, 575 InvalidConfigurationException { 576 577 List abstractDataSources = XMLTools.getNodes( element, "*", nsContext ); 578 List<AbstractDataSource> tempDataSources = new ArrayList<AbstractDataSource>( 579 abstractDataSources.size() ); 580 581 for ( int i = 0; i < abstractDataSources.size(); i++ ) { 582 583 Element dataSourceElement = (Element) abstractDataSources.get( i ); 584 585 // String nodeName = dataSourceElement.getNodeName(); 586 String nodeName = dataSourceElement.getLocalName(); 587 588 if ( nodeName.endsWith( "DataSource" ) ) { 589 QualifiedName pn = null; 590 if ( parentName != null ) { 591 pn = new QualifiedName( PRE_DWPVS, parentName, nsContext.getURI( PRE_DWPVS ) ); 592 } 593 QualifiedName name = XMLTools.getNodeAsQualifiedName( dataSourceElement, 594 PRE_DWPVS + "Name/text()", 595 nsContext, pn ); 596 597 OWSCapabilities owsCapabilities = parseOWSCapabilities( dataSourceElement ); 598 599 double minScaleDenom = XMLTools.getNodeAsDouble( 600 dataSourceElement, 601 PRE_DWPVS 602 + "MinimumScaleDenominator/text()", 603 nsContext, 0 ); 604 605 // update the smallestMinimalScaleDenomiator 606 if ( minScaleDenom < smallestMinimalScaleDenominator ) 607 smallestMinimalScaleDenominator = minScaleDenom; 608 609 double maxScaleDenom = XMLTools.getNodeAsDouble( 610 dataSourceElement, 611 PRE_DWPVS 612 + "MaximumScaleDenominator/text()", 613 nsContext, 9E9 ); 614 615 Surface validArea = parseValidArea( dataSourceElement, defaultCRS ); 616 AbstractDataSource dataSource = null; 617 618 if ( nodeName.equals( "LocalWCSDataSource" ) ) { 619 Element filterElement = (Element) XMLTools.getRequiredNode( 620 dataSourceElement, 621 PRE_DWPVS 622 + "FilterCondition", 623 nsContext ); 624 GetCoverage getCoverage = parseWCSFilterCondition( filterElement ); 625 Color[] transparentColors = parseTransparentColors( dataSourceElement ); 626 627 dataSource = new LocalWCSDataSource( name, owsCapabilities, validArea, 628 minScaleDenom, maxScaleDenom, getCoverage, 629 transparentColors ); 630 LOG.logDebug( "created local wcs with name: " + name ); 631 632 } else if ( nodeName.equals( "RemoteWCSDataSource" ) ) { 633 Element filterElement = (Element) XMLTools.getRequiredNode( 634 dataSourceElement, 635 PRE_DWPVS 636 + "FilterCondition", 637 nsContext ); 638 GetCoverage getCoverage = parseWCSFilterCondition( filterElement ); 639 Color[] transparentColors = parseTransparentColors( dataSourceElement ); 640 641 dataSource = new RemoteWCSDataSource( name, owsCapabilities, validArea, 642 minScaleDenom, maxScaleDenom, 643 getCoverage, transparentColors ); 644 LOG.logDebug( "created remote wcs with name: " + name ); 645 646 } else if ( nodeName.equals( "LocalWFSDataSource" ) ) { 647 Text geoPropNode = (Text) XMLTools.getRequiredNode( 648 dataSourceElement, 649 PRE_DWPVS 650 + "GeometryProperty/text()", 651 nsContext ); 652 PropertyPath geometryProperty = parsePropertyPath( geoPropNode ); 653 654 Element filterElement = (Element) XMLTools.getNode( 655 dataSourceElement, 656 PRE_DWPVS 657 + "FilterCondition/ogc:Filter", 658 nsContext ); 659 660 Filter filterCondition = null; 661 if ( filterElement != null ) { 662 filterCondition = AbstractFilter.buildFromDOM( filterElement, false ); 663 } 664 665 // FeatureCollectionAdapter adapter = createFCAdapterFromAdapterClassName( 666 // dataSourceElement ); 667 668 dataSource = new LocalWFSDataSource( name, owsCapabilities, validArea, 669 minScaleDenom, maxScaleDenom, 670 geometryProperty, filterCondition/* 671 * , 672 * adapter 673 */); 674 LOG.logDebug( "created local wfs with name: " + name ); 675 676 } else if ( nodeName.equals( "RemoteWFSDataSource" ) ) { 677 Text geoPropNode = (Text) XMLTools.getRequiredNode( 678 dataSourceElement, 679 PRE_DWPVS 680 + "GeometryProperty/text()", 681 nsContext ); 682 PropertyPath geometryProperty = parsePropertyPath( geoPropNode ); 683 684 Element filterElement = (Element) XMLTools.getNode( 685 dataSourceElement, 686 PRE_DWPVS 687 + "FilterCondition/ogc:Filter", 688 nsContext ); 689 690 Filter filterCondition = null; 691 if ( filterElement != null ) { 692 filterCondition = AbstractFilter.buildFromDOM( filterElement, false ); 693 } 694 695 // FeatureCollectionAdapter adapter = createFCAdapterFromAdapterClassName( 696 // dataSourceElement ); 697 698 dataSource = new RemoteWFSDataSource( name, owsCapabilities, validArea, 699 minScaleDenom, maxScaleDenom, 700 geometryProperty, filterCondition 701 /* ,adapter */); 702 LOG.logDebug( "created remote wfs with name: " + name ); 703 704 } else if ( nodeName.equals( "LocalWMSDataSource" ) ) { 705 if ( element.getNodeName().endsWith( "ElevationModel" ) ) { 706 throw new InvalidConfigurationException( "An ElevationModel cannot " 707 + "contain a LocalWMSDataSource!" ); 708 } 709 Element filterElement = (Element) XMLTools.getRequiredNode( 710 dataSourceElement, 711 PRE_DWPVS 712 + "FilterCondition", 713 nsContext ); 714 GetMap getMap = parseWMSFilterCondition( filterElement ); 715 716 Color[] transparentColors = parseTransparentColors( dataSourceElement ); 717 718 dataSource = new LocalWMSDataSource( name, owsCapabilities, validArea, 719 minScaleDenom, maxScaleDenom, getMap, 720 transparentColors ); 721 LOG.logDebug( "created local wms with name: " + name ); 722 723 } else if ( nodeName.equals( "RemoteWMSDataSource" ) ) { 724 if ( element.getNodeName().endsWith( "ElevationModel" ) ) { 725 throw new InvalidConfigurationException( "An ElevationModel cannot " 726 + "contain a LocalWMSDataSource!" ); 727 } 728 Element filterElement = (Element) XMLTools.getRequiredNode( 729 dataSourceElement, 730 PRE_DWPVS 731 + "FilterCondition", 732 nsContext ); 733 GetMap getMap = parseWMSFilterCondition( filterElement ); 734 735 Color[] transparentColors = parseTransparentColors( dataSourceElement ); 736 737 dataSource = new RemoteWMSDataSource( name, owsCapabilities, validArea, 738 minScaleDenom, maxScaleDenom, getMap, 739 transparentColors ); 740 LOG.logDebug( "created remote wms with name: " + name ); 741 } else { 742 throw new InvalidCapabilitiesException( "Unknown data source: '" + nodeName 743 + "'" ); 744 } 745 746 tempDataSources.add( dataSource ); 747 } 748 } 749 750 AbstractDataSource[] dataSources = tempDataSources.toArray( new AbstractDataSource[tempDataSources.size()] ); 751 752 return dataSources; 753 } 754 755 /** 756 * FIXME check content of StringBuffer and Map! This is an adapted copy from: 757 * org.deegree.ogcwebservices.wms.configuration#parseWMSFilterCondition(Node) 758 * 759 * Creates and returns a new <code>GetMap</code> object from the given <code>Element</code>. 760 * 761 * @param filterElement 762 * @return a partial wms GetMap request instance 763 * @throws XMLParsingException 764 */ 765 private GetMap parseWMSFilterCondition( Element filterElement ) 766 throws XMLParsingException { 767 768 GetMap getMap = null; 769 770 String wmsRequest = XMLTools.getRequiredNodeAsString( filterElement, PRE_DWPVS 771 + "WMSRequest/text()", 772 nsContext ); 773 774 StringBuffer sd = new StringBuffer( 1000 ); 775 sd.append( "REQUEST=GetMap&LAYERS=%default%&STYLES=&SRS=EPSG:4326&" ); 776 sd.append( "BBOX=0,0,1,1&WIDTH=1&HEIGHT=1&FORMAT=%default%" ); 777 778 Map<String, String> map1 = KVP2Map.toMap( sd.toString() ); 779 780 Map<String, String> map2 = KVP2Map.toMap( wmsRequest ); 781 if ( map2.get( "VERSION" ) == null && map2.get( "WMTVER" ) == null ) { 782 map2.put( "VERSION", "1.1.1" ); 783 } 784 // if no service is set use WMS as default 785 if ( map2.get( "SERVICE" ) == null ) { 786 map2.put( "SERVICE", "WMS" ); 787 } 788 789 map1.putAll( map2 ); 790 791 String id = Long.toString( IDGenerator.getInstance().generateUniqueID() ); 792 map1.put( "ID", id ); 793 try { 794 getMap = GetMap.create( map1 ); 795 } catch ( Exception e ) { 796 throw new XMLParsingException( "could not create GetMap from WMS FilterCondition", e ); 797 } 798 799 return getMap; 800 } 801 802 /** 803 * FIXME check content of StringBuffer ! This is an adapted copy from: 804 * org.deegree.ogcwebservices.wms.configuration#parseWCSFilterCondition(Node) 805 * 806 * Creates and returns a new <code>GetCoverage</code> object from the given 807 * <code>Element</code>. 808 * 809 * @param filterElement 810 * @return a partial GetCoverage request 811 * @throws XMLParsingException 812 */ 813 private GetCoverage parseWCSFilterCondition( Element filterElement ) 814 throws XMLParsingException { 815 816 GetCoverage coverage = null; 817 818 String wcsRequest = XMLTools.getRequiredNodeAsString( filterElement, PRE_DWPVS 819 + "WCSRequest/text()", 820 nsContext ); 821 822 StringBuffer sd = new StringBuffer( 1000 ); 823 sd.append( "version=1.0.0&Coverage=%default%&CRS=EPSG:4326&BBOX=0,0,1,1" ); 824 sd.append( "&Width=1&Height=1&Format=%default%&" ); 825 sd.append( wcsRequest ); 826 827 String id = "" + IDGenerator.getInstance().generateUniqueID(); 828 829 try { 830 coverage = GetCoverage.create( id, sd.toString() ); 831 } catch ( Exception e ) { 832 throw new XMLParsingException( "Could not create GetCoverage " 833 + "from WPVS FilterCondition", e ); 834 } 835 836 return coverage; 837 } 838 839 /** 840 * Creates and returns a new <code>OWSCapabilities</code> object from the given 841 * <code>Element</code>. 842 * 843 * @param element 844 * @return Returns a new OWSCapabilities object. 845 * @throws XMLParsingException 846 * @throws InvalidCapabilitiesException 847 */ 848 private OWSCapabilities parseOWSCapabilities( Element element ) 849 throws XMLParsingException, InvalidCapabilitiesException { 850 851 Element owsCapabilitiesElement = (Element) XMLTools.getRequiredNode( 852 element, 853 PRE_DWPVS 854 + "OWSCapabilities", 855 nsContext ); 856 857 String format = null; 858 859 // FIXME 860 // schema has onlineResourceType as not optional, so it should be mandatory. 861 // but in other examples onlineResource is never created with this onlineResourceType. 862 // therefore it gets omitted here, too. 863 864 // String onlineResourceType = XMLTools.getRequiredNodeAsString( 865 // owsCapabilitiesElement, PRE_DWPVS+"OnlineResource/@xlink:type", nsContext ); 866 867 String onlineResourceURI = XMLTools.getRequiredNodeAsString( 868 owsCapabilitiesElement, 869 PRE_DWPVS 870 + "OnlineResource/@xlink:href", 871 nsContext ); 872 873 URL onlineResource; 874 try { 875 onlineResource = resolve( onlineResourceURI ); 876 } catch ( MalformedURLException e ) { 877 throw new InvalidCapabilitiesException( onlineResourceURI 878 + " does not represent a valid URL: " 879 + e.getMessage() ); 880 } 881 LOG.logDebug( "found following onlineResource: " + onlineResource ); 882 return new OWSCapabilities( format, onlineResource ); 883 884 // FIXME 885 // if onlineResourceType is going to be used, the returned new OnlineResource should be 886 // created with different constructor: 887 // return new OWSCapabilities( format, onlineResourceType, onlineResource ); 888 } 889 890 /** 891 * Creates and returns a new <code>Geometry</code> object from the given Element. 892 * 893 * @param dataSource 894 * @return Returns a new Geometry object. 895 * @throws XMLParsingException 896 * @throws InvalidConfigurationException 897 */ 898 private Surface parseValidArea( Element dataSource, CoordinateSystem defaultCRS ) 899 throws XMLParsingException, InvalidConfigurationException { 900 List nl = XMLTools.getNodes( dataSource, PRE_DWPVS + "ValidArea/*", nsContext ); 901 if ( nl.size() == 0 ) { 902 return null; 903 } 904 905 if ( nl.size() > 1 ) { 906 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_NUMBER_OF_VALID_AREAS", 907 GMLNS.toASCIIString(), dataSource.getLocalName() ) ); 908 return null; 909 } 910 Surface validArea = null; 911 if ( ( (Node) nl.get( 0 ) ).getNamespaceURI().equals( GMLNS.toASCIIString() ) ) { 912 try { 913 String srsName = XMLTools.getNodeAsString( (Node) nl.get( 0 ), "@srsName", 914 nsContext, null ); 915 if ( srsName == null ) { 916 srsName = defaultCRS.getFormattedString(); 917 } 918 919 Geometry geom = GMLGeometryAdapter.wrap( (Element) nl.get( 0 ), srsName ); 920 if ( !( geom instanceof Surface ) ) { 921 throw new InvalidConfigurationException( 922 Messages.getMessage( 923 "WPVS_WRONG_GEOMTERY_VALID_AREA", 924 dataSource.getLocalName() ) ); 925 } 926 validArea = (Surface) geom; 927 } catch ( GeometryException e ) { 928 throw new InvalidConfigurationException( 929 Messages.getMessage( 930 "WPVS_WRONG_GEOMTERY_VALID_AREA", 931 dataSource.getLocalName() ) 932 + "\n" 933 + e.getMessage(), 934 935 e ); 936 } 937 938 } else if ( ( (Node) nl.get( 0 ) ).getNamespaceURI().equals( CommonNamespaces.OWSNS ) ) { 939 try { 940 Element bbox = (Element) nl.get( 0 ); 941 if ( !"BoundingBox".equals( bbox.getLocalName() ) ) { 942 throw new InvalidConfigurationException( 943 Messages.getMessage( 944 "WPVS_WRONG_GEOMTERY_VALID_AREA", 945 dataSource.getLocalName() ) ); 946 } 947 Envelope env = parseBoundingBox( (Element) nl.get( 0 ), null ); 948 validArea = GeometryFactory.createSurface( env, env.getCoordinateSystem() ); 949 } catch ( GeometryException e ) { 950 throw new InvalidConfigurationException( 951 Messages.getMessage( 952 "WPVS_WRONG_GEOMTERY_VALID_AREA", 953 dataSource.getLocalName() ) 954 + "\n" 955 + e.getMessage(), 956 e ); 957 } catch ( InvalidParameterValueException e ) { 958 throw new InvalidConfigurationException( 959 Messages.getMessage( 960 "WPVS_WRONG_GEOMTERY_VALID_AREA", 961 dataSource.getLocalName() ) 962 + "\n" 963 + e.getMessage(), 964 e ); 965 } 966 } else { 967 LOG.logWarning( Messages.getMessage( "WPVS_WRONG_GEOMTERY_VALID_AREA", 968 dataSource.getLocalName() ) ); 969 return null; 970 } 971 return validArea; 972 } 973 974 /** 975 * Creates and returns a new array of <code>Color</code> objects from the given Element. 976 * 977 * @param dataSourceElement 978 * @return Returns a new array of Color objects. 979 * @throws XMLParsingException 980 * @throws InvalidCapabilitiesException 981 */ 982 private Color[] parseTransparentColors( Element dataSourceElement ) 983 throws XMLParsingException { 984 985 List colorList = XMLTools.getNodes( dataSourceElement, PRE_DWPVS + "TransparentColors/" 986 + PRE_DWPVS + "Color", nsContext ); 987 988 Color[] transparentColors = null; 989 if ( colorList != null ) { 990 transparentColors = new Color[colorList.size()]; 991 992 for ( int i = 0; i < transparentColors.length; i++ ) { 993 994 Element colorElement = (Element) colorList.get( i ); 995 String color = XMLTools.getRequiredNodeAsString( colorElement, "text()", nsContext ); 996 997 transparentColors[i] = Color.decode( color ); 998 } 999 } 1000 1001 return transparentColors; 1002 } 1003 1004 } 1005 1006 /*************************************************************************************************** 1007 * <code> 1008 * Changes to this class. What the people have been up to: 1009 * 1010 * $Log$ 1011 * Revision 1.51 2007/03/08 10:16:42 bezema 1012 * added support for the extendRequestPercentage parameter and some small docu/code changes 1013 * 1014 * Revision 1.50 2007/03/06 14:56:55 poth 1015 * bug fix wpvs accessing a dataservices caps 1016 * 1017 * Revision 1.49 2007/03/05 10:19:46 bezema 1018 * removed the usage of an deprectated api 1019 * 1020 * Revision 1.48 2007/01/29 16:44:10 bezema 1021 * removing use of the deprecated api 1022 * 1023 * Revision 1.47 2007/01/29 09:05:16 bezema 1024 * removing use of the deprecated api 1025 * 1026 * Revision 1.46 2007/01/15 17:02:14 bezema 1027 * Updated the capabilities /configuration parsing, and the construction of their beans 1028 * 1029 * Revision 1.45 2006/12/22 13:37:35 poth 1030 * code formatting 1031 * 1032 * Revision 1.44 2006/12/21 11:22:04 bezema 1033 * removed the gabs in a pointbased dgm by interpolation of the nearest boundingbox points and Made the minimalterrainheight configurable. 1034 * 1035 * Revision 1.43 2006/12/20 14:31:50 bezema 1036 * removed syso 1037 * 1038 * Revision 1.42 2006/12/06 12:00:46 poth 1039 * bug fix - reading relative pathes 1040 * 1041 * Revision 1.41 2006/12/06 11:24:33 bezema 1042 * can use the wcs as a localdatasource for textures and dgm, also added support for the wfs features in gml. Still trying to figure out how the eyepoint is set by java3d 1043 * 1044 * Revision 1.40 2006/11/28 18:09:28 mschneider 1045 * Fixed header. 1046 * 1047 * Revision 1.39 2006/11/28 18:08:55 mschneider 1048 * Fixed parsing of GeometryProperty name. Namespace binding was not correctly extracted (null). 1049 * 1050 * Revision 1.38 2006/11/28 16:52:19 bezema Added support for a default splitter 1051 * 1052 * Revision 1.37 2006/11/27 15:41:13 bezema Updated the coordinatesystem handling and the featurecollection adapter 1053 * 1054 * Revision 1.36 2006/11/27 11:44:14 bezema Added a minimalScaleDenomitator check 1055 1056 * Revision 1.34 2006/11/23 11:46:40 bezema The initial version of the new wpvs 1057 * 1058 * Revision 1.33 2006/11/07 16:33:49 poth bug fixes and code formatting 1059 * 1060 * Revision 1.32 2006/08/07 12:14:57 poth never read variable removed 1061 * 1062 * Revision 1.31 2006/07/20 08:13:05 taddei use of QualiName for geometry property 1063 * 1064 * Revision 1.30 2006/07/12 16:59:32 poth required adaptions according to renaming of OnLineResource to OnlineResource 1065 * 1066 * Revision 1.29 2006/07/05 15:58:23 poth bug fix - changed Query to Filter for WFS datasources 1067 * 1068 * Revision 1.28 2006/06/29 19:06:54 poth ** empty log message *** 1069 * 1070 * Revision 1.27 2006/06/29 18:50:16 poth bug fix reading optional element TransparentColors 1071 * 1072 * Revision 1.26 2006/06/20 07:45:21 taddei datasources use quali names now 1073 * 1074 * Revision 1.25 2006/05/05 12:41:36 taddei fixed bug in max tex size 1075 * 1076 * Revision 1.24 2006/04/26 12:13:07 taddei max size and tex config parameters 1077 * 1078 * Revision 1.23 2006/04/06 20:25:24 poth ** empty log message *** 1079 * 1080 * Revision 1.22 2006/04/05 08:56:21 taddei refactoring: fc adapter 1081 * 1082 * Revision 1.20 2006/03/07 08:46:26 taddei added pts list factory 1083 * 1084 * Revision 1.19 2006/02/14 15:14:43 taddei added possibility to choose splitter 1085 * 1086 * Revision 1.18 2006/02/10 16:05:41 taddei capabilities use now resolve() 1087 * 1088 * Revision 1.17 2006/01/30 14:56:10 taddei implementation of copyright info 1089 * 1090 * Revision 1.16 2006/01/26 13:54:59 taddei added code for parsing ElevationModel/Name 1091 * 1092 * Revision 1.15 2006/01/18 08:47:54 taddei bug fixes 1093 * 1094 * Revision 1.14 2005/12/23 11:16:50 mays add comments 1095 * 1096 * Revision 1.13 2005/12/23 10:39:19 mays add imports that where accidentally lost 1097 * 1098 * Revision 1.12 2005/12/23 10:34:56 mays correction of color and filterConditions 1099 * 1100 * Revision 1.10 2005/12/13 13:31:49 mays changes in parseElevationModel because of necessary changes in namespace 1101 * 1102 * Revision 1.9 2005/12/12 13:51:38 mays revision of parseElevationModel, parseDataset, parseDeegreeParams and parseOWSCapabilities. 1103 * 1104 * Revision 1.8 2005/12/09 14:11:22 mays code clean up 1105 * 1106 * Revision 1.7 2005/12/08 16:53:10 mays organized imports 1107 * 1108 * Revision 1.6 2005/12/08 16:49:08 mays move configuration specific stuff from WPVSCapabilitiesDocument to here 1109 * 1110 * Revision 1.5 2005/12/01 10:30:14 mays add standard footer to all java classes in wpvs package 1111 * </code> 1112 **************************************************************************************************/