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