001 // $HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/ogcwebservices/wcs/configuration/ExtensionDocument.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 package org.deegree.ogcwebservices.wcs.configuration; 037 038 import java.io.File; 039 import java.net.MalformedURLException; 040 import java.net.URI; 041 import java.net.URISyntaxException; 042 import java.net.URL; 043 import java.util.ArrayList; 044 import java.util.List; 045 046 import org.deegree.datatypes.values.Interval; 047 import org.deegree.datatypes.values.TypedLiteral; 048 import org.deegree.framework.log.ILogger; 049 import org.deegree.framework.log.LoggerFactory; 050 import org.deegree.framework.util.StringTools; 051 import org.deegree.framework.xml.ElementList; 052 import org.deegree.framework.xml.NamespaceContext; 053 import org.deegree.framework.xml.XMLFragment; 054 import org.deegree.framework.xml.XMLParsingException; 055 import org.deegree.framework.xml.XMLTools; 056 import org.deegree.io.IODocument; 057 import org.deegree.io.JDBCConnection; 058 import org.deegree.model.crs.CRSFactory; 059 import org.deegree.model.crs.CoordinateSystem; 060 import org.deegree.model.crs.UnknownCRSException; 061 import org.deegree.model.spatialschema.Envelope; 062 import org.deegree.model.spatialschema.GMLGeometryAdapter; 063 import org.deegree.ogcbase.CommonNamespaces; 064 import org.deegree.ogcbase.InvalidGMLException; 065 import org.deegree.ogcwebservices.InvalidParameterValueException; 066 import org.w3c.dom.Element; 067 import org.w3c.dom.Node; 068 069 /** 070 * This class creates a class representation of the Extension section of a deegree WCS coverage offering (coverage 071 * configuration) element. the extension section contains informations about data access/sources for different 072 * resolutions and ranges.<BR> 073 * an extension section must contain at least one Resolution element but can contains as much as the user may defined. A 074 * resoluton contains a access informations for data and the ranges the data are assigned to. because of this it is 075 * possible that more than one Resoultion element with same resolution range but with different other ranges (e.g. time 076 * or elevation) 077 * 078 * @version $Revision: 23585 $ 079 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 080 * @author last edited by: $Author: aschmitz $ 081 * 082 * @version 1.0. $Revision: 23585 $, $Date: 2010-04-13 14:07:18 +0200 (Di, 13 Apr 2010) $ 083 * 084 * @since 1.1 085 */ 086 public class ExtensionDocument { 087 088 private static final ILogger LOG = LoggerFactory.getLogger( ExtensionDocument.class ); 089 090 private static URI GMLNS = CommonNamespaces.GMLNS; 091 092 private static URI DGRNS = CommonNamespaces.DEEGREEWCS; 093 094 private static NamespaceContext nsc = CommonNamespaces.getNamespaceContext(); 095 096 private URL systemId = null; 097 098 private Element root = null; 099 100 /** 101 * constructing the ExtensionBuilder by passing the root element of a deegree WCS CoverageOffering Extension. 102 * 103 * @param root 104 * @param systemId 105 */ 106 public ExtensionDocument( Element root, URL systemId ) { 107 this.root = root; 108 this.systemId = systemId; 109 } 110 111 /** 112 * returns the content of the Extension element of te deegree WCS coverage description (configuration document). the 113 * extension section contains informations about data access/sources for different resolutions and ranges.<BR> 114 * an extension section must contain at least one Resolution element but can contains as much as the user may 115 * defined. A resoluton contains a access informations for data and the ranges the data are assigned to. because of 116 * this it is possible that more than one Resoultion element with same resolution range but with different other 117 * ranges (e.g. time or elevation) 118 * 119 * @return content of the Extension element of te deegree WCS coverage description 120 * @throws InvalidCVExtensionException 121 * @throws UnknownCVExtensionException 122 * @throws InvalidParameterValueException 123 * @throws InvalidGMLException 124 * @throws UnknownCRSException 125 */ 126 public Extension getExtension() 127 throws InvalidCVExtensionException, UnknownCVExtensionException, 128 InvalidParameterValueException, InvalidGMLException, UnknownCRSException { 129 Extension extension = null; 130 try { 131 String type = XMLTools.getRequiredNodeAsString( root, "./@type", nsc ); 132 double offset = XMLTools.getNodeAsDouble( root, "./@offset", nsc, 0 ); 133 double scaleFactor = XMLTools.getNodeAsDouble( root, "./@scaleFactor", nsc, 1 ); 134 ElementList el = XMLTools.getChildElements( "Resolution", DGRNS, root ); 135 Resolution[] resolutions = getResolutions( type, el ); 136 extension = new DefaultExtension( type, resolutions, offset, scaleFactor ); 137 } catch ( XMLParsingException e ) { 138 throw new InvalidCVExtensionException( StringTools.stackTraceToString( e ) ); 139 } 140 return extension; 141 } 142 143 /** 144 * returns the resolutions definitions within the Extension element of the deegree WCS coverage offering. Each 145 * resoultion contains access description for its data and an optional description of the ranges the data are valid 146 * for. 147 * 148 * @param type 149 * @param el 150 * @return resolutions definitions within the Extension element of the deegree WCS coverage offering 151 * @throws XMLParsingException 152 * @throws InvalidParameterValueException 153 * @throws UnknownCRSException 154 */ 155 private Resolution[] getResolutions( String type, ElementList el ) 156 throws XMLParsingException, InvalidParameterValueException, InvalidGMLException, 157 UnknownCRSException { 158 Resolution[] resolutions = new Resolution[el.getLength()]; 159 for ( int i = 0; i < resolutions.length; i++ ) { 160 resolutions[i] = getResolution( type, el.item( i ) ); 161 } 162 return resolutions; 163 } 164 165 /** 166 * creates an instance of <tt>Resoltuion</tt> from the passed <tt>Element</tt> and the type of the coverage source. 167 * Valid values for type are: 168 * <ul> 169 * <li>shapeIndexed 170 * <li>nameIndexed 171 * <li>file 172 * </ul> 173 * if an unknown typed is passed an <tt>InvalidParameterValueException</tt> will be thrown 174 * 175 * @param type 176 * @param element 177 * @return created Resoltuion 178 * @throws XMLParsingException 179 * @throws UnknownCRSException 180 */ 181 private Resolution getResolution( String type, Element element ) 182 throws XMLParsingException, InvalidParameterValueException, InvalidGMLException, 183 UnknownCRSException { 184 String tmp = XMLTools.getRequiredAttrValue( "min", null, element ); 185 double min = Double.parseDouble( tmp ); 186 tmp = XMLTools.getRequiredAttrValue( "max", null, element ); 187 double max = Double.parseDouble( tmp ); 188 // ElementList el = XMLTools.getChildElements( "Range", DGRNS, element ); 189 NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); 190 List<Node> el = XMLTools.getNodes( element, "deegreewcs:Range", nsContext ); 191 Range[] ranges = getRanges( el ); 192 Resolution resolution = null; 193 194 if ( type.equals( Extension.SHAPEINDEXED ) ) { 195 // TODO 196 // enable more than one shape 197 Element elem = XMLTools.getRequiredElement( element, "deegreewcs:Shape", nsContext ); 198 Shape shape = getShape( elem ); 199 resolution = new ShapeResolution( min, max, ranges, shape ); 200 } else if ( type.equals( Extension.NAMEINDEXED ) ) { 201 ElementList ell = XMLTools.getChildElements( "Directory", DGRNS, element ); 202 Directory[] dirs = new Directory[ell.getLength()]; 203 for ( int i = 0; i < dirs.length; i++ ) { 204 dirs[i] = getDirectory( ell.item( i ) ); 205 } 206 resolution = new DirectoryResolution( min, max, ranges, dirs ); 207 } else if ( type.equals( Extension.FILEBASED ) ) { 208 ElementList ell = XMLTools.getChildElements( "File", DGRNS, element ); 209 org.deegree.ogcwebservices.wcs.configuration.File[] files = new org.deegree.ogcwebservices.wcs.configuration.File[ell.getLength()]; 210 for ( int i = 0; i < files.length; i++ ) { 211 files[i] = getFile( ell.item( i ) ); 212 } 213 resolution = new FileResolution( min, max, ranges, files ); 214 } else if ( type.equals( Extension.ORACLEGEORASTER ) ) { 215 resolution = getOracleGeoRasterResolution( element, min, max, ranges ); 216 217 } else if ( type.equals( Extension.DATABASEINDEXED ) ) { 218 resolution = getDatabaseIndexed( element, min, max, ranges ); 219 } else if ( type.equals( Extension.SCRIPTBASED ) ) { 220 resolution = getScriptBased( element, min, max, ranges ); 221 } else { 222 String msg = StringTools.concat( 200, "type: ", type, " not known ", "by the deegree WCS" ); 223 throw new InvalidParameterValueException( msg ); 224 } 225 return resolution; 226 } 227 228 private Resolution getScriptBased( Element element, double min, double max, Range[] ranges ) 229 throws XMLParsingException, InvalidParameterValueException { 230 231 XMLFragment xml = new XMLFragment( element ); 232 try { 233 xml.setSystemId( systemId.toExternalForm() ); 234 } catch ( MalformedURLException e ) { 235 // should never happen because systemID is read from a valid URL 236 } 237 238 NamespaceContext nsc = CommonNamespaces.getNamespaceContext(); 239 String xpath = "deegreewcs:Script/deegreewcs:Name"; 240 String script = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 241 242 xpath = "deegreewcs:Script/deegreewcs:Parameter"; 243 List<Node> list = XMLTools.getNodes( element, xpath, nsc ); 244 List<String> parameter = new ArrayList<String>( list.size() ); 245 for ( Node node : list ) { 246 parameter.add( XMLTools.getStringValue( node ) ); 247 } 248 xpath = "deegreewcs:Script/deegreewcs:ResultFormat"; 249 String resultFormat = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 250 xpath = "deegreewcs:Script/deegreewcs:StorageLocation"; 251 String storageLocation = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 252 try { 253 storageLocation = new File( xml.resolve( storageLocation ).getFile() ).getAbsolutePath(); 254 } catch ( MalformedURLException e ) { 255 e.printStackTrace(); 256 throw new InvalidParameterValueException( e.getMessage(), e ); 257 } 258 return new ScriptResolution( min, max, ranges, script, parameter, resultFormat, storageLocation ); 259 } 260 261 /** 262 * creates a <tt>DatabaseResolution</tt> object from the passed element 263 * 264 * @param element 265 * @param min 266 * @param max 267 * @param ranges 268 * @return the resolution 269 * @throws XMLParsingException 270 */ 271 private Resolution getDatabaseIndexed( Element element, double min, double max, Range[] ranges ) 272 throws XMLParsingException { 273 274 NamespaceContext nsc = CommonNamespaces.getNamespaceContext(); 275 String xpath = "deegreewcs:Database/dgjdbc:JDBCConnection"; 276 Node node = XMLTools.getRequiredNode( element, xpath, nsc ); 277 IODocument io = new IODocument( (Element) node ); 278 JDBCConnection jdbc = io.parseJDBCConnection(); 279 xpath = "deegreewcs:Database/deegreewcs:Table/text()"; 280 String table = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 281 xpath = "deegreewcs:Database/deegreewcs:DataRootDirectory/text()"; 282 String rootDir = XMLTools.getNodeAsString( element, xpath, nsc, "./" ); 283 File dir = new File( rootDir ); 284 if ( !dir.isAbsolute() ) { 285 XMLFragment xml = new XMLFragment(); 286 xml.setRootElement( root ); 287 xml.setSystemId( systemId ); 288 try { 289 URL url = xml.resolve( rootDir ); 290 dir = new File( url.toURI() ); 291 } catch ( Exception e ) { 292 LOG.logError( e.getMessage(), e ); 293 } 294 } 295 return new DatabaseResolution( min, max, ranges, jdbc, table, dir.getAbsolutePath() ); 296 } 297 298 /** 299 * creates a <tt>OracleGeoRasterResolution</tt> object from the passed element 300 * 301 * @param element 302 * @param min 303 * @param max 304 * @param ranges 305 * @return the Resolution 306 * @throws XMLParsingException 307 */ 308 private Resolution getOracleGeoRasterResolution( Element element, double min, double max, Range[] ranges ) 309 throws XMLParsingException { 310 Resolution resolution; 311 NamespaceContext nsc = CommonNamespaces.getNamespaceContext(); 312 String xpath = "deegreewcs:OracleGeoRaster/dgjdbc:JDBCConnection"; 313 Node node = XMLTools.getRequiredNode( element, xpath, nsc ); 314 IODocument io = new IODocument( (Element) node ); 315 JDBCConnection jdbc = io.parseJDBCConnection(); 316 xpath = "deegreewcs:OracleGeoRaster/deegreewcs:Table/text()"; 317 String table = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 318 xpath = "deegreewcs:OracleGeoRaster/deegreewcs:RDTTable/text()"; 319 String rdtTable = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 320 xpath = "deegreewcs:OracleGeoRaster/deegreewcs:Column/text()"; 321 String column = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 322 xpath = "deegreewcs:OracleGeoRaster/deegreewcs:Identification/text()"; 323 String identification = XMLTools.getRequiredNodeAsString( element, xpath, nsc ); 324 xpath = "deegreewcs:OracleGeoRaster/deegreewcs:Level/text()"; 325 int level = XMLTools.getNodeAsInt( element, xpath, nsc, 1 ); 326 resolution = new OracleGeoRasterResolution( min, max, ranges, jdbc, table, rdtTable, column, identification, 327 level ); 328 return resolution; 329 } 330 331 /** 332 * creates a <tt>Shape</tt> object from the passed element 333 * 334 * @param element 335 * @return created Shape 336 * @throws XMLParsingException 337 * @throws UnknownCRSException 338 */ 339 private Shape getShape( Element element ) 340 throws XMLParsingException, UnknownCRSException { 341 String tilePoperty = XMLTools.getRequiredAttrValue( "tileProperty", null, element ); 342 String directoryProperty = XMLTools.getRequiredAttrValue( "directoryProperty", null, element ); 343 String srsName = XMLTools.getRequiredAttrValue( "srsName", null, element ); 344 CoordinateSystem crs = CRSFactory.create( srsName ); 345 String rootFileName = XMLTools.getStringValue( element ); 346 rootFileName = rootFileName.trim(); 347 XMLFragment xml = new XMLFragment(); 348 xml.setRootElement( root ); 349 xml.setSystemId( systemId ); 350 java.io.File file = null; 351 try { 352 URL url = xml.resolve( rootFileName + ".shp" ); 353 file = new java.io.File( url.toURI() ); 354 } catch ( Exception e ) { 355 LOG.logError( e.getMessage(), e ); 356 } 357 rootFileName = file.getAbsolutePath(); 358 rootFileName = rootFileName.substring( 0, rootFileName.lastIndexOf( "." ) ); 359 return new Shape( crs, rootFileName, tilePoperty, directoryProperty ); 360 } 361 362 /** 363 * creates a <tt>File</tt> object from the passed Element that describes the extensions and locations of the 364 * coverages assigned to a <tt>Resolution</tt> 365 * 366 * @param element 367 * @return <tt>File</tt> object from the passed Element that describes the extensions and locations of the coverages 368 * assigned to a <tt>Resolution</tt> 369 * @throws XMLParsingException 370 * @throws UnknownCRSException 371 */ 372 private org.deegree.ogcwebservices.wcs.configuration.File getFile( Element element ) 373 throws XMLParsingException, InvalidGMLException, UnknownCRSException { 374 String name = XMLTools.getRequiredStringValue( "Name", DGRNS, element ); 375 XMLFragment xml = new XMLFragment(); 376 xml.setRootElement( element ); 377 xml.setSystemId( systemId ); 378 File file = new File( name ); 379 try { 380 URL url = xml.resolve( name ); 381 file = new java.io.File( url.toURI() ); 382 } catch ( Exception e ) { 383 LOG.logError( e.getMessage(), e ); 384 e.printStackTrace(); 385 } 386 name = file.getAbsolutePath(); 387 388 Element elem = XMLTools.getRequiredChildElement( "Envelope", GMLNS, element ); 389 Envelope envelope = GMLGeometryAdapter.wrapBox( elem, null ); 390 String srs = XMLTools.getRequiredAttrValue( "srsName", null, elem ); 391 392 String[] tmp = StringTools.toArray( srs, "#", false ); 393 // just a heuristic because it is not guarranteed that the URL 394 // in the srsName attribute can be solved 395 if ( srs.toLowerCase().indexOf( "epsg" ) > -1 ) { 396 srs = "EPSG:" + tmp[1]; 397 } else { 398 srs = "CRS:" + tmp[1]; 399 } 400 if ( tmp[1].equals( "0" ) ) { 401 srs = null; 402 } 403 404 CoordinateSystem crs = CRSFactory.create( srs ); 405 return new org.deegree.ogcwebservices.wcs.configuration.File( crs, name, envelope ); 406 } 407 408 /** 409 * creates a <tt>Directory</tt> object from the passed Elememt that describes the extensions and locations of the 410 * coverages assigned to a <tt>Resolution</tt> 411 * 412 * @param element 413 * @return <tt>Directory</tt> object from the passed Elememt that describes the extensions and locations of the 414 * coverages assigned to a <tt>Resolution</tt> 415 * @throws XMLParsingException 416 * @throws UnknownCRSException 417 */ 418 private Directory getDirectory( Element element ) 419 throws XMLParsingException, InvalidGMLException, UnknownCRSException { 420 // get valid file extension for this directory 421 String temp = XMLTools.getRequiredAttrValue( "extensions", null, element ); 422 String[] extensions = StringTools.toArray( temp, ",;", true ); 423 // get the width and height (in pixels) af the tiles in this directory 424 temp = XMLTools.getRequiredAttrValue( "tileWidth", null, element ); 425 double tileWidth = 0; 426 try { 427 tileWidth = Double.parseDouble( temp ); 428 } catch ( Exception e ) { 429 throw new XMLParsingException( "tileWidth attribute isn't a number" ); 430 } 431 double tileHeight = 0; 432 try { 433 tileHeight = Double.parseDouble( temp ); 434 } catch ( Exception e ) { 435 throw new XMLParsingException( "tileHeight attribute isn't a number" ); 436 } 437 // get the directroy name 438 String name = XMLTools.getRequiredStringValue( "Name", DGRNS, element ); 439 XMLFragment xml = new XMLFragment(); 440 xml.setRootElement( element ); 441 xml.setSystemId( systemId ); 442 try { 443 // resolve name if relative 444 name = xml.resolve( name ).toExternalForm(); 445 } catch ( MalformedURLException e ) { 446 throw new XMLParsingException( "invalid file name/path: " + name ); 447 } 448 // get the bounding envelope of all tiles in the directory 449 Element elem = XMLTools.getRequiredChildElement( "Envelope", GMLNS, element ); 450 Envelope envelope = GMLGeometryAdapter.wrapBox( elem, null ); 451 String srs = XMLTools.getRequiredAttrValue( "srsName", null, elem ); 452 if ( srs != null ) { 453 String[] tmp = StringTools.toArray( srs, "#", false ); 454 // just a heuristic because it is not guarranteed that the URL 455 // in the srsName attribute can be solved 456 if ( srs.toLowerCase().indexOf( "epsg" ) > -1 ) { 457 srs = "EPSG:" + tmp[1]; 458 } else { 459 srs = "CRS:" + tmp[1]; 460 } 461 if ( tmp[1].equals( "0" ) ) 462 srs = null; 463 } 464 CoordinateSystem crs = CRSFactory.create( srs ); 465 return new GridDirectory( name, envelope, crs, extensions, tileWidth, tileHeight ); 466 } 467 468 /** 469 * creates an array of <tt>Ranges</tt> from the passed element list 470 * 471 * @param el 472 * @return created array of <tt>Ranges</tt> 473 * @throws XMLParsingException 474 */ 475 private Range[] getRanges( List<Node> el ) 476 throws XMLParsingException { 477 Range[] ranges = new Range[el.size()]; 478 for ( int i = 0; i < ranges.length; i++ ) { 479 ranges[i] = getRange( (Element) el.get( i ) ); 480 } 481 return ranges; 482 } 483 484 /** 485 * creates a <tt>Range</tt> object from the passed element 486 * 487 * @param element 488 * @return created <tt>Range</tt> 489 * @throws XMLParsingException 490 */ 491 private Range getRange( Element element ) 492 throws XMLParsingException { 493 String name = XMLTools.getRequiredStringValue( "Name", DGRNS, element ); 494 ElementList el = XMLTools.getChildElements( "Axis", DGRNS, element ); 495 Axis[] axis = getAxis( el ); 496 return new Range( name, axis ); 497 } 498 499 /** 500 * creates an array of <tt>Axis</tt> objects from the passed element list 501 * 502 * @param el 503 * @return created array of <tt>Axis</tt> 504 * @throws XMLParsingException 505 */ 506 private Axis[] getAxis( ElementList el ) 507 throws XMLParsingException { 508 Axis[] axis = new Axis[el.getLength()]; 509 for ( int i = 0; i < axis.length; i++ ) { 510 axis[i] = getAxis( el.item( i ) ); 511 } 512 return axis; 513 } 514 515 /** 516 * creates an <tt>Axis</tt> object from the passed element. The <tt>Interval</tt> included in the <tt>Axis</tt> 517 * doesn't have a resolution because it isn't required. 518 * 519 * @param element 520 * @return created <tt>Axis</tt> 521 * @throws XMLParsingException 522 */ 523 private Axis getAxis( Element element ) 524 throws XMLParsingException { 525 try { 526 String name = XMLTools.getRequiredStringValue( "Name", DGRNS, element ); 527 Element elem = XMLTools.getRequiredChildElement( "Interval", DGRNS, element ); 528 String tmp = XMLTools.getRequiredStringValue( "min", DGRNS, elem ); 529 TypedLiteral min = new TypedLiteral( tmp, new URI( "xs:double" ) ); 530 tmp = XMLTools.getRequiredStringValue( "max", DGRNS, elem ); 531 TypedLiteral max = new TypedLiteral( tmp, new URI( "xs:double" ) ); 532 Interval interval = new Interval( min, max, null, null, null ); 533 return new Axis( name, interval ); 534 } catch ( URISyntaxException e ) { 535 LOG.logError( e.getMessage(), e ); 536 throw new XMLParsingException( e.getMessage() ); 537 } 538 } 539 540 }