001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wcs/getcoverage/GetCoverage.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 53177 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 package org.deegree.ogcwebservices.wcs.getcoverage; 044 045 import java.net.URI; 046 import java.util.List; 047 import java.util.Map; 048 049 import org.deegree.datatypes.Code; 050 import org.deegree.datatypes.time.TimeSequence; 051 import org.deegree.framework.util.KVP2Map; 052 import org.deegree.framework.util.StringTools; 053 import org.deegree.framework.xml.NamespaceContext; 054 import org.deegree.framework.xml.XMLTools; 055 import org.deegree.model.coverage.grid.Grid; 056 import org.deegree.model.crs.CRSFactory; 057 import org.deegree.model.crs.CoordinateSystem; 058 import org.deegree.model.crs.UnknownCRSException; 059 import org.deegree.model.spatialschema.Envelope; 060 import org.deegree.model.spatialschema.GeometryFactory; 061 import org.deegree.model.spatialschema.Position; 062 import org.deegree.ogcbase.CommonNamespaces; 063 import org.deegree.ogcbase.ExceptionCode; 064 import org.deegree.ogcbase.GMLDocument; 065 import org.deegree.ogcwebservices.InvalidParameterValueException; 066 import org.deegree.ogcwebservices.MissingParameterValueException; 067 import org.deegree.ogcwebservices.OGCWebServiceException; 068 import org.deegree.ogcwebservices.wcs.InterpolationMethod; 069 import org.deegree.ogcwebservices.wcs.WCSException; 070 import org.deegree.ogcwebservices.wcs.WCSRequestBase; 071 import org.w3c.dom.Document; 072 import org.w3c.dom.Element; 073 import org.w3c.dom.Node; 074 075 /** 076 * encapsulates a WCS GetCoverage request 077 * 078 * @version $Revision: 7583 $ 079 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 080 * @author last edited by: $Author: apoth $ 081 * 082 * @version 1.0. $Revision: 7583 $, $Date: 2007-06-18 18:19:03 +0200 (Mo, 18 Jun 2007) $ 083 * 084 * @since 2.0 085 */ 086 087 public class GetCoverage extends WCSRequestBase { 088 089 private static final long serialVersionUID = 44735033754048955L; 090 091 private static final NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); 092 093 private String sourceCoverage = null; 094 095 private DomainSubset domainSubset = null; 096 097 private RangeSubset rangeSubset = null; 098 099 private InterpolationMethod interpolationMethod = null; 100 101 private Output output = null; 102 103 /** 104 * @param id 105 * @param version 106 * @param sourceCoverage 107 * @param domainSubset 108 * @param output 109 * @throws WCSException 110 * @throws OGCWebServiceException 111 */ 112 public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, Output output ) 113 throws WCSException, OGCWebServiceException { 114 this( id, version, sourceCoverage, domainSubset, null, null, output ); 115 } 116 117 /** 118 * @param id 119 * @param version 120 * @param sourceCoverage 121 * @param domainSubset 122 * @param interpolationMethod 123 * @param output 124 * @throws WCSException 125 * @throws OGCWebServiceException 126 */ 127 public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, 128 InterpolationMethod interpolationMethod, Output output ) throws WCSException, 129 OGCWebServiceException { 130 this( id, version, sourceCoverage, domainSubset, null, interpolationMethod, output ); 131 } 132 133 /** 134 * @param id 135 * @param version 136 * @param sourceCoverage 137 * @param domainSubset 138 * @param rangeSubset 139 * @param output 140 * @throws WCSException 141 * @throws OGCWebServiceException 142 */ 143 public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, 144 RangeSubset rangeSubset, Output output ) throws WCSException, OGCWebServiceException { 145 this( id, version, sourceCoverage, domainSubset, rangeSubset, null, output ); 146 } 147 148 /** 149 * @param id 150 * @param version 151 * @param sourceCoverage 152 * @param domainSubset 153 * @param rangeSubset 154 * @param interpolationMethod 155 * @param output 156 * @throws WCSException 157 * @throws OGCWebServiceException 158 */ 159 public GetCoverage( String id, String version, String sourceCoverage, DomainSubset domainSubset, 160 RangeSubset rangeSubset, InterpolationMethod interpolationMethod, Output output ) 161 throws WCSException, OGCWebServiceException { 162 super( id, version ); 163 if ( sourceCoverage == null || sourceCoverage.length() == 0 ) { 164 throw new WCSException( "sourceCoverage must be a valid string with length > 0" ); 165 } 166 if ( domainSubset == null ) { 167 throw new WCSException( "domainSubset must be <> null in GetCoverage" ); 168 } 169 if ( output == null ) { 170 throw new WCSException( "output must be <> null in GetCoverage" ); 171 } 172 this.sourceCoverage = sourceCoverage; 173 this.domainSubset = domainSubset; 174 this.rangeSubset = rangeSubset; 175 this.interpolationMethod = interpolationMethod; 176 this.output = output; 177 } 178 179 /** 180 * creates a GetCoverage request from its KVP representation 181 * 182 * @param id 183 * unique ID of the request 184 * @param kvp 185 * request 186 * @return created <tt>GetCoverage</tt> 187 * @throws OGCWebServiceException 188 * will be thrown if something general is wrong 189 * @throws WCSException 190 * will be thrown if a WCS/GetCoverage specific part of the request is erroreous 191 */ 192 public static GetCoverage create( String id, String kvp ) 193 throws OGCWebServiceException, WCSException { 194 Map<String, String> map = KVP2Map.toMap( kvp ); 195 map.put( "ID", id ); 196 return create( map ); 197 } 198 199 /** 200 * creates a GetCoverage request from its KVP representation 201 * 202 * @param map 203 * request 204 * @return created <tt>GetCoverage</tt> 205 * @throws OGCWebServiceException 206 * will be thrown if something general is wrong 207 * @throws MissingParameterValueException 208 * @throws InvalidParameterValueException 209 * @throws WCSException 210 * will be thrown if a WCS/GetCoverage specific part of the request is erroreous 211 */ 212 public static GetCoverage create( Map<String, String> map ) 213 throws OGCWebServiceException, MissingParameterValueException, 214 InvalidParameterValueException { 215 216 String version = map.remove( "VERSION" ); 217 if ( version == null ) { 218 throw new MissingParameterValueException( "WCS", "'version' must be set" ); 219 } 220 if ( !"1.0.0".equals( version ) ) { 221 ExceptionCode ecode = ExceptionCode.INVALIDPARAMETERVALUE; 222 throw new InvalidParameterValueException( "WCS", "'version' must be 1.0.0", ecode ); 223 } 224 String coverage = map.remove( "COVERAGE" ); 225 String crs = map.remove( "CRS" ); 226 if ( crs == null ) { 227 ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; 228 throw new MissingParameterValueException( "WCS", "'crs' is missing", code ); 229 } 230 String response_crs = map.remove( "RESPONSE_CRS" ); 231 if ( response_crs == null ) { 232 response_crs = crs; 233 } 234 String format = map.remove( "FORMAT" ); 235 Output output = createOutput( response_crs, null, format, null ); 236 SpatialSubset sps = createSpatialSubset( map, crs ); 237 238 String time = map.remove( "TIME" ); 239 TimeSequence temporalSubset = null; 240 if ( time != null ) { 241 temporalSubset = new TimeSequence( time ); 242 } 243 244 Code code = new Code( crs, null ); 245 DomainSubset domainSubset = new DomainSubset( code, sps, temporalSubset ); 246 247 String except = map.remove( "EXCEPTIONS" ); 248 if ( except == null ) { 249 except = "application/vnd.ogc.se_xml"; 250 } else if ( !except.equals( "application/vnd.ogc.se_xml" ) ) { 251 ExceptionCode ecode = ExceptionCode.INVALIDPARAMETERVALUE; 252 throw new InvalidParameterValueException( "WCS", "exceptions != application/vnd.ogc.se_xml", ecode ); 253 } 254 String id = map.remove( "ID" ); 255 256 GetCoverage gc = new GetCoverage( id, version, coverage, domainSubset, null, null, output ); 257 gc.validate(); 258 return gc; 259 } 260 261 /** 262 * creates a GetCoverage request from its XML representation 263 * 264 * @param id 265 * unique ID of the request 266 * @param doc 267 * XML representation of the request 268 * @return created <tt>DescribeCoverage</tt> 269 * @throws OGCWebServiceException 270 * will be thrown if something general is wrong 271 * @throws WCSException 272 * will be thrown if a WCS/GetCoverage specific part of the request is erroreous 273 */ 274 public static GetCoverage create( String id, Document doc ) 275 throws OGCWebServiceException, WCSException { 276 277 GetCoverage gc = null; 278 try { 279 280 String version = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/@version", nsContext, null ); 281 if ( version == null ) { 282 throw new MissingParameterValueException( "WCS", "'version' must be set" ); 283 } 284 if ( !"1.0.0".equals( version ) ) { 285 ExceptionCode ecode = ExceptionCode.INVALIDPARAMETERVALUE; 286 throw new InvalidParameterValueException( "WCS", "'version' must be 1.0.0", ecode ); 287 } 288 289 String coverage = XMLTools.getRequiredNodeAsString( doc, "/wcs:GetCoverage/wcs:sourceCoverage", nsContext ); 290 String interpol = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/wcs:interpolationMethod", nsContext, 291 null ); 292 InterpolationMethod interpolMeth = null; 293 if ( interpol == null || "nearest neighbor".equals( interpol ) ) { 294 interpolMeth = new InterpolationMethod( "nearest neighbor" ); 295 } 296 String path = "/wcs:GetCoverage/wcs:domainSubset/wcs:spatialSubset"; 297 List nl = XMLTools.getNodes( doc, path, nsContext ); 298 SpatialSubset sp = null; 299 if ( nl.size() > 0 ) { 300 Node node = (Node) nl.get( 0 ); 301 sp = createSpatialSubset( (Element) node ); 302 } else { 303 // TODO 304 // temporal subset 305 } 306 // TODO 307 // path = "/wcs:GetCoverage/wcs:rangeSubset/wcs:axisSubset"; 308 // nl = XMLTools.getXPath(path, doc, nsContext); 309 // evaluate possible ranges; e.g.time, extent 310 String format = XMLTools.getRequiredNodeAsString( doc, "/wcs:GetCoverage/wcs:output/wcs:format", nsContext ); 311 // use crs defined for the requested envelope if no CRS is defined 312 // in the request 313 String crsName = "EPSG:4326"; 314 if ( sp.getEnvelope().getCoordinateSystem() != null ) { 315 crsName = sp.getEnvelope().getCoordinateSystem().getName(); 316 } 317 String crs = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/wcs:output/wcs:crs", nsContext, crsName ); 318 319 String ipm = XMLTools.getNodeAsString( doc, "/wcs:GetCoverage/wcs:interpolationMethod", nsContext, null ); 320 if ( ipm != null && !ipm.equals( "nearest neighbor" ) ) { 321 throw new InvalidParameterValueException( "interpolationMethod must " 322 + "have the value 'nearest neighbor'" ); 323 } 324 325 Output output = createOutput( crs, null, format, null ); 326 DomainSubset domainSubset = new DomainSubset( new Code( crsName ), sp ); 327 328 gc = new GetCoverage( id, version, coverage, domainSubset, null, interpolMeth, output ); 329 } catch ( Exception e ) { 330 ExceptionCode code = ExceptionCode.INVALID_FORMAT; 331 throw new WCSException( "WCS", StringTools.stackTraceToString( e ), code ); 332 } 333 334 gc.validate(); 335 return gc; 336 } 337 338 /** 339 * @param element 340 * @return a new Spatial subset 341 * @throws WCSException 342 */ 343 private static SpatialSubset createSpatialSubset( Element element ) 344 throws WCSException { 345 SpatialSubset sp = null; 346 try { 347 List nl = XMLTools.getNodes( element, "gml:Envelope", nsContext ); 348 Envelope env = GMLDocument.parseEnvelope( (Element) nl.get( 0 ) ); 349 nl = XMLTools.getNodes( element, "gml:Grid", nsContext ); 350 Grid grid = GMLDocument.parseGrid( (Element) nl.get( 0 ) ); 351 sp = new SpatialSubset( env, grid.getGridEnvelope() ); 352 } catch ( Exception e ) { 353 ExceptionCode code = ExceptionCode.INVALID_FORMAT; 354 throw new WCSException( "WCS", StringTools.stackTraceToString( e ), code ); 355 } 356 return sp; 357 } 358 359 /** 360 * @param map 361 * @param crs 362 * @return a new SpatialSubset with given crs 363 * @throws WCSException 364 */ 365 public static final SpatialSubset createSpatialSubset( Map map, String crs ) 366 throws WCSException { 367 Envelope envelope = createEnvelope( map, crs ); 368 369 int width = (int) getNumber( (String) map.remove( "WIDTH" ), "WIDTH" ); 370 int height = (int) getNumber( (String) map.remove( "HEIGHT" ), "HEIGHT" ); 371 int depth = (int) getNumber( (String) map.remove( "DEPTH" ), "DEPTH" ); 372 373 double resx = getNumber( (String) map.remove( "RESX" ), "RESX" ); 374 double resy = getNumber( (String) map.remove( "RESY" ), "RESY" ); 375 double resz = getNumber( (String) map.remove( "RESZ" ), "RESZ" ); 376 377 Position low = null; 378 Position high = null; 379 if ( width > 0 && height > 0 ) { 380 if ( depth > 0 ) { 381 low = GeometryFactory.createPosition( 0, 0, 0 ); 382 high = GeometryFactory.createPosition( width-1, height-1, depth ); 383 } else { 384 low = GeometryFactory.createPosition( 0, 0 ); 385 high = GeometryFactory.createPosition( width-1, height-1 ); 386 } 387 } else if ( resx > 0 && resy > 0 ) { 388 if ( resz > 0 ) { 389 ExceptionCode code = ExceptionCode.INVALIDPARAMETERVALUE; 390 throw new WCSException( "WCS", "resz is not supported yet", code ); 391 } 392 width = (int) Math.round( envelope.getWidth() / resx ); 393 height = (int) Math.round( envelope.getHeight() / resy ); 394 low = GeometryFactory.createPosition( 0, 0 ); 395 high = GeometryFactory.createPosition( width, height ); 396 } else { 397 ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; 398 throw new WCSException( "WCS", "width/height or resx/resy must be set", code ); 399 } 400 401 Envelope grid = GeometryFactory.createEnvelope( low, high, null ); 402 403 return new SpatialSubset( envelope, grid ); 404 405 } 406 407 /** 408 * @param map 409 * @return an envelope. 410 * @throws WCSException 411 */ 412 private static Envelope createEnvelope( Map map, String crs ) 413 throws WCSException { 414 String tmp = (String) map.remove( "BBOX" ); 415 double[] bbox = null; 416 if ( tmp != null ) { 417 try { 418 bbox = StringTools.toArrayDouble( tmp, "," ); 419 } catch ( Exception e ) { 420 ExceptionCode code = ExceptionCode.INVALIDPARAMETERVALUE; 421 throw new WCSException( "WCS", "can't read BBOX", code ); 422 } 423 424 Position min = null; 425 Position max = null; 426 if ( bbox.length == 4 ) { 427 min = GeometryFactory.createPosition( bbox[0], bbox[1] ); 428 max = GeometryFactory.createPosition( bbox[2], bbox[3] ); 429 } else { 430 min = GeometryFactory.createPosition( bbox[0], bbox[1], bbox[2] ); 431 max = GeometryFactory.createPosition( bbox[3], bbox[4], bbox[5] ); 432 } 433 CoordinateSystem srs; 434 try { 435 srs = CRSFactory.create( crs ); 436 } catch ( UnknownCRSException e ) { 437 throw new WCSException( GetCoverage.class.getName(), e.getMessage() ); 438 } 439 return GeometryFactory.createEnvelope( min, max, srs ); 440 } 441 return null; 442 443 } 444 445 /** 446 * creates an <tt>Output</tt> object for a GetCoverage request 447 * 448 * @param response_crs 449 * @param crsNS 450 * @param format 451 * @param formatNS 452 * @return an Output 453 * @throws WCSException 454 * will be thrown if the response_crs prefix isn't a valid URI 455 */ 456 public static final Output createOutput( String response_crs, String crsNS, String format, String formatNS ) 457 throws WCSException { 458 URI crsURI = null; 459 if ( crsNS != null ) { 460 try { 461 crsURI = new URI( crsNS ); 462 } catch ( Exception e ) { 463 throw new WCSException( "invalid response crs namespace: " + crsNS ); 464 } 465 } 466 467 URI formatURI = null; 468 if ( formatNS != null ) { 469 try { 470 formatURI = new URI( formatNS ); 471 } catch ( Exception e ) { 472 throw new WCSException( "invalid response crs namespace: " + formatNS ); 473 } 474 } 475 476 Code crs = new Code( response_crs, crsURI ); 477 Code cformat = new Code( format, formatURI ); 478 return new Output( crs, cformat ); 479 } 480 481 /** 482 * @param val 483 * @param name 484 * @return a Number 485 * @throws WCSException 486 */ 487 private static double getNumber( String val, String name ) 488 throws WCSException { 489 if ( val == null ) 490 return -1; 491 double d = -1; 492 try { 493 d = Double.parseDouble( val ); 494 } catch ( Exception e ) { 495 ExceptionCode code = ExceptionCode.INVALIDPARAMETERVALUE; 496 throw new WCSException( "WCS", name + " isn't a valid number format", code ); 497 } 498 return d; 499 } 500 501 /** 502 * @return Returns the domainSubset. 503 */ 504 public DomainSubset getDomainSubset() { 505 return domainSubset; 506 } 507 508 /** 509 * @return Returns the interpolationMethod. 510 */ 511 public InterpolationMethod getInterpolationMethod() { 512 return interpolationMethod; 513 } 514 515 /** 516 * @return Returns the output. 517 */ 518 public Output getOutput() { 519 return output; 520 } 521 522 /** 523 * @return Returns the rangeSubset. 524 */ 525 public RangeSubset getRangeSubset() { 526 return rangeSubset; 527 } 528 529 /** 530 * @return Returns the sourceCoverage. 531 * 532 */ 533 public String getSourceCoverage() { 534 return sourceCoverage; 535 } 536 537 /** 538 * @throws WCSException 539 */ 540 protected void validate() 541 throws WCSException { 542 543 if ( getVersion() == null ) { 544 ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; 545 throw new WCSException( "WCS", "'version' is missing", code ); 546 } 547 548 if ( getSourceCoverage() == null ) { 549 ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; 550 throw new WCSException( "WCS", "'coverage' is missing", code ); 551 } 552 553 DomainSubset ds = getDomainSubset(); 554 if ( ds.getRequestSRS() == null ) { 555 ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; 556 throw new WCSException( "WCS", "'crs' is missing", code ); 557 } 558 559 if ( ds.getSpatialSubset() == null && ds.getTemporalSubset() == null ) { 560 ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; 561 throw new WCSException( "WCS", "either temporal subset or spatial " + "subset must be defined", code ); 562 } 563 564 if ( getOutput().getFormat() == null ) { 565 ExceptionCode code = ExceptionCode.MISSINGPARAMETERVALUE; 566 throw new WCSException( "WCS", "'format' is missing", code ); 567 } 568 569 } 570 571 @Override 572 public String toString() { 573 String response = super.toString(); 574 response += "\nOutput: " + output; 575 response += "\ndomainSubset: " + domainSubset; 576 response += "\nsourceCoverage: " + sourceCoverage; 577 response += "\ninterpolationMethod: " + interpolationMethod; 578 return response; 579 } 580 581 }