001 // $HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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: 20592 $
079 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
080 * @author last edited by: $Author: rbezema $
081 *
082 * @version 1.0. $Revision: 20592 $, $Date: 2009-11-05 13:24:27 +0100 (Do, 05. Nov 2009) $
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.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 }