package org.deegree.ogcwebservices.wcs.getcoverage; import java.net.URI; import java.util.List; import java.util.Map; import org.deegree.datatypes.Code; import org.deegree.datatypes.time.TimeSequence; import org.deegree.framework.util.KVP2Map; import org.deegree.framework.util.StringTools; import org.deegree.framework.xml.NamespaceContext; import org.deegree.framework.xml.XMLTools; import org.deegree.model.coverage.grid.Grid; import org.deegree.model.crs.CRSFactory; import org.deegree.model.crs.CoordinateSystem; import org.deegree.model.crs.UnknownCRSException; import org.deegree.model.spatialschema.Envelope; import org.deegree.model.spatialschema.GeometryFactory; import org.deegree.model.spatialschema.Position; import org.deegree.ogcbase.CommonNamespaces; import org.deegree.ogcbase.ExceptionCode; import org.deegree.ogcbase.GMLDocument; import org.deegree.ogcwebservices.InvalidParameterValueException; import org.deegree.ogcwebservices.MissingParameterValueException; import org.deegree.ogcwebservices.OGCWebServiceException; import org.deegree.ogcwebservices.wcs.InterpolationMethod; import org.deegree.ogcwebservices.wcs.WCSException; import org.deegree.ogcwebservices.wcs.WCSRequestBase; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * encapsulates a WCS GetCoverage request * * @version $Revision: 1.20 $ * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> * @author last edited by: $Author: bezema $ * * @version 1.0. $Revision: 1.20 $, $Date: 2006/11/29 15:58:57 $ * * @since 2.0 */ public class GetCoverage extends WCSRequestBase { /** * */ private static final long serialVersionUID = 44735033754048955L; private static final NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); private String sourceCoverage = null; private DomainSubset domainSubset = null; private RangeSubset rangeSubset = null; private InterpolationMethod interpolationMethod = null; private Output output = null; /** * @param id * @param version * @param sourceCoverage * @param domainSubset * @param output * @throws WCSException * @throws OGCWebServiceException */ public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, Output output ) throws WCSException, OGCWebServiceException { this( id, version, sourceCoverage, domainSubset, null, null, output ); } /** * @param id * @param version * @param sourceCoverage * @param domainSubset * @param interpolationMethod * @param output * @throws WCSException * @throws OGCWebServiceException */ public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, InterpolationMethod interpolationMethod, Output output ) throws WCSException, OGCWebServiceException { this( id, version, sourceCoverage, domainSubset, null, interpolationMethod, output ); } /** * @param id * @param version * @param sourceCoverage * @param domainSubset * @param rangeSubset * @param output * @throws WCSException * @throws OGCWebServiceException */ public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, RangeSubset rangeSubset, Output output ) throws WCSException, OGCWebServiceException { this( id, version, sourceCoverage, domainSubset, rangeSubset, null, output ); } /** * @param id * @param version * @param sourceCoverage * @param domainSubset * @param rangeSubset * @param interpolationMethod * @param output * @throws WCSException * @throws OGCWebServiceException */ public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, RangeSubset rangeSubset, InterpolationMethod interpolationMethod, Output output ) throws WCSException, OGCWebServiceException { super( id, version ); if ( sourceCoverage == null || sourceCoverage.length() == 0 ) { throw new WCSException( "sourceCoverage must be a valid string with length > 0" ); } if ( domainSubset == null ) { throw new WCSException( "domainSubset must be <> null in GetCoverage" ); } if ( output == null ) { throw new WCSException( "output must be <> null in GetCoverage" ); } this.sourceCoverage = sourceCoverage; this.domainSubset = domainSubset; this.rangeSubset = rangeSubset; this.interpolationMethod = interpolationMethod; this.output = output; } /** * creates a GetCoverage request from its KVP representation * * @param id * unique ID of the request * @param kvp * request * @return created <tt>GetCoverage</tt> * @throws OGCWebServiceException * will be thrown if something general is wrong * @throws WCSException * will be thrown if a WCS/GetCoverage specific part of the request is erroreous */ public static GetCoverage create( String id, String kvp ) throws OGCWebServiceException, WCSException { Map<String, String> map = KVP2Map.toMap( kvp ); map.put( "ID", id ); return create( map ); } /** * creates a GetCoverage request from its KVP representation * * @param map * request * @return created <tt>GetCoverage</tt> * @throws OGCWebServiceException * will be thrown if something general is wrong * @throws MissingParameterValueException * @throws InvalidParameterValueException * @throws WCSException * will be thrown if a WCS/GetCoverage specific part of the request is erroreous */ public static GetCoverage create( Map<String, String> map ) throws OGCWebServiceException, MissingParameterValueException, InvalidParameterValueException { String version = map.remove( "VERSION" ); if ( version == null ) { throw new MissingParameterValueException( "'version' must be set" ); } if ( !"1.0.0".equals( version ) ) { ExceptionCode ecode = ExceptionCode.INVALIDPARAMETERVALUE; throw new InvalidParameterValueException( "GetCoverage", "'version' must be 1.0.0", ecode ); } String coverage = map.remove( "COVERAGE" ); String crs = map.remove( "CRS" ); if ( crs == null ) { ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; throw new MissingParameterValueException( "GetCoverage", "'crs' is missing", code ); } String response_crs = map.remove( "RESPONSE_CRS" ); if ( response_crs == null ) { response_crs = crs; } String format = map.remove( "FORMAT" ); Output output = createOutput( response_crs, null, format, null ); SpatialSubset sps = createSpatialSubset( map, crs ); String time = map.remove( "TIME" ); TimeSequence temporalSubset = null; if ( time != null ) { temporalSubset = new TimeSequence( time ); } Code code = new Code( crs, null ); DomainSubset domainSubset = new DomainSubset( code, sps, temporalSubset ); String except = map.remove( "EXCEPTIONS" ); if ( except == null ) { except = "application/vnd.ogc.se_xml"; } else if ( !except.equals( "application/vnd.ogc.se_xml" ) ) { ExceptionCode ecode = ExceptionCode.INVALIDPARAMETERVALUE; throw new InvalidParameterValueException( "GetCoverage", "exceptions != application/vnd.ogc.se_xml", ecode ); } String id = map.remove( "ID" ); GetCoverage gc = new GetCoverage( id, version, coverage, domainSubset, null, null, output ); gc.validate(); return gc; } /** * creates a GetCoverage request from its XML representation * * @param id * unique ID of the request * @param doc * XML representation of the request * @return created <tt>DescribeCoverage</tt> * @throws OGCWebServiceException * will be thrown if something general is wrong * @throws WCSException * will be thrown if a WCS/GetCoverage specific part of the request is erroreous */ public static GetCoverage create( String id, Document doc ) throws OGCWebServiceException, WCSException { GetCoverage gc = null; try { String version = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/@version", nsContext, null ); if ( version == null ) { throw new MissingParameterValueException( "'version' must be set" ); } if ( !"1.0.0".equals( version ) ) { ExceptionCode ecode = ExceptionCode.INVALIDPARAMETERVALUE; throw new InvalidParameterValueException( "GetCoverage", "'version' must be 1.0.0", ecode ); } String coverage = XMLTools.getRequiredNodeAsString( doc, "/wcs:GetCoverage/wcs:sourceCoverage", nsContext ); String interpol = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/wcs:interpolationMethod", nsContext, null ); InterpolationMethod interpolMeth = null; if ( interpol == null || "nearest neighbor".equals( interpol ) ) { interpolMeth = new InterpolationMethod( "nearest neighbor" ); } String path = "/wcs:GetCoverage/wcs:domainSubset/wcs:spatialSubset"; List nl = XMLTools.getNodes( doc, path, nsContext ); SpatialSubset sp = null; if ( nl.size() > 0 ) { Node node = (Node) nl.get( 0 ); sp = createSpatialSubset( (Element) node ); } else { // TODO // temporal subset } // TODO // path = "/wcs:GetCoverage/wcs:rangeSubset/wcs:axisSubset"; // nl = XMLTools.getXPath(path, doc, nsContext); // evaluate possible ranges; e.g.time, extent String format = XMLTools.getRequiredNodeAsString( doc, "/wcs:GetCoverage/wcs:output/wcs:format", nsContext ); // use crs defined for the requested envelope if no CRS is defined // in the request String crsName = "EPSG:4326"; if ( sp.getEnvelope().getCoordinateSystem() != null ) { crsName = sp.getEnvelope().getCoordinateSystem().getName(); } String crs = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/wcs:output/wcs:crs", nsContext, crsName ); String ipm = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/wcs:interpolationMethod", nsContext, null ); if ( ipm != null && !ipm.equals( "nearest neighbor" ) ) { throw new InvalidParameterValueException( "interpolationMethod must " + "have the value 'nearest neighbor'" ); } Output output = createOutput( crs, null, format, null ); DomainSubset domainSubset = new DomainSubset( new Code( crsName ), sp ); gc = new GetCoverage( id, version, coverage, domainSubset, null, interpolMeth, output ); } catch ( Exception e ) { ExceptionCode code = ExceptionCode.INVALID_FORMAT; throw new WCSException( "GetCoverage", StringTools.stackTraceToString( e ), code ); } gc.validate(); return gc; } /** * @param element * @return a new Spatial subset * @throws WCSException */ private static SpatialSubset createSpatialSubset( Element element ) throws WCSException { SpatialSubset sp = null; try { List nl = XMLTools.getNodes( element, "gml:Envelope", nsContext ); Envelope env = GMLDocument.parseEnvelope( (Element) nl.get( 0 ) ); nl = XMLTools.getNodes( element, "gml:Grid", nsContext ); Grid grid = GMLDocument.parseGrid( (Element) nl.get( 0 ) ); sp = new SpatialSubset( env, grid.getGridEnvelope() ); } catch ( Exception e ) { ExceptionCode code = ExceptionCode.INVALID_FORMAT; throw new WCSException( "GetCoverage", StringTools.stackTraceToString( e ), code ); } return sp; } /** * @param map * @param crs * @return a new SpatialSubset with given crs * @throws WCSException */ public static final SpatialSubset createSpatialSubset( Map map, String crs ) throws WCSException { Envelope envelope = createEnvelope( map, crs ); int width = (int) getNumber( (String) map.remove( "WIDTH" ), "WIDTH" ); int height = (int) getNumber( (String) map.remove( "HEIGHT" ), "HEIGHT" ); int depth = (int) getNumber( (String) map.remove( "DEPTH" ), "DEPTH" ); double resx = getNumber( (String) map.remove( "RESX" ), "RESX" ); double resy = getNumber( (String) map.remove( "RESY" ), "RESY" ); double resz = getNumber( (String) map.remove( "RESZ" ), "RESZ" ); Position low = null; Position high = null; if ( width > 0 && height > 0 ) { if ( depth > 0 ) { low = GeometryFactory.createPosition( 0, 0, 0 ); high = GeometryFactory.createPosition( width - 1, height - 1, depth - 1 ); } else { low = GeometryFactory.createPosition( 0, 0 ); high = GeometryFactory.createPosition( width - 1, height - 1 ); } } else if ( resx > 0 && resy > 0 ) { if ( resz > 0 ) { ExceptionCode code = ExceptionCode.INVALIDPARAMETERVALUE; throw new WCSException( "GetCoverage", "resz is not supported yet", code ); } width = (int) Math.round( envelope.getWidth() / resx ); height = (int) Math.round( envelope.getHeight() / resy ); low = GeometryFactory.createPosition( 0, 0 ); high = GeometryFactory.createPosition( width - 1, height - 1 ); } else { ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; throw new WCSException( "GetCoverage", "width/height or resx/resy must be set", code ); } Envelope grid = GeometryFactory.createEnvelope( low, high, null ); return new SpatialSubset( envelope, grid ); } /** * @param map * @return an envelope. * @throws WCSException */ private static Envelope createEnvelope( Map map, String crs ) throws WCSException { String tmp = (String) map.remove( "BBOX" ); double[] bbox = null; if ( tmp != null ) { try { bbox = StringTools.toArrayDouble( tmp, "," ); } catch ( Exception e ) { ExceptionCode code = ExceptionCode.INVALIDPARAMETERVALUE; throw new WCSException( "GetCoverage", "can't read BBOX", code ); } Position min = null; Position max = null; if ( bbox.length == 4 ) { min = GeometryFactory.createPosition( bbox[0], bbox[1] ); max = GeometryFactory.createPosition( bbox[2], bbox[3] ); } else { min = GeometryFactory.createPosition( bbox[0], bbox[1], bbox[2] ); max = GeometryFactory.createPosition( bbox[3], bbox[4], bbox[5] ); } CoordinateSystem srs; try { srs = CRSFactory.create( crs ); } catch ( UnknownCRSException e ) { throw new WCSException( GetCoverage.class.getName(), e.getMessage() ); } return GeometryFactory.createEnvelope( min, max, srs ); } return null; } /** * creates an <tt>Output</tt> object for a GetCoverage request * * @param response_crs * @param crsNS * @param format * @param formatNS * @return an Output * @throws WCSException * will be thrown if the response_crs prefix isn't a valid URI */ public static final Output createOutput( String response_crs, String crsNS, String format, String formatNS ) throws WCSException { URI crsURI = null; if ( crsNS != null ) { try { crsURI = new URI( crsNS ); } catch ( Exception e ) { throw new WCSException( "invalid response crs namespace: " + crsNS ); } } URI formatURI = null; if ( formatNS != null ) { try { formatURI = new URI( formatNS ); } catch ( Exception e ) { throw new WCSException( "invalid response crs namespace: " + formatNS ); } } Code crs = new Code( response_crs, crsURI ); Code cformat = new Code( format, formatURI ); return new Output( crs, cformat ); } /** * @param val * @param name * @return a Number * @throws WCSException */ private static double getNumber( String val, String name ) throws WCSException { if ( val == null ) return -1; double d = -1; try { d = Double.parseDouble( val ); } catch ( Exception e ) { ExceptionCode code = ExceptionCode.INVALIDPARAMETERVALUE; throw new WCSException( "GetCoverage", name + " isn't a valid number format", code ); } return d; } /** * @return Returns the domainSubset. */ public DomainSubset getDomainSubset() { return domainSubset; } /** * @return Returns the interpolationMethod. */ public InterpolationMethod getInterpolationMethod() { return interpolationMethod; } /** * @return Returns the output. */ public Output getOutput() { return output; } /** * @return Returns the rangeSubset. */ public RangeSubset getRangeSubset() { return rangeSubset; } /** * @return Returns the sourceCoverage. * */ public String getSourceCoverage() { return sourceCoverage; } /** * @throws WCSException */ protected void validate() throws WCSException { if ( getVersion() == null ) { ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; throw new WCSException( "GetCoverage", "'version' is missing", code ); } if ( getSourceCoverage() == null ) { ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; throw new WCSException( "GetCoverage", "'coverage' is missing", code ); } DomainSubset ds = getDomainSubset(); if ( ds.getRequestSRS() == null ) { ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; throw new WCSException( "GetCoverage", "'crs' is missing", code ); } if ( ds.getSpatialSubset() == null && ds.getTemporalSubset() == null ) { ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; throw new WCSException( "GetCoverage", "either temporal subset or spatial " + "subset must be defined", code ); } if ( getOutput().getFormat() == null ) { ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; throw new WCSException( "GetCoverage", "'format' is missing", code ); } } @Override public String toString(){ String response = super.toString(); response += "\nOutput: " + output; response += "\ndomainSubset: " + domainSubset; response += "\nsourceCoverage: " + sourceCoverage; response += "\ninterpolationMethod: " + interpolationMethod; return response; } } /*************************************************************************************************** * Changes to this class. What the people have been up to: $Log: GetCoverage.java,v $ * Changes to this class. What the people have been up to: Revision 1.20 2006/11/29 15:58:57 bezema * Changes to this class. What the people have been up to: added toString and fixed javadoc and warnings * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.19 2006/11/28 16:35:47 bezema * Changes to this class. What the people have been up to: Cleaned up javadoc * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.18 2006/11/27 09:07:53 poth * Changes to this class. What the people have been up to: JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code. * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.17 2006/08/07 13:47:00 poth * Changes to this class. What the people have been up to: bug fix - reading of interprolations method completed * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.16 2006/07/13 13:48:24 poth * Changes to this class. What the people have been up to: parsing TimeSequence from a string extracted as additional constructor into the class TimeSequence * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.15 2006/05/01 20:15:27 poth * Changes to this class. What the people have been up to: *** empty log message *** * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.14 2006/03/03 13:37:42 poth * Changes to this class. What the people have been up to: *** empty log message *** * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.13 2006/02/20 14:14:00 poth * Changes to this class. What the people have been up to: *** empty log message *** * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.12 2006/01/30 14:37:59 taddei * Changes to this class. What the people have been up to: changed private static methods createOutput and createSpatialSubset to public static final to use in WPVS * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.11 2006/01/16 20:36:40 poth * Changes to this class. What the people have been up to: *** empty log message *** * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.10 2005/11/17 08:15:50 deshmukh * Changes to this class. What the people have been up to: Renamed nsNode to nsContext * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.9 2005/11/16 13:45:01 mschneider * Changes to this class. What the people have been up to: Merge of wfs development branch. * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.8.2.2 2005/11/07 16:45:08 deshmukh * Changes to this class. What the people have been up to: NodeList to List * Changes to this class. What the people have been up to: Changes to * this class. What the people have been up to: Revision 1.8.2.1 2005/11/07 15:38:04 mschneider * Changes to this class. What the people have been up to: Refactoring: use NamespaceContext instead * of Node for namespace bindings. Changes to this class. What the people have been up to: Revision * 1.8 2005/09/27 19:53:19 poth no message * * Revision 1.7 2005/03/16 16:22:59 mschneider ** empty log message *** * * Revision 1.6 2005/03/09 11:55:47 mschneider ** empty log message *** * * Revision 1.5 2005/03/01 14:39:08 mschneider ** empty log message *** * * Revision 1.4 2005/02/24 20:04:04 poth no message * * Revision 1.3 2005/02/21 11:24:33 poth no message * * Revision 1.2 2005/01/18 22:08:55 poth no message * * Revision 1.11 2004/09/01 08:06:03 ap no message * * Revision 1.10 2004/08/12 10:39:44 ap no message * * Revision 1.9 2004/07/12 11:14:19 ap no message * * Revision 1.8 2004/07/12 06:12:11 ap no message * * Revision 1.7 2004/06/30 15:16:05 mschneider Refactoring of XMLTools. * * Revision 1.6 2004/06/28 15:40:13 mschneider Finished the generation of the ServiceIdentification * part of the Capabilities from DOM, added functionality to the XMLTools helper class. * * Revision 1.5 2004/06/28 06:26:52 ap no message * * Revision 1.4 2004/06/18 06:18:46 ap no message * * Revision 1.3 2004/06/16 11:48:17 ap no message * * Revision 1.2 2004/05/25 07:19:13 ap no message * * Revision 1.1 2004/05/24 06:54:39 ap no message * * **************************************************************************************************/