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