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