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