001    /*----------------------------------------------------------------------------
002     This file is part of deegree, http://deegree.org/
003     Copyright (C) 2001-2009 by:
004       Department of Geography, University of Bonn
005     and
006       lat/lon GmbH
007    
008     This library is free software; you can redistribute it and/or modify it under
009     the terms of the GNU Lesser General Public License as published by the Free
010     Software Foundation; either version 2.1 of the License, or (at your option)
011     any later version.
012     This library is distributed in the hope that it will be useful, but WITHOUT
013     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
014     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
015     details.
016     You should have received a copy of the GNU Lesser General Public License
017     along with this library; if not, write to the Free Software Foundation, Inc.,
018     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019    
020     Contact information:
021    
022     lat/lon GmbH
023     Aennchenstr. 19, 53177 Bonn
024     Germany
025     http://lat-lon.de/
026    
027     Department of Geography, University of Bonn
028     Prof. Dr. Klaus Greve
029     Postfach 1147, 53001 Bonn
030     Germany
031     http://www.geographie.uni-bonn.de/deegree/
032    
033     e-mail: info@deegree.org
034    ----------------------------------------------------------------------------*/
035    package org.deegree.ogcwebservices.wpvs.operation;
036    
037    import java.awt.Point;
038    import java.awt.Rectangle;
039    import java.util.ArrayList;
040    import java.util.List;
041    import java.util.Map;
042    import java.util.StringTokenizer;
043    
044    import org.deegree.framework.log.ILogger;
045    import org.deegree.framework.log.LoggerFactory;
046    import org.deegree.i18n.Messages;
047    import org.deegree.ogcbase.ExceptionCode;
048    import org.deegree.ogcwebservices.AbstractOGCWebServiceRequest;
049    import org.deegree.ogcwebservices.InconsistentRequestException;
050    import org.deegree.ogcwebservices.InvalidParameterValueException;
051    import org.deegree.ogcwebservices.OGCWebServiceException;
052    
053    /**
054     * This Class handles a kvp encoded Get3DFeatureInfo-request and stores it's values.
055     *
056     * @version $Revision: $
057     * @author <a href="mailto:cordes@lat-lon.de">Lyn Buesching</a>
058     * @author last edited by: $Author: $
059     *
060     * @version 1.0. $Revision: $, $Date: $
061     *
062     */
063    public class Get3DFeatureInfo extends AbstractOGCWebServiceRequest {
064    
065        /**
066         * the created serial id.
067         */
068        private static final long serialVersionUID = 4584807898848764192L;
069    
070        private static final ILogger LOGGER = LoggerFactory.getLogger( Get3DFeatureInfo.class );
071    
072        private GetView getViewRequestCopy = null;
073    
074        private Point clickPoint = null;
075    
076        private Rectangle queryBox = null;
077    
078        private float apexAngle;
079    
080        private int radius;
081    
082        private float depth;
083    
084        private String exceptions = null;
085    
086        private String infoFormat;
087    
088        private List<String> queryDatasets = null;
089    
090        private int featureCount = 0;
091    
092        private boolean parent;
093    
094        /**
095         * creates a <tt>WPVSFeatureInfoRequest</tt> from a <tt>HashMap</tt> that contains the
096         * request parameters as key-value-pairs.
097         *
098         * @param param
099         *            <tt>HashMap</tt> containing the request parameters
100         * @return an instance of <tt>WPVSFeatureInfoRequest</tt>
101         * @throws OGCWebServiceException
102         */
103        public static Get3DFeatureInfo create( Map<String, String> param )
104                                throws OGCWebServiceException {
105    
106            // VERSION
107            String version = param.get( "VERSION" ); //$NON-NLS-1$
108            if ( version == null ) {
109                throw new InconsistentRequestException( Messages.getMessage( "WPVS_INVALID_VERSION" ) ); //$NON-NLS-1$
110            }
111    
112            // ID
113            String id = param.get( "ID" ); //$NON-NLS-1$
114            if ( id == null ) {
115                throw new InconsistentRequestException( Messages.getMessage( "WPVS_MISSING_ID" ) ); //$NON-NLS-1$
116            }
117    
118            // <view_request_copy>
119            GetView getViewRequestCopy = null;
120            try {
121                getViewRequestCopy = GetView.create( param );
122            } catch ( Exception ex ) {
123                throw new InconsistentRequestException( Messages.getMessage( "WPVS_EXCEPTION_GETVIEWREQUESTCOPY" ) //$NON-NLS-1$
124                                                        + ex.getMessage() );
125            }
126    
127            // APEXANGLE
128            float apexAngle;
129            if ( param.get( "AA" ) != null ) {
130                try {
131                    apexAngle = (float) Math.toRadians( Float.parseFloat( param.remove( "AA" ).trim() ) );
132                } catch ( NumberFormatException nfe ) {
133                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_APEXANGLE" ) );
134                }
135                if ( apexAngle < 0 ) {
136                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_APEXANGLE_LESS_0" ) );
137                }
138            } else {
139                apexAngle = 0;
140            }
141    
142            // I, J
143            Point clickPoint = null;
144            if ( ( param.get( "I" ) != null ) && ( param.get( "J" ) != null ) ) { //$NON-NLS-1$ //$NON-NLS-2$
145                try {
146                    int i = Integer.parseInt( param.remove( "I" ) ); //$NON-NLS-1$
147                    int j = Integer.parseInt( param.remove( "J" ) ); //$NON-NLS-1$
148                    clickPoint = new java.awt.Point( i, j );
149                } catch ( NumberFormatException nfe ) {
150                    LOGGER.logError( nfe.getLocalizedMessage(), nfe );
151                    throw new OGCWebServiceException( "Get3DFeatureInfo", Messages.getMessage( "WPVS_INVALID_POINT" ), //$NON-NLS-1$ //$NON-NLS-2$
152                                                      ExceptionCode.INVALID_POINT );
153                }
154            }
155    
156            // QUERYBOX
157            Rectangle queryBox = null;
158            if ( param.get( "QUERYBOX" ) != null ) {
159                String[] tokens = param.remove( "QUERYBOX" ).split( "," ); //$NON-NLS-1$
160                if ( tokens.length != 4 ) {
161                    throw new InconsistentRequestException( Messages.getMessage( "WPVS_INVALID_QUERYBOX" ) ); //$NON-NLS-1$
162                }
163                int minx;
164                int maxx;
165                int miny;
166                int maxy;
167                try {
168                    minx = Integer.parseInt( tokens[0] );
169                    maxx = Integer.parseInt( tokens[1] );
170                    miny = Integer.parseInt( tokens[2] );
171                    maxy = Integer.parseInt( tokens[3] );
172                } catch ( NumberFormatException e ) {
173                    throw new InconsistentRequestException( Messages.getMessage( "WPVS_ILLEGAL_QUERYBOX" ) //$NON-NLS-1$
174                                                            + e.getMessage() );
175                }
176                if ( minx >= maxx ) {
177                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_MINX_MAXX" ) ); //$NON-NLS-1$
178                }
179                if ( miny >= maxy ) {
180                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_MINY_MAXY" ) ); //$NON-NLS-1$
181                }
182                queryBox = new Rectangle( minx, maxx, miny, maxy );
183            }
184    
185            // RADIUS
186            int radius = 0;
187            if ( param.get( "RADIUS" ) != null ) {
188                try {
189                    radius = Integer.parseInt( param.remove( "RADIUS" ).trim() );
190                } catch ( NumberFormatException nfe ) {
191                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_RADIUS" ) );
192                }
193                if ( radius < 0 ) {
194                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_RADIUS_LESS_0" ) );
195                }
196            }
197    
198            // I,J or QUERYBOX?
199            if ( clickPoint == null && queryBox == null ) {
200                throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_QUERYTYPE" ) ); //$NON-NLS-1$
201            }
202    
203            // DEPTH
204            float depth = 0;
205            if ( param.get( "DEPTH" ) != null ) {
206                try {
207                    depth = Float.parseFloat( param.remove( "DEPTH" ).trim() );
208                } catch ( NumberFormatException nfe ) {
209                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_DEPTH" ) );
210                }
211                if ( depth < 0 ) {
212                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_DEPTH_LESS_0" ) );
213                }
214            }
215    
216            // EXCEPTIONS (default=application/vnd.ogc.se_xml)
217            String exceptions = param.remove( "EXCEPTIONS" ); //$NON-NLS-1$
218            if ( exceptions == null ) {
219                exceptions = "application/vnd.ogc.se_xml"; //$NON-NLS-1$
220            }
221    
222            // INFO_FORMAT (mime-type)
223            String infoFormat = param.remove( "INFO_FORMAT" ); //$NON-NLS-1$
224            if ( infoFormat == null ) {
225                infoFormat = "application/vnd.ogc.gml"; //$NON-NLS-1$
226            }
227    
228            // QUERY_LAYERS
229            List<String> queryDatasets = null;
230            if ( param.get( "QUERY_DATASETS" ) != null ) {
231                StringTokenizer st = new StringTokenizer( param.remove( "QUERY_DATASETS" ), "," ); //$NON-NLS-1$
232                queryDatasets = new ArrayList<String>( st.countTokens() );
233                while ( st.hasMoreTokens() ) {
234                    queryDatasets.add( st.nextToken() );
235                }
236            } else {
237                throw new InconsistentRequestException( Messages.getMessage( "WPVS_INVALID_QUERYLAYERS" ) ); //$NON-NLS-1$
238            }
239    
240            // FEATURE_COUNT
241            int featureCount = 1;
242            if ( param.get( "FEATURE_COUNT" ) != null ) {
243                try {
244                    featureCount = Integer.parseInt( param.remove( "FEATURE_COUNT" ) );
245                } catch ( NumberFormatException nfe ) {
246                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_FEATURE_COUNT" ) );
247                }
248                if ( featureCount < 0 ) {
249                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_FEATURE_COUNT_LESS_0" ) );
250                }
251            }
252    
253            // PARENT
254            boolean parent = true;
255            if ( param.get( "PARENT" ) != null ) {
256                if ( param.get( "PARENT" ).toUpperCase().trim().equals( "FALSE" ) ) {
257                    parent = false;
258                } else if ( !param.remove( "PARENT" ).toUpperCase().trim().equals( "TRUE" ) ) {
259                    throw new InvalidParameterValueException( Messages.getMessage( "WPVS_INVALID_PARENT_NOT_BOOLEAN" ) );
260                }
261            }
262    
263            // VendorSpecificParameter; because all defined parameters has been
264            // removed from the model the vendorSpecificParameters are what left
265            Map<String, String> vendorSpecificParameter = param;
266    
267            return new Get3DFeatureInfo( version, id, vendorSpecificParameter, getViewRequestCopy, clickPoint, queryBox,
268                                         apexAngle, radius, depth, infoFormat, exceptions, queryDatasets, parent,
269                                         featureCount );
270    
271        }
272    
273        /**
274         * creates a new WPVSFeatureInfoRequest_Impl object
275         *
276         * @param version
277         * @param id
278         * @param vendorSpecificParameter
279         * @param getViewRequestCopy
280         * @param clickPoint
281         * @param queryBox
282         * @param radius
283         * @param depth
284         * @param infoFormat
285         * @param exceptions
286         * @param queryDatasets
287         * @param parent
288         * @param featureCount
289         */
290        private Get3DFeatureInfo( String version, String id, Map<String, String> vendorSpecificParameter,
291                                  GetView getViewRequestCopy, Point clickPoint, Rectangle queryBox, float apexAngle,
292                                  int radius, float depth, String infoFormat, String exceptions,
293                                  List<String> queryDatasets, boolean parent, int featureCount ) {
294    
295            super( version, id, vendorSpecificParameter );
296            this.getViewRequestCopy = getViewRequestCopy;
297            this.clickPoint = clickPoint;
298            this.queryBox = queryBox;
299            this.apexAngle = apexAngle;
300            this.radius = radius;
301            this.depth = depth;
302            this.infoFormat = infoFormat;
303            this.exceptions = exceptions;
304            this.queryDatasets = queryDatasets;
305            this.parent = parent;
306            this.featureCount = featureCount;
307        }
308    
309        public String getServiceName() {
310            return "WPVS"; //$NON-NLS-1$
311        }
312    
313        /**
314         * The AA Parameter indicates the apex angle of a request with a cone
315         *
316         * @return the apex angle
317         */
318        public float getApexAngle() {
319            return apexAngle;
320        }
321    
322        /**
323         * The I and J parameters indicate a point of interest on the map. Used by the request with a
324         * line or cone. The origin is set to (0,0) centered in the pixel at the upper left corner; I
325         * increases to the right and J increases downward. I and J are returned as java.awt.Point
326         * class/datastructure.
327         *
328         * @return the point of interest
329         */
330        public Point getClickPoint() {
331            return clickPoint;
332        }
333    
334        /**
335         * This optional parameter indicates the depth of a query
336         *
337         * @return the depth
338         */
339        public float getDepth() {
340            return depth;
341        }
342    
343        /**
344         * The optional EXCEPTIONS parameter states the manner in which errors are to be reported to the
345         * client. The default value is application/vnd.ogc.se_xml if this parameter is absent from the
346         * request.
347         *
348         * @return the exception format
349         */
350        public String getExceptions() {
351            return exceptions;
352        }
353    
354        /**
355         * <view request copy> is not a name/value pair like the other parameters. Instead, most of the
356         * GetView request parameters that generated the original map are repeated. Two are omitted
357         * because Get3DFeatureInfo provides its own values: VERSION and REQUEST. The remainder of the
358         * GetView request shall be embedded contiguously in the Get3DFeatureInfo request.
359         *
360         * @return a copy of the original request
361         */
362        public GetView getGetViewRequestCopy() {
363            return getViewRequestCopy;
364        }
365    
366        /**
367         * The optional INFO_FORMAT indicates what format to use when returning the feature information.
368         * Supported values for a Get3DFeatureInfo request on a WPVS instance are listed as MIME types
369         * in one or more <Format>elements inside the <Request><FeatureInfo>element of its Capabilities
370         * XML. The entire MIME type string in <Format>is used as the value of the INFO_FORMAT
371         * parameter. In an HTTP environment, the MIME type shall be set on the returned object using
372         * the Content-type entity header.
373         * <p>
374         * </p>
375         * <b>EXAMPLE: </b> <tt> The parameter INFO_FORMAT=application/vnd.ogc.gml
376         * requests that the feature information be formatted in Geography Markup
377         * Language (GML).</tt>
378         *
379         * @return the format
380         */
381        public String getInfoFormat() {
382            return infoFormat;
383        }
384    
385        /**
386         * The required QUERY_LAYERS parameter states the map layer(s) from which feature information is
387         * desired to be retrieved. Its value is a comma- separated list of one or more map layers that
388         * are returned as an array. This parameter shall contain at least one layer name, but may
389         * contain fewer layers than the original GetView request.
390         * <p>
391         * </p>
392         * If any layer in this list is not contained in the Capabilities XML of the WPVS, the results
393         * are undefined and the WPVS shall produce an exception response.
394         *
395         * @return the layer names
396         */
397        public List<String> getQueryDatasets() {
398            return queryDatasets;
399        }
400    
401        /**
402         * @return true if a parent is available.
403         */
404        public boolean getParent() {
405            return parent;
406        }
407    
408        /**
409         * @return the number of features.
410         */
411        public int getFeatureCount() {
412            return featureCount;
413        }
414    
415        /**
416         * The parameter QueryBox indicates the rectangle for the Request with a pyramid
417         *
418         * @return the queryBox
419         */
420        public Rectangle getQueryBox() {
421            return queryBox;
422        }
423    
424        /**
425         * @return the radius of a feature info request.
426         */
427        public int getRadius() {
428            return radius;
429        }
430    
431    }