    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    }