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 }