    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/security/owsrequestvalidator/wms/GetMapRequestValidator.java $
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036    package org.deegree.security.owsrequestvalidator.wms;
    037
    038    import static org.deegree.security.drm.model.RightType.GETMAP;
    039
    040    import java.net.URL;
    041    import java.util.ArrayList;
    042    import java.util.HashMap;
    043    import java.util.List;
    044    import java.util.Map;
    045
    046    import org.deegree.datatypes.QualifiedName;
    047    import org.deegree.datatypes.Types;
    048    import org.deegree.framework.log.ILogger;
    049    import org.deegree.framework.log.LoggerFactory;
    050    import org.deegree.framework.util.ColorUtils;
    051    import org.deegree.framework.util.MapUtils;
    052    import org.deegree.framework.util.StringTools;
    053    import org.deegree.framework.xml.XMLParsingException;
    054    import org.deegree.graphics.sld.AbstractStyle;
    055    import org.deegree.graphics.sld.NamedLayer;
    056    import org.deegree.graphics.sld.NamedStyle;
    057    import org.deegree.graphics.sld.SLDFactory;
    058    import org.deegree.graphics.sld.StyledLayerDescriptor;
    059    import org.deegree.model.crs.CRSFactory;
    060    import org.deegree.model.crs.CoordinateSystem;
    061    import org.deegree.model.crs.GeoTransformer;
    062    import org.deegree.model.feature.Feature;
    063    import org.deegree.model.feature.FeatureFactory;
    064    import org.deegree.model.feature.FeatureProperty;
    065    import org.deegree.model.feature.schema.FeatureType;
    066    import org.deegree.model.feature.schema.PropertyType;
    067    import org.deegree.model.spatialschema.Envelope;
    068    import org.deegree.model.spatialschema.GeometryFactory;
    069    import org.deegree.ogcwebservices.InvalidParameterValueException;
    070    import org.deegree.ogcwebservices.OGCWebServiceRequest;
    071    import org.deegree.ogcwebservices.wms.operation.GetMap;
    072    import org.deegree.security.UnauthorizedException;
    073    import org.deegree.security.drm.model.User;
    074    import org.deegree.security.owsproxy.Condition;
    075    import org.deegree.security.owsproxy.OperationParameter;
    076    import org.deegree.security.owsproxy.Request;
    077    import org.deegree.security.owsrequestvalidator.Messages;
    078    import org.deegree.security.owsrequestvalidator.Policy;
    079
    080    /**
    081     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
    082     * @author last edited by: $Author: mschneider $
    083     *
    084     * @version 1.1, $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    085     *
    086     * @since 1.1
    087     */
    088
    089    public class GetMapRequestValidator extends AbstractWMSRequestValidator {
    090
    091        private static final ILogger LOG = LoggerFactory.getLogger( GetMapRequestValidator.class );
    092
    093        // known condition parameter
    094        private static final String BBOX = "bbox";
    095
    096        private static final String LAYERS = "layers";
    097
    098        private static final String BGCOLOR = "bgcolor";
    099
    100        private static final String TRANSPARENCY = "transparency";
    101
    102        private static final String RESOLUTION = "resolution";
    103
    104        private static final String SLD = "sld";
    105
    106        private static final String INVALIDBBOX = Messages.getString( "GetMapRequestValidator.INVALIDBBOX" );
    107
    108        private static final String INVALIDLAYER = Messages.getString( "GetMapRequestValidator.INVALIDLAYER" );
    109
    110        private static final String INVALIDSTYLE = Messages.getString( "GetMapRequestValidator.INVALIDSTYLE" );
    111
    112        private static final String INVALIDBGCOLOR = Messages.getString( "GetMapRequestValidator.INVALIDBGCOLOR" );
    113
    114        private static final String INVALIDTRANSPARENCY = Messages.getString( "GetMapRequestValidator.INVALIDTRANSPARENCY" );
    115
    116        private static final String INVALIDRESOLUTION = Messages.getString( "GetMapRequestValidator.INVALIDRESOLUTION" );
    117
    118        private static final String INVALIDSLD = Messages.getString( "GetMapRequestValidator.INVALIDSLD" );
    119
    120        private static final String MISSINGCRS = Messages.getString( "GetMapRequestValidator.MISSINGCRS" );
    121
    122        private List<String> accessdRes = new ArrayList<String>();
    123
    124        private static FeatureType mapFT = null;
    125
    126        private GeoTransformer gt = null;
    127
    128        static {
    129            if ( mapFT == null ) {
    130                mapFT = GetMapRequestValidator.createFeatureType();
    131            }
    132        }
    133
    134        /**
    135         * @param policy
    136         */
    137        public GetMapRequestValidator( Policy policy ) {
    138            super( policy );
    139            try {
    140                gt = new GeoTransformer( "EPSG:4326" );
    141            } catch ( Exception e ) {
    142                e.printStackTrace();
    143            }
    144        }
    145
    146        /**
    147         * validates the incoming GetMap request against the policy assigned to a validator
    148         *
    149         * @param request
    150         *            request to validate
    151         * @param user
    152         *            name of the user who likes to perform the request (can be null)
    153         */
    154        @Override
    155        public void validateRequest( OGCWebServiceRequest request, User user )
    156                                throws InvalidParameterValueException, UnauthorizedException {
    157
    158            accessdRes.clear();
    159            userCoupled = false;
    160            Request req = policy.getRequest( "WMS", "GetMap" );
    161            // request is valid because no restrictions are made
    162            if ( req.isAny() || req.getPreConditions().isAny() ) {
    163                return;
    164            }
    165            Condition condition = req.getPreConditions();
    166
    167            GetMap wmsreq = (GetMap) request;
    168
    169            validateVersion( condition, wmsreq.getVersion() );
    170            Envelope env = wmsreq.getBoundingBox();
    171            try {
    172                env = gt.transform( env, wmsreq.getSrs() );
    173            } catch ( Exception e ) {
    174                throw new InvalidParameterValueException( "condition envelope isn't in the right CRS ", e );
    175            }
    176            validateBBOX( condition, env );
    177            validateLayers( condition, wmsreq.getLayers() );
    178            validateBGColor( condition, ColorUtils.toHexCode( "0x", wmsreq.getBGColor() ) );
    179            validateTransparency( condition, wmsreq.getTransparency() );
    180            validateExceptions( condition, wmsreq.getExceptions() );
    181            validateFormat( condition, wmsreq.getFormat() );
    182            validateMaxWidth( condition, wmsreq.getWidth() );
    183            validateMaxHeight( condition, wmsreq.getHeight() );
    184            validateResolution( condition, wmsreq );
    185            validateSLD( condition, wmsreq.getSLD_URL() );
    186            validateSLD_Body( condition, wmsreq.getStyledLayerDescriptor() );
    187
    188            if ( userCoupled ) {
    189                validateAgainstRightsDB( wmsreq, user );
    190            }
    191
    192        }
    193
    194        /**
    195         * checks if the passed envelope is valid against the maximum bounding box defined in the policy. If
    196         * <tt>user</ff> != <tt>null</tt> the maximu valid BBOX will be read from the user/rights repository
    197         *
    198         * @param condition
    199         *            condition containing the definition of the valid BBOX
    200         * @param envelope
    201         * @throws InvalidParameterValueException
    202         */
    203        private void validateBBOX( Condition condition, Envelope envelope )
    204                                throws InvalidParameterValueException {
    205
    206            OperationParameter op = condition.getOperationParameter( BBOX );
    207
    208            // version is valid because no restrictions are made
    209            if ( op.isAny() )
    210                return;
    211
    212            String v = op.getFirstAsString();
    213            String[] d = StringTools.toArray( v, ",", false );
    214            Envelope env = GeometryFactory.createEnvelope( Double.parseDouble( d[0] ), Double.parseDouble( d[1] ),
    215                                                           Double.parseDouble( d[2] ), Double.parseDouble( d[3] ), null );
    216
    217            try {
    218                env = gt.transform( env, d[4] );
    219            } catch ( Exception e ) {
    220                throw new InvalidParameterValueException( MISSINGCRS, e );
    221            }
    222
    223            if ( !env.contains( envelope ) ) {
    224                if ( !op.isUserCoupled() ) {
    225                    // if not user coupled the validation has failed
    226                    throw new InvalidParameterValueException( INVALIDBBOX + op.getFirstAsString() );
    227                }
    228                userCoupled = true;
    229                accessdRes.add( "BBOX: " + v );
    230            }
    231        }
    232
    233        /**
    234         * checks if the passed layres/styles are valid against the layers/styles list defined in the policy. If
    235         * <tt>user</ff> != <tt>null</tt> the valid layers/styles will be read from the user/rights repository
    236         *
    237         * @param condition
    238         *            condition containing the definition of the valid layers/styles
    239         * @param layers
    240         * @throws InvalidParameterValueException
    241         */
    242        private void validateLayers( Condition condition, GetMap.Layer[] layers )
    243                                throws InvalidParameterValueException {
    244
    245            OperationParameter op = condition.getOperationParameter( LAYERS );
    246
    247            // version is valid because no restrictions are made
    248            if ( op.isAny() ) {
    249                return;
    250            }
    251
    252            List<String> v = op.getValues();
    253            // seperate layers from assigned styles
    254            Map<String, String> map = new HashMap<String, String>();
    255            for ( int i = 0; i < v.size(); i++ ) {
    256                String[] tmp = StringTools.toArray( v.get( i ), "|", false );
    257                map.put( tmp[0], tmp[1] );
    258            }
    259
    260            for ( int i = 0; i < layers.length; i++ ) {
    261                String style = layers[i].getStyleName();
    262                String vs = map.get( layers[i].getName() );
    263                if ( vs == null ) {
    264                    if ( !op.isUserCoupled() ) {
    265                        throw new InvalidParameterValueException( INVALIDLAYER + layers[i].getName() );
    266                    }
    267                    accessdRes.add( "Layers: " + layers[i].getName() );
    268                    userCoupled = true;
    269                } else if ( !style.equalsIgnoreCase( "default" ) && vs.indexOf( "$any$" ) < 0 && vs.indexOf( style ) < 0 ) {
    270                    // a style is valid for a layer if it's the default style
    271                    // or the layer accepts any style or a style is explicit defined
    272                    // to be valid
    273                    if ( !op.isUserCoupled() ) {
    274                        throw new InvalidParameterValueException( INVALIDSTYLE + layers[i].getName() + ':' + style );
    275                    }
    276                    userCoupled = true;
    277                    accessdRes.add( "Styles: " + style );
    278                }
    279            }
    280
    281        }
    282
    283        /**
    284         * checks if the passed bgcolor is valid against the bgcolor(s) defined in the policy. If
    285         * <tt>user</ff> != <tt>null</tt> the valid bgcolors will be read from the user/rights repository
    286         *
    287         * @param condition
    288         *            condition containing the definition of the valid bgcolors
    289         * @param bgcolor
    290         * @throws InvalidParameterValueException
    291         */
    292        private void validateBGColor( Condition condition, String bgcolor )
    293                                throws InvalidParameterValueException {
    294
    295            OperationParameter op = condition.getOperationParameter( BGCOLOR );
    296
    297            // version is valid because no restrictions are made
    298            if ( op.isAny() )
    299                return;
    300
    301            List<String> list = op.getValues();
    302
    303            if ( !list.contains( bgcolor ) ) {
    304                if ( !op.isUserCoupled() ) {
    305                    throw new InvalidParameterValueException( INVALIDBGCOLOR + bgcolor );
    306                }
    307                accessdRes.add( "BGCOLOR" + bgcolor );
    308                userCoupled = true;
    309            }
    310
    311        }
    312
    313        /**
    314         * checks if the passed transparency is valid against the transparency defined in the policy. If
    315         * <tt>user</ff> != <tt>null</tt> the valid transparency will be read from the user/rights repository
    316         *
    317         * @param condition
    318         *            condition containing the definition of the valid transparency
    319         * @param transparency
    320         * @throws InvalidParameterValueException
    321         */
    322        private void validateTransparency( Condition condition, boolean transparency )
    323                                throws InvalidParameterValueException {
    324
    325            OperationParameter op = condition.getOperationParameter( TRANSPARENCY );
    326
    327            // version is valid because no restrictions are made
    328            if ( op.isAny() )
    329                return;
    330
    331            List<String> v = op.getValues();
    332            String s = "" + transparency;
    333            if ( !v.get( 0 ).equals( s ) && !v.get( v.size() - 1 ).equals( s ) ) {
    334                if ( !op.isUserCoupled() ) {
    335                    throw new InvalidParameterValueException( INVALIDTRANSPARENCY + transparency );
    336                }
    337                userCoupled = true;
    338                accessdRes.add( "Transparency: " + transparency );
    339            }
    340
    341        }
    342
    343        /**
    344         * checks if the requested map area/size is valid against the minimum resolution defined in the policy. If
    345         * <tt>user</ff> != <tt>null</tt> the valid resolution will be read from the user/rights repository
    346         *
    347         * @param condition
    348         *            condition containing the definition of the valid resolution
    349         * @throws InvalidParameterValueException
    350         */
    351        private void validateResolution( Condition condition, GetMap gmr )
    352                                throws InvalidParameterValueException {
    353
    354            OperationParameter op = condition.getOperationParameter( RESOLUTION );
    355
    356            // version is valid because no restrictions are made
    357            if ( op.isAny() )
    358                return;
    359
    360            double scale = 0;
    361            try {
    362                scale = calcScale( gmr );
    363            } catch ( Exception e ) {
    364                throw new InvalidParameterValueException( StringTools.stackTraceToString( e ) );
    365            }
    366            double compareRes = 0;
    367            compareRes = op.getFirstAsDouble();
    368            if ( scale < compareRes ) {
    369                if ( !op.isUserCoupled() ) {
    370                    throw new InvalidParameterValueException( INVALIDRESOLUTION + scale );
    371                }
    372                userCoupled = true;
    373                accessdRes.add( "resolution: " + scale );
    374            }
    375        }
    376
    377        /**
    378         * checks if the passed reference to a SLD document is valid against the defined in the policy. If
    379         * <tt>user</ff> != <tt>null</tt> the valid sld reference addresses will be read from the user/rights repository
    380         *
    381         * @param condition
    382         *            condition containing the definition of the valid sldRef
    383         * @param sldRef
    384         * @throws InvalidParameterValueException
    385         */
    386        private void validateSLD( Condition condition, URL sldRef )
    387                                throws InvalidParameterValueException {
    388
    389            OperationParameter op = condition.getOperationParameter( SLD );
    390            OperationParameter gmop = condition.getOperationParameter( LAYERS );
    391
    392            if ( op == null && sldRef != null ) {
    393                throw new InvalidParameterValueException( INVALIDSLD + sldRef );
    394            }
    395            // sldRef is valid because no restrictions are made
    396            if ( sldRef == null || op.isAny() ) {
    397                return;
    398            }
    399
    400            // validate reference base of the SLD
    401            List<String> list = op.getValues();
    402            String port = null;
    403            if ( sldRef.getPort() != -1 ) {
    404                port = ":" + sldRef.getPort();
    405            } else {
    406                port = ":80";
    407            }
    408            String addr = sldRef.getProtocol() + "://" + sldRef.getHost() + port;
    409            if ( !list.contains( addr ) ) {
    410                if ( !op.isUserCoupled() ) {
    411                    throw new InvalidParameterValueException( INVALIDSLD + sldRef );
    412                }
    413                userCoupled = true;
    414            }
    415
    416            // validate referenced dacument to be a valid SLD
    417            StyledLayerDescriptor sld = null;
    418            try {
    419                sld = SLDFactory.createSLD( sldRef );
    420            } catch ( XMLParsingException e ) {
    421                String s = org.deegree.i18n.Messages.getMessage( "WMS_SLD_IS_NOT_VALID", sldRef );
    422                throw new InvalidParameterValueException( s );
    423            }
    424
    425            // validate NamedLayers referenced by the SLD
    426            NamedLayer[] nl = sld.getNamedLayers();
    427            List<String> v = gmop.getValues();
    428            // seperate layers from assigned styles
    429            Map<String, String> map = new HashMap<String, String>();
    430            for ( int i = 0; i < v.size(); i++ ) {
    431                String[] tmp = StringTools.toArray( v.get( i ), "|", false );
    432                map.put( tmp[0], tmp[1] );
    433            }
    434            if ( !userCoupled ) {
    435                for ( int i = 0; i < nl.length; i++ ) {
    436                    AbstractStyle st = nl[i].getStyles()[0];
    437                    String style = null;
    438                    if ( st instanceof NamedStyle ) {
    439                        style = ( (NamedStyle) st ).getName();
    440                    } else {
    441                        // use default as name if a UserStyle is defined
    442                        // to ensure that the style will be accepted by
    443                        // the validator
    444                        style = "default";
    445                    }
    446                    String vs = map.get( nl[i].getName() );
    447                    if ( vs == null ) {
    448                        if ( !op.isUserCoupled() ) {
    449                            throw new InvalidParameterValueException( INVALIDLAYER + nl[i].getName() );
    450                        }
    451                        accessdRes.add( "Layers: " + nl[i].getName() );
    452                        userCoupled = true;
    453                    } else if ( !style.equalsIgnoreCase( "default" ) && vs.indexOf( "$any$" ) < 0
    454                                && vs.indexOf( style ) < 0 ) {
    455                        // a style is valid for a layer if it's the default style
    456                        // or the layer accepts any style or a style is explicit defined
    457                        // to be valid
    458                        if ( !op.isUserCoupled() ) {
    459                            throw new InvalidParameterValueException( INVALIDSTYLE + nl[i].getName() + ':' + style );
    460                        }
    461                        userCoupled = true;
    462                        accessdRes.add( "Styles: " + style );
    463                    }
    464                }
    465            }
    466
    467        }
    468
    469        /**
    470         * checks if the passed user is allowed to perform a GetMap request containing a SLD_BODY parameter.
    471         *
    472         * @param condition
    473         *            condition containing when SLD_BODY is valid or nots
    474         * @param sld_body
    475         */
    476        private void validateSLD_Body( Condition condition, StyledLayerDescriptor sld_body ) {
    477
    478            /*
    479             *
    480             * OperationParameter op = condition.getOperationParameter( SLD_BODY ); // version is valid because no
    481             * restrictions are made if ( sld_body == null ||op.isAny() ) return; // at the moment it is just evaluated if
    482             * the user is allowed // to perform a SLD request or not. no content validation will // be made boolean
    483             * isAllowed = false; if ( op.isUserCoupled() ) { //TODO // get comparator list from security registry } if
    484             * (!isAllowed ) { throw new InvalidParameterValueException( INVALIDSLD_BODY ); }
    485             */
    486        }
    487
    488        /**
    489         * validates the passed WMS GetMap request against a User- and Rights-Management DB.
    490         *
    491         * @param wmsreq
    492         * @param user
    493         * @throws InvalidParameterValueException
    494         */
    495        private void validateAgainstRightsDB( GetMap wmsreq, User user )
    496                                throws InvalidParameterValueException, UnauthorizedException {
    497
    498            if ( user == null ) {
    499                StringBuffer sb = new StringBuffer( 1000 );
    500                sb.append( ' ' );
    501                for ( int i = 0; i < accessdRes.size(); i++ ) {
    502                    sb.append( accessdRes.get( i ) ).append( "; " );
    503                }
    504                throw new UnauthorizedException( Messages.format( "RequestValidator.NOACCESS", sb ) );
    505            }
    506
    507            Double scale = null;
    508            try {
    509                scale = new Double( calcScale( wmsreq ) );
    510            } catch ( Exception e ) {
    511                throw new InvalidParameterValueException( e );
    512            }
    513
    514            // create feature that describes the map request
    515            FeatureProperty[] fps = new FeatureProperty[11];
    516            fps[0] = FeatureFactory.createFeatureProperty( new QualifiedName( "version" ), wmsreq.getVersion() );
    517            fps[1] = FeatureFactory.createFeatureProperty( new QualifiedName( "width" ), new Integer( wmsreq.getWidth() ) );
    518            fps[2] = FeatureFactory.createFeatureProperty( new QualifiedName( "height" ), new Integer( wmsreq.getHeight() ) );
    519            Envelope env = wmsreq.getBoundingBox();
    520            try {
    521                env = gt.transform( env, wmsreq.getSrs() );
    522            } catch ( Exception e ) {
    523                throw new InvalidParameterValueException( "A:condition envelope isn't in the right CRS ", e );
    524            }
    525            Object geom = null;
    526            try {
    527                geom = GeometryFactory.createSurface( env, null );
    528            } catch ( Exception e1 ) {
    529                e1.printStackTrace();
    530            }
    531            fps[3] = FeatureFactory.createFeatureProperty( new QualifiedName( "GEOM" ), geom );
    532            fps[4] = FeatureFactory.createFeatureProperty( new QualifiedName( "format" ), wmsreq.getFormat() );
    533            fps[5] = FeatureFactory.createFeatureProperty( new QualifiedName( "bgcolor" ),
    534                                                           ColorUtils.toHexCode( "0x", wmsreq.getBGColor() ) );
    535            fps[6] = FeatureFactory.createFeatureProperty( new QualifiedName( "transparent" ), ""
    536                                                                                               + wmsreq.getTransparency() );
    537            fps[7] = FeatureFactory.createFeatureProperty( new QualifiedName( "exceptions" ), wmsreq.getExceptions() );
    538            fps[8] = FeatureFactory.createFeatureProperty( new QualifiedName( "resolution" ), scale );
    539            fps[9] = FeatureFactory.createFeatureProperty( new QualifiedName( "sld" ), wmsreq.getSLD_URL() );
    540
    541            GetMap.Layer[] layers = wmsreq.getLayers();
    542            for ( int i = 0; i < layers.length; i++ ) {
    543                fps[10] = FeatureFactory.createFeatureProperty( new QualifiedName( "style" ), layers[i].getStyleName() );
    544                Feature feature = FeatureFactory.createFeature( "id", mapFT, fps );
    545
    546                if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
    547                    for ( int ii = 0; ii < fps.length; ii++ ) {
    548                        LOG.logDebug( "compared property: ", fps[ii] );
    549                    }
    550                }
    551
    552                if ( securityConfig.getProxiedUrl() == null ) {
    553                    handleUserCoupledRules( user, feature, layers[i].getName(), "Layer", GETMAP );
    554                } else {
    555                    handleUserCoupledRules( user, feature, "[" + securityConfig.getProxiedUrl() + "]:"
    556                                                           + layers[i].getName(), "Layer", GETMAP );
    557                }
    558            }
    559
    560        }
    561
    562        /**
    563         * calculates the map scale as defined in the OGC WMS 1.1.1 specifications
    564         *
    565         * @return scale of the map
    566         */
    567        private double calcScale( GetMap request )
    568                                throws Exception {
    569
    570            Envelope bbox = request.getBoundingBox();
    571
    572            CoordinateSystem crs = CRSFactory.create( request.getSrs() );
    573            return MapUtils.calcScale( request.getWidth(), request.getHeight(), bbox, crs, 1 );
    574            // would return scale denominator
    575            // return MapUtils.calcScale( request.getWidth(), request.getHeight(), bbox, crs, DEFAULT_PIXEL_SIZE );
    576        }
    577
    578        private static FeatureType createFeatureType() {
    579            PropertyType[] ftps = new PropertyType[11];
    580            ftps[0] = FeatureFactory.createSimplePropertyType( new QualifiedName( "version" ), Types.VARCHAR, false );
    581            ftps[1] = FeatureFactory.createSimplePropertyType( new QualifiedName( "width" ), Types.INTEGER, false );
    582            ftps[2] = FeatureFactory.createSimplePropertyType( new QualifiedName( "height" ), Types.INTEGER, false );
    583            ftps[3] = FeatureFactory.createSimplePropertyType( new QualifiedName( "GEOM" ), Types.GEOMETRY, false );
    584            ftps[4] = FeatureFactory.createSimplePropertyType( new QualifiedName( "format" ), Types.VARCHAR, false );
    585            ftps[5] = FeatureFactory.createSimplePropertyType( new QualifiedName( "bgcolor" ), Types.VARCHAR, false );
    586            ftps[6] = FeatureFactory.createSimplePropertyType( new QualifiedName( "transparent" ), Types.VARCHAR, false );
    587            ftps[7] = FeatureFactory.createSimplePropertyType( new QualifiedName( "exceptions" ), Types.VARCHAR, false );
    588            ftps[8] = FeatureFactory.createSimplePropertyType( new QualifiedName( "resolution" ), Types.DOUBLE, false );
    589            ftps[9] = FeatureFactory.createSimplePropertyType( new QualifiedName( "sld" ), Types.VARCHAR, false );
    590            ftps[10] = FeatureFactory.createSimplePropertyType( new QualifiedName( "style" ), Types.VARCHAR, false );
    591
    592            return FeatureFactory.createFeatureType( "GetMap", false, ftps );
    593        }
    594
    595    }