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