001    /*----------------    FILE HEADER  ------------------------------------------
002    
003     This file is part of deegree.
004     Copyright (C) 2001-2007 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        private static final ILogger LOGGER = LoggerFactory.getLogger( Get3DFeatureInfo.class );
075    
076        private GetView getViewRequestCopy = null;
077    
078        private Point clickPoint = null;
079    
080        private Rectangle queryBox = null;
081    
082        private float apexAngle;
083    
084        private int radius;
085    
086        private float depth;
087    
088        private String exceptions = null;
089    
090        private String infoFormat;
091    
092        private List<String> queryDatasets = null;
093    
094        private int featureCount = 0;
095    
096        private boolean parent;
097    
098        /**
099         * creates a <tt>WPVSFeatureInfoRequest</tt> from a <tt>HashMap</tt> that contains the
100         * request parameters as key-value-pairs.
101         * 
102         * @param param
103         *            <tt>HashMap</tt> containing the request parameters
104         * @return an instance of <tt>WPVSFeatureInfoRequest</tt>
105         * @throws OGCWebServiceException
106         */
107        public static Get3DFeatureInfo create(Map<String, String> param) throws OGCWebServiceException {
108                    
109                    LOGGER.entering();
110                    
111                    // VERSION
112                    String version = param.get( "VERSION" ); //$NON-NLS-1$
113                    if ( version == null ) {
114                            throw new InconsistentRequestException( 
115                                            Messages.getMessage( "WPVS_INVALID_VERSION" ) );    //$NON-NLS-1$
116                    }
117                    
118                    // ID
119            String id = param.get( "ID" ); //$NON-NLS-1$
120            if ( id == null ) {
121                throw new InconsistentRequestException(
122                        Messages.getMessage( "WPVS_MISSING_ID" ) ); //$NON-NLS-1$
123            }
124            
125            // <view_request_copy>
126            GetView getViewRequestCopy = null;
127            try {
128                getViewRequestCopy = GetView.create( param );
129            } catch( Exception ex ) {
130                throw new InconsistentRequestException( 
131                            Messages.getMessage( "WPVS_EXCEPTION_GETVIEWREQUESTCOPY" ) //$NON-NLS-1$
132                                            + ex.getMessage() );
133            }
134            
135            // APEXANGLE
136            float apexAngle;
137            if ( param.get( "AA" ) != null ) {
138                    try {
139                            apexAngle = (float)Math.toRadians( Float.parseFloat( param.remove( "AA" ).trim() ) );
140                    } catch ( NumberFormatException nfe ) {
141                        throw new InvalidParameterValueException( 
142                                    Messages.getMessage( "WPVS_INVALID_APEXANGLE" ) );
143                }
144                if ( apexAngle < 0 ) {
145                    throw new InvalidParameterValueException( 
146                                    Messages.getMessage( "WPVS_INVALID_APEXANGLE_LESS_0" ) );
147                }
148            } else {
149                    apexAngle = 0;
150            }
151            
152            // I, J
153            Point clickPoint = null;
154            if ( ( param.get( "I" ) != null ) && ( param.get( "J" ) != null ) ) { //$NON-NLS-1$ //$NON-NLS-2$
155                try {
156                    int i = Integer.parseInt( param.remove( "I" ) ); //$NON-NLS-1$
157                    int j = Integer.parseInt( param.remove( "J" ) ); //$NON-NLS-1$
158                    clickPoint = new java.awt.Point( i, j );
159                } catch ( NumberFormatException nfe ) {
160                    LOGGER.logError( nfe.getLocalizedMessage(), nfe );
161                    throw new OGCWebServiceException( 
162                                    "Get3DFeatureInfo", Messages.getMessage( "WPVS_INVALID_POINT" ), //$NON-NLS-1$ //$NON-NLS-2$
163                            ExceptionCode.INVALID_POINT );
164                }
165            }
166            
167            // QUERYBOX
168            Rectangle queryBox = null;
169            if ( param.get( "QUERYBOX" ) != null ) {
170                    String[] tokens = param.remove( "QUERYBOX" ).split( "," ); //$NON-NLS-1$
171                    if ( tokens.length != 4 ) {
172                            throw new InconsistentRequestException( 
173                                            Messages.getMessage( "WPVS_INVALID_QUERYBOX" )); //$NON-NLS-1$
174                    }
175                    int minx;
176                    int maxx;
177                    int miny;
178                    int maxy;
179                    try {
180                            minx = Integer.parseInt(tokens[0]);
181                            maxx = Integer.parseInt(tokens[1]);
182                            miny = Integer.parseInt(tokens[2]);
183                            maxy = Integer.parseInt(tokens[3]);
184                    } catch ( NumberFormatException e ) {
185                        throw new InconsistentRequestException( 
186                                    Messages.getMessage( "WPVS_ILLEGAL_QUERYBOX" )  //$NON-NLS-1$
187                                                                            + e.getMessage() );
188                    }
189                    if ( minx >= maxx ) {
190                       throw new InvalidParameterValueException( 
191                                       Messages.getMessage( "WPVS_INVALID_MINX_MAXX" ) ); //$NON-NLS-1$
192                    }
193                    if ( miny >= maxy ) {
194                       throw new InvalidParameterValueException( 
195                                       Messages.getMessage( "WPVS_INVALID_MINY_MAXY" ) ); //$NON-NLS-1$
196                    }
197                    queryBox = new Rectangle( minx, maxx, miny, maxy );
198            }
199            
200            // RADIUS
201            int radius = 0;
202            if ( param.get( "RADIUS" ) != null ) {
203                    try {
204                            radius = Integer.parseInt( param.remove( "RADIUS" ).trim() ) ;
205                    } catch ( NumberFormatException nfe ) {
206                         throw new InvalidParameterValueException( 
207                                     Messages.getMessage( "WPVS_INVALID_RADIUS" ) );
208                }
209                if ( radius < 0 ) {
210                    throw new InvalidParameterValueException( 
211                                    Messages.getMessage( "WPVS_INVALID_RADIUS_LESS_0" ) );
212                }
213            } 
214            
215            // I,J or QUERYBOX?
216            if ( clickPoint == null && queryBox == null ) {
217                    throw new InvalidParameterValueException( 
218                                    Messages.getMessage( "WPVS_INVALID_QUERYTYPE" ) ); //$NON-NLS-1$
219            }
220            
221            // DEPTH
222            float depth = 0;
223            if (  param.get("DEPTH" ) != null ) {
224                    try {
225                            depth = Float.parseFloat( param.remove("DEPTH" ).trim() );
226                    } catch ( NumberFormatException nfe ) {
227                            throw new InvalidParameterValueException( 
228                                            Messages.getMessage( "WPVS_INVALID_DEPTH" ) ); 
229                    }
230                    if ( depth < 0 ){
231                            throw new InvalidParameterValueException( 
232                                            Messages.getMessage( "WPVS_INVALID_DEPTH_LESS_0" ) );
233                    }
234            }
235                    
236            // EXCEPTIONS (default=application/vnd.ogc.se_xml)
237            String exceptions = param.remove( "EXCEPTIONS" ); //$NON-NLS-1$
238            if ( exceptions == null ) {
239                exceptions = "application/vnd.ogc.se_xml"; //$NON-NLS-1$
240            }
241    
242            // INFO_FORMAT (mime-type)
243            String infoFormat = param.remove( "INFO_FORMAT" ); //$NON-NLS-1$
244            if ( infoFormat == null ) {
245                infoFormat = "application/vnd.ogc.gml"; //$NON-NLS-1$
246            }
247    
248            // QUERY_LAYERS
249            List<String> queryDatasets = null;
250            if ( param.get( "QUERY_DATASETS" ) != null ) {
251                StringTokenizer st = new StringTokenizer( param.remove( "QUERY_DATASETS" ), "," ); //$NON-NLS-1$
252                queryDatasets = new ArrayList<String>( st.countTokens() );
253                while ( st.hasMoreTokens() ) {
254                    queryDatasets.add( st.nextToken() );
255                }
256            } else {
257                throw new InconsistentRequestException( 
258                            Messages.getMessage( "WPVS_INVALID_QUERYLAYERS" ) ); //$NON-NLS-1$
259            }
260            
261            // FEATURE_COUNT
262            int featureCount = 1 ;
263            if ( param.get( "FEATURE_COUNT" ) != null ) {
264                    try {
265                            featureCount = Integer.parseInt( param.remove( "FEATURE_COUNT" ) );
266                    } catch ( NumberFormatException nfe ) {
267                            throw new InvalidParameterValueException( 
268                                            Messages.getMessage( "WPVS_INVALID_FEATURE_COUNT" ) ); 
269                    }
270                    if ( featureCount < 0 ) {
271                    throw new InvalidParameterValueException( 
272                                    Messages.getMessage( "WPVS_INVALID_FEATURE_COUNT_LESS_0" ) );
273                }
274            }
275            
276            // PARENT
277            boolean parent = true;
278            if ( param.get("PARENT") != null ) {
279                    if ( param.get("PARENT").toUpperCase().trim().equals( "FALSE" ) ) {
280                            parent = false;
281                    } else if ( !param.remove("PARENT").toUpperCase().trim().equals( "TRUE" ) ){
282                            throw new InvalidParameterValueException( 
283                                    Messages.getMessage( "WPVS_INVALID_PARENT_NOT_BOOLEAN" ) );
284                    }
285            }
286            
287            // VendorSpecificParameter; because all defined parameters has been
288            // removed from the model the vendorSpecificParameters are what left
289            Map<String, String> vendorSpecificParameter = param;
290    
291            LOGGER.exiting();
292    
293            return new Get3DFeatureInfo( version, id, vendorSpecificParameter, getViewRequestCopy, 
294                                                                     clickPoint, queryBox, apexAngle, radius, depth, infoFormat, 
295                                                                     exceptions, queryDatasets, parent, featureCount );
296             
297        }
298    
299        /**
300         * creates a new WPVSFeatureInfoRequest_Impl object
301         * 
302         * @param version
303         * @param id
304         * @param vendorSpecificParameter
305         * @param getViewRequestCopy
306         * @param clickPoint
307         * @param queryBox
308         * @param aa
309         * @param depth
310         * @param queryLayers
311         * @param infoFormat
312         * @param exceptions
313         */
314    
315        private Get3DFeatureInfo( String version, String id, Map<String, String> vendorSpecificParameter,
316                                  GetView getViewRequestCopy, Point clickPoint, Rectangle queryBox, float apexAngle,
317                                  int radius, float depth, String infoFormat, String exceptions,
318                                  List<String> queryDatasets, boolean parent, int featureCount ) {
319    
320            super( version, id, vendorSpecificParameter );
321            this.getViewRequestCopy = getViewRequestCopy;
322            this.clickPoint = clickPoint;
323            this.queryBox = queryBox;
324            this.apexAngle = apexAngle;
325            this.radius = radius;
326            this.depth = depth;
327            this.infoFormat = infoFormat;
328            this.exceptions = exceptions;
329            this.queryDatasets = queryDatasets;
330            this.parent = parent;
331            this.featureCount = featureCount;
332        }
333    
334        public String getServiceName() {
335            return "WPVS"; //$NON-NLS-1$
336        }
337    
338        /**
339         * The AA Parameter indicates the apex angle of a request with a cone
340         * 
341         * @return the apex angle
342         */
343        public float getApexAngle() {
344            return apexAngle;
345        }
346    
347        /**
348         * The I and J parameters indicate a point of interest on the map. Used by the request with a
349         * line or cone. The origin is set to (0,0) centered in the pixel at the upper left corner; I
350         * increases to the right and J increases downward. I and J are returned as java.awt.Point
351         * class/datastructure.
352         * 
353         * @return the point of interest
354         */
355        public Point getClickPoint() {
356            return clickPoint;
357        }
358    
359        /**
360         * This optional parameter indicates the depth of a query
361         * 
362         * @return the depth
363         */
364        public float getDepth() {
365            return depth;
366        }
367    
368        /**
369         * The optional EXCEPTIONS parameter states the manner in which errors are to be reported to the
370         * client. The default value is application/vnd.ogc.se_xml if this parameter is absent from the
371         * request.
372         * 
373         * @return the exception format
374         */
375        public String getExceptions() {
376            return exceptions;
377        }
378    
379        /**
380         * <view request copy> is not a name/value pair like the other parameters. Instead, most of the
381         * GetView request parameters that generated the original map are repeated. Two are omitted
382         * because Get3DFeatureInfo provides its own values: VERSION and REQUEST. The remainder of the
383         * GetView request shall be embedded contiguously in the Get3DFeatureInfo request.
384         * 
385         * @return a copy of the original request
386         */
387        public GetView getGetViewRequestCopy() {
388            return getViewRequestCopy;
389        }
390    
391        /**
392         * The optional INFO_FORMAT indicates what format to use when returning the feature information.
393         * Supported values for a Get3DFeatureInfo request on a WPVS instance are listed as MIME types
394         * in one or more <Format>elements inside the <Request><FeatureInfo>element of its Capabilities
395         * XML. The entire MIME type string in <Format>is used as the value of the INFO_FORMAT
396         * parameter. In an HTTP environment, the MIME type shall be set on the returned object using
397         * the Content-type entity header.
398         * <p>
399         * </p>
400         * <b>EXAMPLE: </b> <tt> The parameter INFO_FORMAT=application/vnd.ogc.gml
401         * requests that the feature information be formatted in Geography Markup
402         * Language (GML).</tt>
403         * 
404         * @return the format
405         */
406        public String getInfoFormat() {
407            return infoFormat;
408        }
409    
410        /**
411         * The required QUERY_LAYERS parameter states the map layer(s) from which feature information is
412         * desired to be retrieved. Its value is a comma- separated list of one or more map layers that
413         * are returned as an array. This parameter shall contain at least one layer name, but may
414         * contain fewer layers than the original GetView request.
415         * <p>
416         * </p>
417         * If any layer in this list is not contained in the Capabilities XML of the WPVS, the results
418         * are undefined and the WPVS shall produce an exception response.
419         * 
420         * @return the layer names
421         */
422        public List<String> getQueryDatasets() {
423            return queryDatasets;
424        }
425    
426        public boolean getParent() {
427            return parent;
428        }
429    
430        public int getFeatureCount() {
431            return featureCount;
432        }
433    
434        /**
435         * The parameter QueryBox indicates the rectangle for the Request with a pyramid
436         * 
437         * @return the queryBox
438         */
439        public Rectangle getQueryBox() {
440            return queryBox;
441        }
442    
443        public int getRadius() {
444            return radius;
445        }
446    
447    }