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-2006 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.IGeoTransformer;
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.ogcbase.ExceptionCode;
062    import org.deegree.ogcwebservices.CurrentUpdateSequenceException;
063    import org.deegree.ogcwebservices.InvalidParameterValueException;
064    import org.deegree.ogcwebservices.InvalidUpdateSequenceException;
065    import org.deegree.ogcwebservices.LonLatEnvelope;
066    import org.deegree.ogcwebservices.OGCWebServiceException;
067    import org.deegree.ogcwebservices.OGCWebServiceRequest;
068    import org.deegree.ogcwebservices.SupportedFormats;
069    import org.deegree.ogcwebservices.wcs.CoverageOfferingBrief;
070    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageDescription;
071    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering;
072    import org.deegree.ogcwebservices.wcs.describecoverage.DescribeCoverage;
073    import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage;
074    
075    /**
076     * @version $Revision: 6259 $
077     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
078     * @author last edited by: $Author: bezema $
079     * 
080     * @version 1.0. $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $
081     * 
082     * @since 2.0
083     */
084    public class WCSRequestValidator {
085        
086        private static final ILogger LOG = LoggerFactory.getLogger( WCSRequestValidator.class );
087    
088        /**
089         * validates the passed <tt>AbstractOGCWebServiceRequest</tt> which must
090         * be a request that is known by a WCS against the passed
091         * <tt>WCSCapabilities</tt>
092         * 
093         * @param capabilities
094         * @param request
095         * @throws CurrentUpdateSequenceException
096         * @throws InvalidUpdateSequenceException
097         * @throws OGCWebServiceException 
098         */
099        public static void validate(WCSCapabilities capabilities,
100                                        OGCWebServiceRequest request)
101                                        throws CurrentUpdateSequenceException,
102                                        InvalidUpdateSequenceException, OGCWebServiceException {        
103            // schmitz: since we only support one version, we can actually just ignore
104            // the attribute (at least for GetCapabilities requests). I do not think
105            // it does any harm to remove it completely.
106    
107    //        if ( !request.getVersion().equals(capabilities.getVersion() )) {
108    //            throw new InvalidParameterValueException(request.getVersion() + " is not " +
109    //                    "a valid version for requesting this WCS");
110    //        }
111    
112            if (request instanceof WCSGetCapabilities) {
113                validate(capabilities, (WCSGetCapabilities) request);
114            } else if (request instanceof GetCoverage) {
115                validate( capabilities, (GetCoverage)request );
116            } else if (request instanceof DescribeCoverage) {
117                validate(capabilities, (DescribeCoverage) request);
118            } else {
119                throw new OGCWebServiceException("Invalid request type: " + request);
120            }
121        }
122    
123        /**
124         * validates the passed <tt>WCSGetCapabilities</tt> against the passed
125         * <tt>WCSCapabilities</tt>
126         * 
127         * @param capabilities
128         * @param request
129         * @throws CurrentUpdateSequenceException
130         * @throws InvalidUpdateSequenceException
131         */
132        private static void validate(WCSCapabilities capabilities,
133                WCSGetCapabilities request) throws CurrentUpdateSequenceException,
134                InvalidUpdateSequenceException {
135            String rUp = request.getUpdateSequence();
136            String cUp = capabilities.getUpdateSequence();
137    
138            if ((rUp != null) && (cUp != null) && (rUp.compareTo(cUp) == 0)) {
139                ExceptionCode code = ExceptionCode.CURRENT_UPDATE_SEQUENCE;
140                throw new CurrentUpdateSequenceException("WCS GetCapabilities",
141                        "request update sequence: " + rUp
142                                + "is equal to capabilities" + " update sequence "
143                                + cUp, code);
144            }
145    
146            if ((rUp != null) && (cUp != null) && (rUp.compareTo(cUp) > 0)) {
147                ExceptionCode code = ExceptionCode.INVALID_UPDATESEQUENCE;
148                throw new InvalidUpdateSequenceException("WCS GetCapabilities",
149                        "request update sequence: " + rUp + " is higher then the "
150                                + "capabilities update sequence " + cUp, code);
151            }
152        }
153    
154        /**
155         * validates the passed <tt>DescribeCoverage</tt> against the passed
156         * <tt>WCSCapabilities</tt>
157         * 
158         * @param capabilities
159         * @param request
160         * @throws InvalidParameterValueException
161         */
162        private static void validate(WCSCapabilities capabilities,
163                DescribeCoverage request) throws InvalidParameterValueException {
164            String[] coverages = request.getCoverages();
165            if (coverages != null) {
166                ContentMetadata cm = capabilities.getContentMetadata();
167                for (int i = 0; i < coverages.length; i++) {
168                    if (cm.getCoverageOfferingBrief(coverages[i]) == null) { 
169                        throw new InvalidParameterValueException(
170                            "Coverage: " + coverages[i] + "is not known by the WCS"); }
171                }
172            }
173        }
174    
175        /**
176         * validates the passed <tt>GetCoverage</tt> against the passed
177         * <tt>WCSCapabilities</tt>
178         * 
179         * @param capabilities
180         * @param request
181         * @throws InvalidParameterValueException
182         */
183        private static void validate(WCSCapabilities capabilities,
184                GetCoverage request) throws InvalidParameterValueException {
185            String coverage = request.getSourceCoverage();
186            ContentMetadata cm = capabilities.getContentMetadata();
187            // is coverage known by the WCS?
188            CoverageOfferingBrief cob = cm.getCoverageOfferingBrief(coverage);
189            if (cob == null) { throw new InvalidParameterValueException(
190                    "Coverage: " + coverage + " is not known by the WCS"); }
191    
192            URL url = cob.getConfiguration();
193            CoverageDescription cd = null;
194            try {
195                cd = CoverageDescription.createCoverageDescription(url);
196            } catch (Exception e) {
197                LOG.logError( e.getMessage(), e );
198                throw new InvalidParameterValueException( e.getMessage() );
199            }
200            CoverageOffering co = cd.getCoverageOffering(coverage);
201            if (co == null ) {
202                throw new InvalidParameterValueException("no coverage descrition " +
203                        "available for requested coverage: " + coverage);
204            }
205            // validate requested format
206            String format = request.getOutput().getFormat().getCode();
207            SupportedFormats sf = co.getSupportedFormats();
208            CodeList[] codeList = sf.getFormats();        
209            if (!validate(codeList, null, format)) { 
210                throw new InvalidParameterValueException( "requested format: " + format
211                            + " is not known by the WCS for coverage:" + coverage); }
212            // validate requested response CRS
213            String crs = request.getOutput().getCrs().getCode();
214            URI codeSpace = request.getOutput().getCrs().getCodeSpace();        
215            String space = null;
216            if ( codeSpace != null ) {
217                    space = codeSpace.toString(); 
218            }
219    
220            CodeList[] rrcrs = co.getSupportedCRSs().getRequestResponseSRSs();
221            CodeList[] rescrs = co.getSupportedCRSs().getResponseSRSs();        
222            if (!validate(rrcrs, space, crs) && !validate(rescrs, space, crs)) { 
223                throw new InvalidParameterValueException(
224                    "requested response CRS: " + crs
225                            + " is not known by the WCS " + "for coverage:"
226                            + coverage); }
227            // validate requested CRS
228            crs = request.getDomainSubset().getRequestSRS().getCode();
229            codeSpace = request.getDomainSubset().getRequestSRS().getCodeSpace();
230            if ( codeSpace != null ) {
231                    space = codeSpace.toString(); 
232            }
233            CodeList[] reqcrs = co.getSupportedCRSs().getRequestSRSs();
234            
235            if (!validate(rrcrs, space, crs) && !validate(reqcrs, space, crs)) { 
236                    throw new InvalidParameterValueException(
237                    "requested request CRS: " + crs
238                            + " is not known by the WCS for coverage:" + coverage); }
239            // validate requested envelope
240            Envelope envelope = request.getDomainSubset().getSpatialSubset().getEnvelope();
241            LonLatEnvelope llEnv = cob.getLonLatEnvelope();
242    
243            try {
244                if ( !intersects(envelope, request.getDomainSubset().getRequestSRS(), llEnv) ) { 
245                    throw new InvalidParameterValueException(
246                        "requested BBOX: doesn't intersect "
247                                + " the area of the requested coverage: "
248                                + coverage); 
249                }
250            } catch ( UnknownCRSException e ) {
251                throw new InvalidParameterValueException( e );
252            }
253            
254        }
255    
256        /**
257         * @return true if the passed <tt>CodeList</tt> s contains the also passed
258         * codeSpace-value combination. Otherwise false will be returned
259         * 
260         * @param codeList
261         * @param codeSpace
262         * @param value
263         */
264        private static boolean validate(CodeList[] codeList, String codeSpace,
265                String value) {
266            for (int i = 0; i < codeList.length; i++) {                  
267                if (codeList[i].validate(codeSpace, value)) { return true; }            
268            }
269            return false;
270        }
271    
272        private static boolean intersects(Envelope envelope, Code reqCRS,
273                                                              LonLatEnvelope llEnv) throws UnknownCRSException {
274            Envelope latlonEnv = 
275                    GeometryFactory.createEnvelope(llEnv.getMin().getX(), 
276                                                                               llEnv.getMin().getY(), 
277                                                                                       llEnv.getMax().getX(), 
278                                                                                       llEnv.getMax().getY(),
279                                               CRSFactory.create("EPSG:4326") );
280            try {
281                if ( !"EPSG:4326".equals( reqCRS.getCode() ) ) {
282                    IGeoTransformer gt = new GeoTransformer("EPSG:4326");
283                    String crs = reqCRS.getCode();
284                    envelope = gt.transform(envelope, crs );
285                }
286            } catch (Exception e) {
287                e.printStackTrace();
288                return false;
289            }
290            return envelope.intersects(latlonEnv);
291        }
292    
293    }/* ********************************************************************
294    Changes to this class. What the people have been up to:
295    $Log$
296    Revision 1.18  2007/01/24 17:23:47  schmitz
297    Fixed versioning for WCS compliance.
298    
299    Revision 1.17  2006/11/27 09:07:52  poth
300    JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code.
301    
302    Revision 1.16  2006/11/23 09:23:43  bezema
303    added a EPSG:4326 to the longlatenvellope
304    
305    Revision 1.15  2006/09/27 16:46:41  poth
306    transformation method signature changed
307    
308    Revision 1.14  2006/08/07 13:37:59  poth
309    bug fix - checking for intersection between requested box and a coverages envelope
310    
311    Revision 1.13  2006/07/28 08:01:27  schmitz
312    Updated the WMS for 1.1.1 compliance.
313    Fixed some documentation.
314    
315    Revision 1.12  2006/07/12 14:46:19  poth
316    comment footer added
317    
318    ********************************************************************** */