001 // $HeadURL: 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 and 009 grit GmbH 010 http://www.grit.de 011 012 This library is free software; you can redistribute it and/or modify it under 013 the terms of the GNU Lesser General Public License as published by the Free 014 Software Foundation; either version 2.1 of the License, or (at your option) 015 any later version. 016 This library is distributed in the hope that it will be useful, but WITHOUT 017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 018 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 019 details. 020 You should have received a copy of the GNU Lesser General Public License 021 along with this library; if not, write to the Free Software Foundation, Inc., 022 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 023 024 Contact information: 025 026 lat/lon GmbH 027 Aennchenstr. 19, 53177 Bonn 028 Germany 029 http://lat-lon.de/ 030 031 Department of Geography, University of Bonn 032 Prof. Dr. Klaus Greve 033 Postfach 1147, 53001 Bonn 034 Germany 035 http://www.geographie.uni-bonn.de/deegree/ 036 037 e-mail: info@deegree.org 038 ----------------------------------------------------------------------------*/ 039 package org.deegree.ogcwebservices.wcs.getcapabilities; 040 041 import java.net.URI; 042 import java.net.URL; 043 044 import org.deegree.crs.exceptions.CRSException; 045 import org.deegree.datatypes.Code; 046 import org.deegree.datatypes.CodeList; 047 import org.deegree.framework.log.ILogger; 048 import org.deegree.framework.log.LoggerFactory; 049 import org.deegree.model.crs.CRSFactory; 050 import org.deegree.model.crs.CRSTransformationException; 051 import org.deegree.model.crs.GeoTransformer; 052 import org.deegree.model.crs.UnknownCRSException; 053 import org.deegree.model.spatialschema.Envelope; 054 import org.deegree.model.spatialschema.GeometryException; 055 import org.deegree.model.spatialschema.GeometryFactory; 056 import org.deegree.model.spatialschema.Surface; 057 import org.deegree.ogcbase.ExceptionCode; 058 import org.deegree.ogcwebservices.CurrentUpdateSequenceException; 059 import org.deegree.ogcwebservices.InvalidParameterValueException; 060 import org.deegree.ogcwebservices.InvalidUpdateSequenceException; 061 import org.deegree.ogcwebservices.LonLatEnvelope; 062 import org.deegree.ogcwebservices.OGCWebServiceException; 063 import org.deegree.ogcwebservices.OGCWebServiceRequest; 064 import org.deegree.ogcwebservices.SupportedFormats; 065 import org.deegree.ogcwebservices.wcs.CoverageOfferingBrief; 066 import org.deegree.ogcwebservices.wcs.describecoverage.CoverageDescription; 067 import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering; 068 import org.deegree.ogcwebservices.wcs.describecoverage.DescribeCoverage; 069 import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage; 070 071 /** 072 * @version $Revision: 20437 $ 073 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> 074 * @author <a href="mailto:reichhelm@grit.de">Stephan Reichhelm</a> 075 * @author last edited by: $Author: apoth $ 076 * 077 * @version 1.0. $Revision: 20437 $, $Date: 2009-10-29 09:49:03 +0100 (Do, 29 Okt 2009) $ 078 * 079 * @since 2.0 080 */ 081 public class WCSRequestValidator { 082 083 private static final ILogger LOG = LoggerFactory.getLogger( WCSRequestValidator.class ); 084 085 /** 086 * validates the passed <tt>AbstractOGCWebServiceRequest</tt> which must be a request that is known by a WCS against 087 * the passed <tt>WCSCapabilities</tt> 088 * 089 * @param capabilities 090 * @param request 091 * @throws CurrentUpdateSequenceException 092 * @throws InvalidUpdateSequenceException 093 * @throws OGCWebServiceException 094 */ 095 public static void validate( WCSCapabilities capabilities, OGCWebServiceRequest request ) 096 throws CurrentUpdateSequenceException, InvalidUpdateSequenceException, 097 OGCWebServiceException { 098 // schmitz: since we only support one version, we can actually just ignore 099 // the attribute (at least for GetCapabilities requests). I do not think 100 // it does any harm to remove it completely. 101 102 // if ( !request.getVersion().equals(capabilities.getVersion() )) { 103 // throw new InvalidParameterValueException(request.getVersion() + " is not " + 104 // "a valid version for requesting this WCS"); 105 // } 106 107 if ( request instanceof WCSGetCapabilities ) { 108 validate( capabilities, (WCSGetCapabilities) request ); 109 } else if ( request instanceof GetCoverage ) { 110 validate( capabilities, (GetCoverage) request ); 111 } else if ( request instanceof DescribeCoverage ) { 112 validate( capabilities, (DescribeCoverage) request ); 113 } else { 114 throw new OGCWebServiceException( "Invalid request type: " + request ); 115 } 116 } 117 118 /** 119 * validates the passed <tt>WCSGetCapabilities</tt> against the passed <tt>WCSCapabilities</tt> 120 * 121 * @param capabilities 122 * @param request 123 * @throws CurrentUpdateSequenceException 124 * @throws InvalidUpdateSequenceException 125 */ 126 private static void validate( WCSCapabilities capabilities, WCSGetCapabilities request ) 127 throws CurrentUpdateSequenceException, InvalidUpdateSequenceException { 128 String rUp = request.getUpdateSequence(); 129 String cUp = capabilities.getUpdateSequence(); 130 131 if ( ( rUp != null ) && ( cUp != null ) && ( rUp.compareTo( cUp ) == 0 ) ) { 132 ExceptionCode code = ExceptionCode.CURRENT_UPDATE_SEQUENCE; 133 throw new CurrentUpdateSequenceException( "WCS GetCapabilities", "request update sequence: " + rUp 134 + "is equal to capabilities" 135 + " update sequence " + cUp, code ); 136 } 137 138 if ( ( rUp != null ) && ( cUp != null ) && ( rUp.compareTo( cUp ) > 0 ) ) { 139 ExceptionCode code = ExceptionCode.INVALID_UPDATESEQUENCE; 140 throw new InvalidUpdateSequenceException( "WCS GetCapabilities", "request update sequence: " + rUp 141 + " is higher then the " 142 + "capabilities update sequence " + cUp, 143 code ); 144 } 145 } 146 147 /** 148 * validates the passed <tt>DescribeCoverage</tt> against the passed <tt>WCSCapabilities</tt> 149 * 150 * @param capabilities 151 * @param request 152 * @throws InvalidParameterValueException 153 */ 154 private static void validate( WCSCapabilities capabilities, DescribeCoverage request ) 155 throws InvalidParameterValueException { 156 String[] coverages = request.getCoverages(); 157 if ( coverages != null ) { 158 ContentMetadata cm = capabilities.getContentMetadata(); 159 for ( int i = 0; i < coverages.length; i++ ) { 160 if ( cm.getCoverageOfferingBrief( coverages[i] ) == null ) { 161 throw new InvalidParameterValueException( "Coverage: " + coverages[i] + "is not known by the WCS" ); 162 } 163 } 164 } 165 } 166 167 /** 168 * validates the passed <tt>GetCoverage</tt> against the passed <tt>WCSCapabilities</tt> 169 * 170 * @param capabilities 171 * @param request 172 * @throws InvalidParameterValueException 173 */ 174 private static void validate( WCSCapabilities capabilities, GetCoverage request ) 175 throws InvalidParameterValueException { 176 String coverage = request.getSourceCoverage(); 177 ContentMetadata cm = capabilities.getContentMetadata(); 178 // is coverage known by the WCS? 179 CoverageOfferingBrief cob = cm.getCoverageOfferingBrief( coverage ); 180 if ( cob == null ) { 181 throw new InvalidParameterValueException( "Coverage: " + coverage + " is not known by the WCS" ); 182 } 183 184 URL url = cob.getConfiguration(); 185 CoverageDescription cd = null; 186 try { 187 cd = CoverageDescription.createCoverageDescription( url ); 188 } catch ( Exception e ) { 189 LOG.logError( e.getMessage(), e ); 190 throw new InvalidParameterValueException( e.getMessage() ); 191 } 192 CoverageOffering co = cd.getCoverageOffering( coverage ); 193 if ( co == null ) { 194 throw new InvalidParameterValueException( "no coverage descrition " + "available for requested coverage: " 195 + coverage ); 196 } 197 // validate requested format 198 String format = request.getOutput().getFormat().getCode(); 199 SupportedFormats sf = co.getSupportedFormats(); 200 CodeList[] codeList = sf.getFormats(); 201 if ( !validate( codeList, null, format ) ) { 202 throw new InvalidParameterValueException( "requested format: " + format 203 + " is not known by the WCS for coverage:" + coverage ); 204 } 205 // validate requested response CRS 206 String crs = request.getOutput().getCrs().getCode(); 207 URI codeSpace = request.getOutput().getCrs().getCodeSpace(); 208 String space = null; 209 if ( codeSpace != null ) { 210 space = codeSpace.toString(); 211 } 212 213 CodeList[] rrcrs = co.getSupportedCRSs().getRequestResponseSRSs(); 214 CodeList[] rescrs = co.getSupportedCRSs().getResponseSRSs(); 215 if ( !validate( rrcrs, space, crs ) && !validate( rescrs, space, crs ) ) { 216 throw new InvalidParameterValueException( "requested response CRS: " + crs + " is not known by the WCS " 217 + "for coverage:" + coverage ); 218 } 219 // validate requested CRS 220 crs = request.getDomainSubset().getRequestSRS().getCode(); 221 codeSpace = request.getDomainSubset().getRequestSRS().getCodeSpace(); 222 if ( codeSpace != null ) { 223 space = codeSpace.toString(); 224 } 225 CodeList[] reqcrs = co.getSupportedCRSs().getRequestSRSs(); 226 227 if ( !validate( rrcrs, space, crs ) && !validate( reqcrs, space, crs ) ) { 228 throw new InvalidParameterValueException( "requested request CRS: " + crs 229 + " is not known by the WCS for coverage:" + coverage ); 230 } 231 // validate requested envelope 232 Envelope envelope = request.getDomainSubset().getSpatialSubset().getEnvelope(); 233 LonLatEnvelope llEnv = cob.getLonLatEnvelope(); 234 Envelope[] domEnvs = co.getDomainSet().getSpatialDomain().getEnvelops(); 235 236 try { 237 if ( !intersects( envelope, request.getDomainSubset().getRequestSRS(), domEnvs, llEnv ) ) { 238 throw new InvalidParameterValueException( "requested BBOX: doesn't intersect " 239 + " the area of the requested coverage: " + coverage ); 240 } 241 } catch ( UnknownCRSException e ) { 242 throw new InvalidParameterValueException( e ); 243 } 244 245 } 246 247 /** 248 * @return true if the passed <tt>CodeList</tt> s contains the also passed codeSpace-value combination. Otherwise 249 * false will be returned 250 * 251 * @param codeList 252 * @param codeSpace 253 * @param value 254 */ 255 private static boolean validate( CodeList[] codeList, String codeSpace, String value ) { 256 for ( int i = 0; i < codeList.length; i++ ) { 257 if ( codeList[i].validate( codeSpace, value ) ) { 258 return true; 259 } 260 } 261 return false; 262 } 263 264 private static boolean intersects( Envelope envelope, Code reqCRS, Envelope[] envs, LonLatEnvelope llEnv ) 265 throws UnknownCRSException { 266 267 boolean res = false; 268 String reqCRSCode = reqCRS.getCode(); 269 270 try { 271 if ( envs == null || envs.length == 0 ) { 272 Envelope latlonEnv = GeometryFactory.createEnvelope( llEnv.getMin().getX(), llEnv.getMin().getY(), 273 llEnv.getMax().getX(), llEnv.getMax().getY(), 274 CRSFactory.create( "EPSG:4326" ) ); 275 276 if ( !"EPSG:4326".equals( reqCRSCode ) ) { 277 res = intersects( envelope, reqCRSCode, latlonEnv, "EPSG:4326" ); 278 } else { 279 res = envelope.intersects( latlonEnv ); 280 } 281 } else { 282 for ( int i = 0; i < envs.length && !res; i++ ) { 283 if ( intersects( envelope, reqCRSCode, envs[i], envs[i].getCoordinateSystem().getPrefixedName() ) ) { 284 res = true; 285 break; 286 } 287 } 288 } 289 } catch ( GeometryException ex ) { 290 LOG.logWarning( "intersection test; translation into surface failed", ex ); 291 } catch ( CRSException ex ) { 292 LOG.logWarning( "intersection test; transformation of reqeust envelope/valid area impossible", ex ); 293 } catch ( CRSTransformationException ex ) { 294 LOG.logWarning( "intersection test; transformation of reqeust envelope/valid area failed", ex ); 295 } 296 return res; 297 } 298 299 private static boolean intersects( Envelope requestEnv, String requestCrs, Envelope regionEnv, String regionCrs ) 300 throws CRSException, GeometryException, CRSTransformationException, UnknownCRSException { 301 Surface request = GeometryFactory.createSurface( requestEnv, CRSFactory.create( requestCrs ) ); 302 Surface region = GeometryFactory.createSurface( regionEnv, CRSFactory.create( regionCrs ) ); 303 304 if ( !requestCrs.equalsIgnoreCase( regionCrs ) ) { 305 GeoTransformer gt = new GeoTransformer( requestCrs ); 306 region = (Surface) gt.transform( region ); 307 } 308 309 return request.intersects( region ); 310 } 311 312 }