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