// $Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/ogcwebservices/wcs/WCService.java,v 1.27 2006/12/03 21:20:35 poth Exp $ /*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2006 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/deegree/ lat/lon GmbH http://www.lat-lon.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstr. 19 53115 Bonn Germany E-Mail: poth@lat-lon.de Prof. Dr. Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: greve@giub.uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.ogcwebservices.wcs; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.deegree.datatypes.parameter.GeneralParameterValueIm; import org.deegree.datatypes.parameter.OperationParameterIm; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.StringTools; import org.deegree.io.JDBCConnection; import org.deegree.io.oraclegeoraster.GeoRasterDescription; import org.deegree.model.coverage.grid.AbstractGridCoverage; import org.deegree.model.coverage.grid.FormatIm; import org.deegree.model.coverage.grid.GridCoverageExchangeIm; import org.deegree.model.coverage.grid.ImageGridCoverage; import org.deegree.model.crs.GeoTransformer; import org.deegree.model.crs.IGeoTransformer; import org.deegree.model.spatialschema.Envelope; import org.deegree.ogcwebservices.InvalidParameterValueException; import org.deegree.ogcwebservices.OGCWebService; import org.deegree.ogcwebservices.OGCWebServiceException; import org.deegree.ogcwebservices.OGCWebServiceRequest; import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities; import org.deegree.ogcwebservices.wcs.configuration.Directory; import org.deegree.ogcwebservices.wcs.configuration.DirectoryResolution; import org.deegree.ogcwebservices.wcs.configuration.Extension; import org.deegree.ogcwebservices.wcs.configuration.File; import org.deegree.ogcwebservices.wcs.configuration.FileResolution; import org.deegree.ogcwebservices.wcs.configuration.OracleGeoRasterResolution; import org.deegree.ogcwebservices.wcs.configuration.Resolution; import org.deegree.ogcwebservices.wcs.configuration.Shape; import org.deegree.ogcwebservices.wcs.configuration.ShapeResolution; import org.deegree.ogcwebservices.wcs.configuration.WCSConfiguration; import org.deegree.ogcwebservices.wcs.describecoverage.CoverageDescription; import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering; import org.deegree.ogcwebservices.wcs.describecoverage.DescribeCoverage; import org.deegree.ogcwebservices.wcs.describecoverage.InvalidCoverageDescriptionExcpetion; import org.deegree.ogcwebservices.wcs.getcapabilities.ContentMetadata; import org.deegree.ogcwebservices.wcs.getcapabilities.WCSGetCapabilities; import org.deegree.ogcwebservices.wcs.getcapabilities.WCSRequestValidator; import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage; import org.deegree.ogcwebservices.wcs.getcoverage.ResultCoverage; import org.deegree.ogcwebservices.wcs.getcoverage.SpatialSubset; import org.opengis.coverage.Coverage; import org.opengis.coverage.grid.Format; import org.opengis.coverage.grid.GridCoverageReader; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.OperationParameter; import org.xml.sax.SAXException; /** * @version $Revision: 1.27 $ * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> * @author last edited by: $Author: poth $ * * @version 1.0. $Revision: 1.27 $, $Date: 2006/12/03 21:20:35 $ * * @since 2.0 */ public class WCService implements OGCWebService { private static final ILogger LOG = LoggerFactory.getLogger( WCService.class ); /** * */ private WCSConfiguration configuration = null; /** * creates a WCService from a configuration * * @param configuration */ public WCService( WCSConfiguration configuration ) { this.configuration = configuration; } /** * returns the capabilities of the WCS * * @return capabilities of the WCS */ public OGCCapabilities getCapabilities() { return configuration; } /** * @param request * @return */ public CoverageDescription describeCoverage( DescribeCoverage request ) throws OGCWebServiceException { WCSRequestValidator.validate( configuration, request ); CoverageOffering[] co = null; try { co = getCoverageOfferings( request ); } catch ( Exception e ) { LOG.logError( StringTools.stackTraceToString( e ) ); throw new OGCWebServiceException( StringTools.stackTraceToString( e ) ); } CoverageDescription cd = new CoverageDescription( co, request.getVersion() ); return cd; } /** * @param request * @return */ public Coverage getCoverage( GetCoverage request ) throws OGCWebServiceException { WCSRequestValidator.validate( configuration, request ); Coverage cov = null; if ( request.getOutput().getFormat().getCode().equals( "GML" ) ) { CoverageOffering co; try { co = getCoverageOffering( request ); } catch ( InvalidCoverageDescriptionExcpetion e ) { LOG.logError( "CoverageDescription is not valid", e ); throw new OGCWebServiceException( getClass().getName(), "CoverageDescription is not valid: " + e.getMessage() ); } catch ( IOException e ) { LOG.logError( "could not read CoverageDescription", e ); throw new OGCWebServiceException( getClass().getName(), "could not read CoverageDescription: " + e.getMessage() ); } catch ( SAXException e ) { LOG.logError( "could not parse CoverageDescription", e ); throw new OGCWebServiceException( getClass().getName(), "could not parse CoverageDescription: " + e.getMessage() ); } Envelope env = request.getDomainSubset().getSpatialSubset().getEnvelope(); BufferedImage bi = new BufferedImage( 2, 2, BufferedImage.TYPE_INT_ARGB ); cov = new ImageGridCoverage( co, env, bi ); } else { cov = readCoverage( request ); } return cov; } /** * method for event based request procrssing * * @param request * object containing the request. * @return */ public Object doService( OGCWebServiceRequest request ) throws OGCWebServiceException { Object response = null; if ( request instanceof WCSGetCapabilities ) { WCSRequestValidator.validate( configuration, request ); response = getCapabilities(); } else if ( request instanceof GetCoverage ) { Coverage cov = getCoverage( (GetCoverage) request ); response = new ResultCoverage( cov, cov.getClass(), ( (GetCoverage) request ).getOutput().getFormat(), (GetCoverage) request ); } else if ( request instanceof DescribeCoverage ) { response = describeCoverage( (DescribeCoverage) request ); } return response; } /** * returns the <tt>CoverageOffering</tt> s according to the coverages * names contained in the passed request. If the request doesn't contain one * or more named coverage <tt>CoverageOffering</tt> s for all coverages * known by the WCS will be returned. * * @param request * DescribeCoverage request * @return @throws * IOException * @throws SAXException * @throws InvalidCoverageDescriptionExcpetion */ private CoverageOffering[] getCoverageOfferings( DescribeCoverage request ) throws IOException, SAXException, InvalidCoverageDescriptionExcpetion { String[] coverages = request.getCoverages(); CoverageOffering[] co = null; ContentMetadata cm = configuration.getContentMetadata(); if ( coverages.length == 0 ) { // get descriptions of all coverages CoverageOfferingBrief[] cob = cm.getCoverageOfferingBrief(); co = new CoverageOffering[cob.length]; for ( int i = 0; i < cob.length; i++ ) { URL url = cob[i].getConfiguration(); CoverageDescription cd = CoverageDescription.createCoverageDescription( url ); co[i] = cd.getCoverageOffering( cob[i].getName() ); } } else { // get descriptions of all requested coverages co = new CoverageOffering[coverages.length]; for ( int i = 0; i < coverages.length; i++ ) { CoverageOfferingBrief cob = cm.getCoverageOfferingBrief( coverages[i] ); URL url = cob.getConfiguration(); CoverageDescription cd = CoverageDescription.createCoverageDescription( url ); co[i] = cd.getCoverageOffering( cob.getName() ); } } return co; } /** * The method reads and returns the coverage described by the passed * request. * * @param request * @return @throws * OGCWebServiceException * @throws InvalidCoverageDescriptionExcpetion */ private Coverage readCoverage( GetCoverage request ) throws OGCWebServiceException, InvalidCoverageDescriptionExcpetion, InvalidParameterValueException { Coverage result = null; try { CoverageOffering co = getCoverageOffering( request ); Resolution[] resolutions = getResolutions( co, request ); if ( resolutions == null || resolutions.length == 0 ) { throw new InvalidParameterValueException( "No data source defined the requested combination of spatial resolution and ranges" ); } GridCoverageReader reader = null; LOG.logInfo( "getting responsible GridCoverageReader" ); if ( resolutions[0] instanceof FileResolution ) { reader = getFileReader( resolutions, co, request ); } else if ( resolutions[0] instanceof ShapeResolution ) { reader = getShapeReader( resolutions, co, request ); } else if ( resolutions[0] instanceof DirectoryResolution ) { reader = getDirectoryReader( resolutions, co, request ); } else if ( resolutions[0] instanceof OracleGeoRasterResolution ) { reader = getOracleGeoRasterReader( resolutions, co, request ); } List<GeneralParameterValue> list = new ArrayList<GeneralParameterValue>( 10 ); Envelope size = (Envelope) request.getDomainSubset().getSpatialSubset().getGrid(); OperationParameter op = new OperationParameterIm( "width", null, new Integer( (int) size.getWidth() + 1 ) ); list.add( new GeneralParameterValueIm( op ) ); op = new OperationParameterIm( "height", null, new Integer( (int) size.getHeight() + 1 ) ); list.add( new GeneralParameterValueIm( op ) ); GeneralParameterValue[] gpvs = new GeneralParameterValue[list.size()]; result = reader.read( list.toArray( gpvs ) ); // transform Coverage into another CRS if required String crs = request.getOutput().getCrs().getCode(); if ( crs == null ) { crs = request.getDomainSubset().getRequestSRS().getCode(); } if ( !crs.equalsIgnoreCase( co.getSupportedCRSs().getNativeSRSs()[0].getCodes()[0] ) ) { LOG.logDebug( "transforming coverage to " + crs ); GeoTransformer gt = new GeoTransformer( crs ); result = gt.transform( (AbstractGridCoverage)result, 5, 3, null ); } } catch ( Exception e ) { e.printStackTrace(); LOG.logError( StringTools.stackTraceToString( e ) ); throw new OGCWebServiceException( StringTools.stackTraceToString( e ) ); } return result; } /** * returns the <tt>CoverageOffering</tt> describing the access to the data * sources behind the requested coverage * * @param request * GetCoverage request * @return @throws * IOException * @throws SAXException * @throws InvalidCoverageDescriptionExcpetion */ private CoverageOffering getCoverageOffering( GetCoverage request ) throws IOException, SAXException, InvalidCoverageDescriptionExcpetion { ContentMetadata cm = configuration.getContentMetadata(); CoverageOfferingBrief cob = cm.getCoverageOfferingBrief( request.getSourceCoverage() ); URL url = cob.getConfiguration(); CoverageDescription cd = CoverageDescription.createCoverageDescription( url ); CoverageOffering co = cd.getCoverageOffering( request.getSourceCoverage() ); return co; } /** * returns the <tt>Resolution</tt> s matching the scale, region and range * parameters of the passed request * * @param co * @param request * @return */ private Resolution[] getResolutions( CoverageOffering co, GetCoverage request ) { Extension extension = co.getExtension(); SpatialSubset sps = request.getDomainSubset().getSpatialSubset(); // determenine resolution of the requested coverage Envelope env = sps.getEnvelope(); Envelope grid = (Envelope) sps.getGrid(); double qx = env.getWidth() / grid.getWidth(); double qy = env.getHeight() / grid.getHeight(); double reso = qx; // if x- and y-direction has different resolution in the GetCoverage // request use the finest if ( qy < qx ) { reso = qy; } Resolution[] res = extension.getResolutions( reso ); return res; } /** * returns a <tt>GridCoverageReader</tt> for accessing the data source of * the target coverage of the passed GetCoverage request. The reader will be * constructed from all <tt>File</tt> s matching the filter conditions * defined in the passed GeCoverage request. <BR> * At the moment just the first field of the passed <tt>Resolution</tt> * array will be considered! * * @param resolutions * <tT>Resolution</tt> to get a reader for * @param co * description of the requested coverage * @param request * @return <tt>GridCoverageReader</tt> * @throws IOException */ private GridCoverageReader getFileReader( Resolution[] resolutions, CoverageOffering co, GetCoverage request ) throws IOException, InvalidParameterValueException { String nativeCRS = co.getSupportedCRSs().getNativeSRSs()[0].getCodes()[0]; // calculates the envevole to be used by the created GridCoverageReader Envelope envelope = calculateRequestEnvelope( request, nativeCRS ); File[] files = ( (FileResolution) resolutions[0] ).getFiles(); List list = new ArrayList(); for ( int i = 0; i < files.length; i++ ) { Envelope fileEnv = files[i].getEnvelope(); if ( fileEnv.intersects( envelope ) ) { list.add( files[i] ); } } files = (File[]) list.toArray( new File[list.size()] ); GridCoverageExchangeIm gce = new GridCoverageExchangeIm( null ); Format format = new FormatIm( co.getSupportedFormats().getNativeFormat() ); GridCoverageReader reader = gce.getReader( files, co, envelope, format ); return reader; } /** * returns a <tt>GridCoverageReader</tt> for accessing the data source of * the target coverage of the passed GetCoverage request. The reader will be * constructed from all <tt>Shape</tt> s matching the filter conditions * defined in the passed GeCoverage request. At least this should be just * one! <BR> * At the moment just the first field of the passed <tt>Resolution</tt> * array will be considered! * * @param resolutions * @param co * @param request * @return @throws * IOException */ private GridCoverageReader getShapeReader( Resolution[] resolutions, CoverageOffering co, GetCoverage request ) throws IOException, InvalidParameterValueException { String nativeCRS = co.getSupportedCRSs().getNativeSRSs()[0].getCodes()[0]; // calculates the envevole to be used by the created GridCoverageReader Envelope envelope = calculateRequestEnvelope( request, nativeCRS ); Shape shape = ( (ShapeResolution) resolutions[0] ).getShape(); GridCoverageExchangeIm gce = new GridCoverageExchangeIm( null ); Format format = new FormatIm( co.getSupportedFormats().getNativeFormat() ); GridCoverageReader reader = gce.getReader( shape, co, envelope, format ); return reader; } /** * returns a <tt>GridCoverageReader</tt> for accessing the data source of * the target coverage of the passed GetCoverage request. The reader will be * constructed from all <tt>Directory</tt> s matching the filter * conditions defined in the passed GeCoverage request. At least this should * be just one! <BR> * At the moment just the first field of the passed <tt>Resolution</tt> * array will be considered! * * @param resolutions * @param co * @param request * @return @throws * IOException */ private GridCoverageReader getDirectoryReader( Resolution[] resolutions, CoverageOffering co, GetCoverage request ) throws IOException, InvalidParameterValueException { String nativeCRS = co.getSupportedCRSs().getNativeSRSs()[0].getCodes()[0]; // calculates the envevole to be used by the created GridCoverageReader Envelope envelope = calculateRequestEnvelope( request, nativeCRS ); Directory[] dirs = ( (DirectoryResolution) resolutions[0] ).getDirectories( envelope ); GridCoverageExchangeIm gce = new GridCoverageExchangeIm( null ); Format format = new FormatIm( co.getSupportedFormats().getNativeFormat() ); GridCoverageReader reader = gce.getReader( dirs, co, envelope, format ); return reader; } /** * returns a <tt>GridCoverageReader</tt> for accessing the data source of * the target coverage of the passed GetCoverage request. The reader will be * constructed from the JDBCV connnection defined in the CoverageDescription * extension.<BR> * At the moment just the first field of the passed <tt>Resolution</tt> * array will be considered! * * @param resolutions * @param co * @param request * @return * @throws InvalidParameterValueException * @throws IOException */ private GridCoverageReader getOracleGeoRasterReader( Resolution[] resolutions, CoverageOffering co, GetCoverage request ) throws InvalidParameterValueException, IOException { String nativeCRS = co.getSupportedCRSs().getNativeSRSs()[0].getCodes()[0]; // calculates the envevole to be used by the created GridCoverageReader Envelope envelope = calculateRequestEnvelope( request, nativeCRS ); JDBCConnection jdbc = ( (OracleGeoRasterResolution) resolutions[0] ).getJDBCConnection(); String table = ( (OracleGeoRasterResolution) resolutions[0] ).getTable(); String rdtTable = ( (OracleGeoRasterResolution) resolutions[0] ).getRdtTable(); String column = ( (OracleGeoRasterResolution) resolutions[0] ).getColumn(); String identification = ( (OracleGeoRasterResolution) resolutions[0] ).getIdentification(); int level = ( (OracleGeoRasterResolution) resolutions[0] ).getLevel(); GeoRasterDescription grd = new GeoRasterDescription( jdbc, table, rdtTable, column, identification, level ); GridCoverageExchangeIm gce = new GridCoverageExchangeIm( null ); Format format = new FormatIm( co.getSupportedFormats().getNativeFormat() ); return gce.getReader( grd, co, envelope, format ); } /** * According to WCS 1.0.0 the CRS of the GetCoverage request BBOX can be * different to the desired CRS of the resulting coverage. This method * transforms the request CRS to the output CRS if requiered. At the moment * deegree WCS doesn't support transformation of grid coverages so the * output CRS will always be the native CRS of te data. * * @param request * @param targetCrs * @return @throws * InvalidParameterValueException */ private Envelope calculateRequestEnvelope( GetCoverage request, String targetCrs ) throws InvalidParameterValueException { SpatialSubset spsu = request.getDomainSubset().getSpatialSubset(); Envelope envelope = spsu.getEnvelope(); String reqCrs = request.getDomainSubset().getRequestSRS().getCode(); if ( !reqCrs.equals( targetCrs ) ) { IGeoTransformer gt = new GeoTransformer(targetCrs); try { envelope = gt.transform( envelope, reqCrs ); } catch ( Exception e ) { throw new InvalidParameterValueException( "requestCRS couldn't be " + "transformed to outputCRS: " + reqCrs ); } } return envelope; } } /* ****************************************************************************** * Changes to this class. What the people have been up to: * $Log: WCService.java,v $ * Revision 1.27 2006/12/03 21:20:35 poth * support for transforming GridCoverages into other CRS added * * Revision 1.26 2006/11/27 09:07:53 poth * JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code. * * Revision 1.25 2006/09/27 16:46:41 poth * transformation method signature changed * * Revision 1.24 2006/09/14 20:07:35 poth * code formatting * * Revision 1.23 2006/06/12 08:11:21 poth * footer comment corrected * * Revision 1.22 2006/05/18 15:58:07 poth * *** empty log message *** * * Revision 1.21 2006/05/03 20:09:52 poth * *** empty log message *** * * Revision 1.20 2006/05/01 20:15:27 poth * *** empty log message *** * * Revision 1.19 2006/04/06 20:25:31 poth * *** empty log message *** * * Revision 1.18 2006/03/30 21:20:28 poth * *** empty log message *** * * Revision 1.17 2006/03/16 12:22:28 poth * *** empty log message *** * * Revision 1.16 2006/03/16 12:22:01 poth * *** empty log message *** * * Revision 1.15 2006/03/15 22:20:09 poth * *** empty log message *** * * Revision 1.14 2006/03/14 08:51:22 poth * *** empty log message *** * * Revision 1.13 2006/03/02 21:39:38 poth * *** empty log message *** * * Revision 1.12 2006/03/02 11:06:04 poth * *** empty log message *** * * Revision 1.11 2006/02/28 17:53:31 poth * *** empty log message *** * * Revision 1.10 2006/02/05 20:33:09 poth * *** empty log message *** * * Revision 1.9 2006/01/11 16:57:02 poth * *** empty log message *** * * Revision 1.8 2005/12/21 17:30:10 poth * no message * * Revision 1.7 2005/11/21 15:03:42 deshmukh * CRS to SRS * * ***************************************************************************** */