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 }