    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/ogcwebservices/wms/operation/GetMap.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.ogcwebservices.wms.operation;
    037
    038    import static org.deegree.crs.components.Unit.DEGREE;
    039
    040    import java.awt.Color;
    041    import java.io.Serializable;
    042    import java.io.UnsupportedEncodingException;
    043    import java.net.MalformedURLException;
    044    import java.net.URL;
    045    import java.net.URLDecoder;
    046    import java.net.URLEncoder;
    047    import java.util.ArrayList;
    048    import java.util.Arrays;
    049    import java.util.HashMap;
    050    import java.util.Iterator;
    051    import java.util.LinkedList;
    052    import java.util.List;
    053    import java.util.Map;
    054    import java.util.StringTokenizer;
    055
    056    import org.deegree.datatypes.values.Values;
    057    import org.deegree.framework.log.ILogger;
    058    import org.deegree.framework.log.LoggerFactory;
    059    import org.deegree.framework.util.CharsetUtils;
    060    import org.deegree.framework.util.ColorUtils;
    061    import org.deegree.framework.util.IDGenerator;
    062    import org.deegree.framework.util.MimeTypeMapper;
    063    import org.deegree.framework.util.NetWorker;
    064    import org.deegree.framework.util.StringTools;
    065    import org.deegree.framework.xml.Marshallable;
    066    import org.deegree.framework.xml.NamespaceContext;
    067    import org.deegree.framework.xml.XMLFragment;
    068    import org.deegree.framework.xml.XMLParsingException;
    069    import org.deegree.framework.xml.XMLTools;
    070    import org.deegree.graphics.sld.SLDFactory;
    071    import org.deegree.graphics.sld.StyledLayerDescriptor;
    072    import org.deegree.i18n.Messages;
    073    import org.deegree.model.crs.CRSFactory;
    074    import org.deegree.model.crs.CoordinateSystem;
    075    import org.deegree.model.crs.UnknownCRSException;
    076    import org.deegree.model.spatialschema.Envelope;
    077    import org.deegree.model.spatialschema.GMLGeometryAdapter;
    078    import org.deegree.model.spatialschema.GeometryFactory;
    079    import org.deegree.ogcbase.CommonNamespaces;
    080    import org.deegree.ogcbase.InvalidGMLException;
    081    import org.deegree.ogcwebservices.InconsistentRequestException;
    082    import org.deegree.ogcwebservices.OGCWebServiceException;
    083    import org.deegree.ogcwebservices.wmps.operation.PrintMap;
    084    import org.deegree.ogcwebservices.wms.InvalidCRSException;
    085    import org.deegree.ogcwebservices.wms.InvalidFormatException;
    086    import org.deegree.ogcwebservices.wms.InvalidSRSException;
    087    import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
    088    import org.deegree.ogcwebservices.wms.configuration.RemoteWMSDataSource;
    089    import org.w3c.dom.Document;
    090    import org.w3c.dom.Element;
    091
    092    /**
    093     * This interface describes the access to the parameters of a GeMap request. It is excpected that there are two kinds of
    094     * request. The first is the 'normal' HTTP GET request with name-value-pair enconding and the second is a HTTP POST
    095     * request containing a SLD.
    096     * <p>
    097     * </p>
    098     * Even it is possible to access the values of a HTTP GET request throught their bean accessor methods the request shall
    099     * be mapped to a SLD data structure that is accessible using the <tt>getSLD()</tt>.
    100     *
    101     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    102     * @author last edited by: $Author:wanhoff$
    103     *
    104     * @version $Revision: 21363 $, $Date:20.03.2007$
    105     */
    106    public class GetMap extends WMSRequestBase {
    107
    108        private static final long serialVersionUID = 887256882709344021L;
    109
    110        private static final ILogger LOG = LoggerFactory.getLogger( GetMap.class );
    111
    112        private Values elevation = null;
    113
    114        private Values time = null;
    115
    116        private Map<String, Values> sampleDimension = null;
    117
    118        private List<Layer> layers = null;
    119
    120        private Color bGColor = null;
    121
    122        private Envelope boundingBox = null;
    123
    124        private String exceptions = null;
    125
    126        private String format = null;
    127
    128        private String srs = null;
    129
    130        private StyledLayerDescriptor sld = null;
    131
    132        private URL sLD_URL = null;
    133
    134        private URL wFS_URL = null;
    135
    136        private boolean transparency = false;
    137
    138        private int height = 0;
    139
    140        private int width = 0;
    141
    142        private DimensionValues dimTime;
    143
    144        private DimensionValues dimElev;
    145
    146        /**
    147         * A list to transport messages to the WMSHandler that need to be set in HTTP headers.
    148         */
    149        public LinkedList<String> warningHeaders = new LinkedList<String>();
    150
    151        /**
    152         * creates a <tt>WTSGetViewRequest</tt> from a set of parameters and builds up the complete SLD.
    153         *
    154         * @return an instance of <tt>GetMapRequest</tt>
    155         * @param version
    156         *            Request version.
    157         * @param layers
    158         *            list of one or more map layers. Optional if SLD parameter is present. Contains list of one rendering
    159         *            style per requested layer. Optional if SLD parameter is present.
    160         * @param elevation
    161         *            Elevation of layer desired.
    162         * @param sampleDimension
    163         *            Value of other dimensions as appropriate.
    164         * @param format
    165         *            Output format of map.
    166         * @param width
    167         *            Width in pixels of map picture.
    168         * @param height
    169         *            Height in pixels of map picture.
    170         * @param srs
    171         *            the requested Spatial Reference System.
    172         * @param boundingBox
    173         *            Bounding box corners (lower left, upper right) in SRS units.
    174         * @param transparency
    175         *            Background transparency of map.
    176         * @param bGColor
    177         *            Hexadecimal red-green-blue color value for the background color.
    178         * @param exceptions
    179         *            The format in which exceptions are to be reported by the WMS.
    180         * @param time
    181         *            Time value of layer desired
    182         * @param sld
    183         *            Styled Layer Descriptor
    184         * @param id
    185         *            an unique ID of the request
    186         * @param sldURL
    187         * @param vendorSpecificParameter
    188         *            Vendor Specific Parameter
    189         */
    190        public static GetMap create( String version, String id, Layer[] layers, Values elevation,
    191                                     Map<String, Values> sampleDimension, String format, int width, int height, String srs,
    192                                     Envelope boundingBox, boolean transparency, Color bGColor, String exceptions,
    193                                     Values time, URL sldURL, StyledLayerDescriptor sld,
    194                                     Map<String, String> vendorSpecificParameter ) {
    195            return new GetMap( version, id, layers, elevation, sampleDimension, format, width, height, srs, boundingBox,
    196                               transparency, bGColor, exceptions, time, sldURL, sld, vendorSpecificParameter );
    197        }
    198
    199        /**
    200         * creates a getMap request for requesting a cascaded remote WMS considering the getMap request and the
    201         * filterconditions defined in the submitted <tt>DataSource</tt> object The request will be encapsualted within a
    202         * <tt>OGCWebServiceEvent</tt>.
    203         *
    204         * @param ds
    205         * @param request
    206         * @param style
    207         * @param layer
    208         * @return GetMap request object
    209         */
    210        public static GetMap createGetMapRequest( AbstractDataSource ds, GetMap request, String style, String layer ) {
    211
    212            GetMap gmr = ( (RemoteWMSDataSource) ds ).getGetMapRequest();
    213
    214            String format = request.getFormat();
    215
    216            if ( gmr != null && !"%default%".equals( gmr.getFormat() ) ) {
    217                format = gmr.getFormat();
    218            }
    219
    220            GetMap.Layer[] lys = null;
    221            lys = new GetMap.Layer[1];
    222
    223            if ( style != null ) {
    224                lys[0] = PrintMap.createLayer( layer, style );
    225            } else {
    226                lys[0] = PrintMap.createLayer( layer, "$DEFAULT" );
    227            }
    228            if ( gmr != null && gmr.getLayers() != null && !( gmr.getLayers()[0].getName().equals( "%default%" ) ) ) {
    229                lys = gmr.getLayers();
    230            }
    231            Color bgColor = request.getBGColor();
    232            if ( gmr != null && gmr.getBGColor() != null ) {
    233                bgColor = gmr.getBGColor();
    234            }
    235            Values time = request.getTime();
    236            if ( gmr != null && gmr.getTime() != null ) {
    237                time = gmr.getTime();
    238            }
    239
    240            Map<String, String> vendorSpecificParameter = request.getVendorSpecificParameters();
    241            if ( gmr != null && gmr.getVendorSpecificParameters() != null && gmr.getVendorSpecificParameters().size() > 0 ) {
    242                vendorSpecificParameter.putAll( gmr.getVendorSpecificParameters() );
    243            }
    244            String version = "1.1.0";
    245            if ( gmr != null && gmr.getVersion() != null ) {
    246                version = gmr.getVersion();
    247            }
    248
    249            Values elevation = request.getElevation();
    250            if ( gmr != null && gmr.getElevation() != null ) {
    251                elevation = gmr.getElevation();
    252            }
    253            Map<String, Values> sampleDim = null;
    254            if ( gmr != null && gmr.getSampleDimension() != null ) {
    255                sampleDim = gmr.getSampleDimension();
    256            }
    257
    258            boolean tranparency = false;
    259            if ( gmr != null ) {
    260                tranparency = gmr.getTransparency();
    261            }
    262
    263            // now filter out the unwanted vendor specific parameters and put in
    264            // the wanted additional ones
    265            Map<String, String> vsp = new HashMap<String, String>( 10 );
    266            vsp.putAll( ( (RemoteWMSDataSource) ds ).getAddedParameters() );
    267            for ( String name : ( (RemoteWMSDataSource) ds ).getPassedParameters() ) {
    268                if ( vendorSpecificParameter.containsKey( name ) ) {
    269                    vsp.put( name, vendorSpecificParameter.get( name ).toString() );
    270                }
    271            }
    272
    273            IDGenerator idg = IDGenerator.getInstance();
    274            gmr = GetMap.create( version, "" + idg.generateUniqueID(), lys, elevation, sampleDim, format,
    275                                 request.getWidth(), request.getHeight(), request.getSrs(), request.getBoundingBox(),
    276                                 tranparency, bgColor, request.getExceptions(), time, null, null, vsp );
    277
    278            return gmr;
    279        }
    280
    281        /**
    282         * creates a <tt>GetMapRequest</tt> from a <tt>HashMap</tt> that contains the request parameters as key-value-pairs.
    283         * Keys are expected to be in upper case notation.
    284         *
    285         * @param model
    286         *            <tt>HashMap</tt> containing the request parameters
    287         * @return an instance of <tt>GetMapRequest</tt>
    288         * @throws InconsistentRequestException
    289         * @throws XMLParsingException
    290         * @throws MalformedURLException
    291         */
    292        public static GetMap create( Map<String, String> model )
    293                                throws InconsistentRequestException, XMLParsingException, MalformedURLException {
    294
    295            LOG.logDebug( "Request parameters: " + model );
    296
    297            // use model.remove(..) so at the end of the method the vendor
    298            // specific parameters remains in the model HashMap
    299            model.remove( "REQUEST" );
    300
    301            // Version
    302            String version = model.remove( "VERSION" );
    303
    304            if ( version == null ) {
    305                version = model.remove( "WMTVER" );
    306            }
    307
    308            if ( version == null ) {
    309                throw new InconsistentRequestException( "VERSION-value must be set" );
    310            }
    311
    312            // LAYERS & STYLES & SLD (URL, XML)
    313            StyledLayerDescriptor sld = null;
    314            String sld_body = model.remove( "SLD_BODY" );
    315            String sld_urlstring = model.remove( "SLD" );
    316
    317            // The SLD is complete in the Maprequest
    318            URL sLD_URL = null;
    319
    320            if ( sld_body != null ) {
    321                try {
    322                    sld_body = URLDecoder.decode( sld_body, CharsetUtils.getSystemCharset() );
    323                    sld = SLDFactory.createSLD( sld_body );
    324                } catch ( Exception ee ) {
    325                    throw new XMLParsingException( "Could not decode SLD_BODY: " + ee.toString() );
    326                }
    327            } else if ( sld_urlstring != null ) {
    328                // The SLD is as url in the Maprequest
    329                sLD_URL = new URL( sld_urlstring );
    330
    331                try {
    332                    sld = SLDFactory.createSLD( sLD_URL );
    333                } catch ( Exception ioex ) {
    334                    ioex.printStackTrace();
    335                    LOG.logError( ioex.getMessage(), ioex );
    336                    throw new InconsistentRequestException( "IOException occured during the access "
    337                                                            + "to the SLD-URL. Wrong URL? Server down?" + ioex.getMessage() );
    338                }
    339            }
    340
    341            // LAYERS & STYLES
    342            String layersstring = model.remove( "LAYERS" );
    343            if ( ( layersstring == null || layersstring.trim().length() == 0 ) && ( sld == null ) ) {
    344                throw new InconsistentRequestException( "At least one layer must be defined within a GetMap request" );
    345            }
    346            String stylesstring = model.remove( "STYLES" );
    347
    348            // normalize styles parameter
    349            if ( stylesstring == null ) {
    350                stylesstring = "";
    351            }
    352            if ( stylesstring.startsWith( "," ) ) {
    353                stylesstring = "$DEFAULT" + stylesstring;
    354            }
    355
    356            stylesstring = StringTools.replace( stylesstring, ",,", ",$DEFAULT,", true );
    357
    358            if ( stylesstring.endsWith( "," ) ) {
    359                stylesstring = stylesstring + "$DEFAULT";
    360            }
    361
    362            List<String> layers = StringTools.toList( layersstring, ",", false );
    363
    364            List<String> styles = null;
    365            if ( stylesstring.length() == 0 ) {
    366                styles = new ArrayList<String>( layers.size() );
    367                for ( int i = 0; i < layers.size(); i++ ) {
    368                    styles.add( "$DEFAULT" );
    369                }
    370            } else {
    371                styles = StringTools.toList( stylesstring, ",", false );
    372            }
    373
    374            // At last, build up the Layer object
    375            GetMap.Layer[] ls = new GetMap.Layer[layers.size()];
    376
    377            if ( styles.size() != layers.size() ) {
    378                throw new InconsistentRequestException( Messages.getMessage( "WMS_WRONG_STYLES" ) );
    379            }
    380
    381            for ( int i = 0; i < layers.size(); i++ ) {
    382                try {
    383                    String l = URLDecoder.decode( layers.get( i ), CharsetUtils.getSystemCharset() );
    384                    ls[i] = GetMap.createLayer( l, styles.get( i ) );
    385                } catch ( UnsupportedEncodingException e2 ) {
    386                    e2.printStackTrace();
    387                }
    388            }
    389
    390            // FORMAT
    391            String format = model.remove( "FORMAT" );
    392            if ( format == null ) {
    393                throw new InconsistentRequestException( "FORMAT-value must be set" );
    394            }
    395            try {
    396                format = URLDecoder.decode( format, CharsetUtils.getSystemCharset() );
    397            } catch ( UnsupportedEncodingException e1 ) {
    398                e1.printStackTrace();
    399            }
    400            if ( !MimeTypeMapper.isKnownImageType( format ) ) {
    401                throw new InvalidFormatException( format + " is not a valid image/result format" );
    402            }
    403
    404            // width
    405            String tmp = model.remove( "WIDTH" );
    406            if ( tmp == null ) {
    407                throw new InconsistentRequestException( "WIDTH must be set" );
    408            }
    409            int width = 0;
    410            try {
    411                width = Integer.parseInt( tmp );
    412            } catch ( Exception e ) {
    413                throw new InconsistentRequestException( "WIDTH must be a valid integer number" );
    414            }
    415
    416            // height
    417            tmp = model.remove( "HEIGHT" );
    418            if ( tmp == null ) {
    419                throw new InconsistentRequestException( "HEIGHT must be set" );
    420            }
    421            int height = 0;
    422            try {
    423                height = Integer.parseInt( tmp );
    424            } catch ( Exception e ) {
    425                throw new InconsistentRequestException( "HEIGHT must be a valid integer number" );
    426            }
    427
    428            double minx, miny, maxx, maxy;
    429            Envelope boundingBox = null;
    430            String srs;
    431            boolean isLongLat = false;
    432
    433            boolean is130 = false;
    434
    435            if ( "1.3.0".compareTo( version ) <= 0 ) {
    436                is130 = true;
    437
    438                // SRS or rather CRS
    439                srs = model.remove( "CRS" );
    440                if ( srs == null ) {
    441                    throw new InvalidCRSException( "CRS-value must be set" );
    442                }
    443
    444                // check for geographic coordinate system
    445                try {
    446                    CoordinateSystem crs = CRSFactory.create( srs );
    447                    isLongLat = crs.getAxisUnits()[0].equals( DEGREE ) && srs.toLowerCase().startsWith( "epsg" );
    448                } catch ( UnknownCRSException e ) {
    449                    LOG.logDebug( e.getLocalizedMessage(), e );
    450                    throw new InvalidCRSException( srs );
    451                }
    452
    453            } else {
    454                // SRS
    455                srs = model.remove( "SRS" );
    456                if ( srs == null ) {
    457                    throw new InvalidSRSException( "SRS-value must be set" );
    458                }
    459
    460                try {
    461                    // check for crs validity - yes, this method is bad. Is there a better one?
    462                    CRSFactory.create( srs );
    463                } catch ( UnknownCRSException e ) {
    464                    LOG.logDebug( e.getLocalizedMessage(), e );
    465                    if ( is130 ) {
    466                        throw new InvalidCRSException( Messages.getMessage( "WMS_UNKNOWN_CRS", srs ) );
    467                    }
    468                    throw new InvalidSRSException( Messages.getMessage( "WMS_UNKNOWN_CRS", srs ) );
    469                }
    470
    471            }
    472
    473            // BBOX
    474            String boxstring = model.remove( "BBOX" );
    475            if ( boxstring == null ) {
    476                throw new InconsistentRequestException( "BBOX-value must be set" );
    477            }
    478
    479            // ESRI ArcGIS Explorer hack which sends bboxes like 45,1234,7,234,46,123,8,345
    480            int count = StringTools.countString( boxstring, "," );
    481            if ( count == 7 ) {
    482                String str = boxstring;
    483                boxstring = "";
    484                for ( int i = 0; i < 4; ++i ) {
    485                    str = str.replaceFirst( ",", "." );
    486                    if ( str.indexOf( "," ) == -1 ) {
    487                        boxstring += str;
    488                    } else {
    489                        boxstring += str.substring( 0, str.indexOf( "," ) + 1 );
    490                        str = str.substring( str.indexOf( "," ) + 1 );
    491                    }
    492                }
    493                LOG.logDebug( "Changed bbox string from ArcGIS Explorer to " + boxstring );
    494            }
    495
    496            StringTokenizer st = new StringTokenizer( boxstring, "," );
    497
    498            if ( isLongLat ) {
    499                // parse first y, then x
    500                String s = st.nextToken().replace( ' ', '+' );
    501                miny = Double.parseDouble( s );
    502                s = st.nextToken().replace( ' ', '+' );
    503                minx = Double.parseDouble( s );
    504                s = st.nextToken().replace( ' ', '+' );
    505                maxy = Double.parseDouble( s );
    506                s = st.nextToken().replace( ' ', '+' );
    507                maxx = Double.parseDouble( s );
    508            } else {
    509                // old method
    510                String s = st.nextToken().replace( ' ', '+' );
    511                minx = Double.parseDouble( s );
    512                s = st.nextToken().replace( ' ', '+' );
    513                miny = Double.parseDouble( s );
    514                s = st.nextToken().replace( ' ', '+' );
    515                maxx = Double.parseDouble( s );
    516                s = st.nextToken().replace( ' ', '+' );
    517                maxy = Double.parseDouble( s );
    518            }
    519
    520            // check for consistency
    521            if ( minx >= maxx ) {
    522                throw new InvalidFormatException( "minx must be lower than maxx" );
    523            }
    524
    525            if ( miny >= maxy ) {
    526                throw new InvalidFormatException( "miny must be lower than maxy" );
    527            }
    528
    529            boundingBox = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, null );
    530
    531            // TRANSPARENCY
    532            boolean transparency = false;
    533            String tp = model.remove( "TRANSPARENT" );
    534            if ( tp != null ) {
    535                transparency = tp.toUpperCase().trim().equals( "TRUE" );
    536            }
    537
    538            String mime = MimeTypeMapper.toMimeType( format );
    539            if ( mime.equals( "image/jpg" ) || mime.equals( "image/jpeg" ) || mime.equals( "image/bmp" )
    540                 || mime.equals( "image/tif" ) || mime.equals( "image/tiff" ) ) {
    541                transparency = false;
    542            }
    543
    544            // BGCOLOR
    545            tmp = model.remove( "BGCOLOR" );
    546            Color bgColor = Color.white;
    547            if ( tmp != null ) {
    548                bgColor = Color.decode( tmp );
    549            }
    550
    551            // EXCEPTIONS
    552            String exceptions = model.remove( "EXCEPTIONS" );
    553
    554            if ( exceptions == null ) {
    555                if ( is130 ) {
    556                    exceptions = "XML";
    557                } else {
    558                    exceptions = "application/vnd.ogc.se_xml";
    559                }
    560            }
    561
    562            // WFS
    563            /*
    564             * URL wFS_URL = null; if ((String)model.get( "WFS" ) != null) { wFS_URL = new URL((String)model.remove( "WFS"
    565             * )); }
    566             */
    567
    568            // ID
    569            String id = model.remove( "ID" );
    570            if ( id == null ) {
    571                throw new InconsistentRequestException( "ID-value must be set" );
    572            }
    573
    574            String dim = model.remove( "TIME" );
    575            DimensionValues dimTime = dim == null ? null : new DimensionValues( dim );
    576            dim = model.remove( "ELEVATION" );
    577            DimensionValues dimElev = dim == null ? null : new DimensionValues( dim );
    578
    579            // VendorSpecificParameter; because all defined parameters has been
    580            // removed
    581            // from the model the vendorSpecificParameters are what left
    582            Map<String, String> vendorSpecificParameter = new HashMap<String, String>();
    583            for ( Object str : model.keySet() ) {
    584                vendorSpecificParameter.put( str.toString(), model.get( str ).toString() );
    585            }
    586
    587            return new GetMap( version, id, ls, format, width, height, srs, boundingBox, transparency, bgColor, exceptions,
    588                               sLD_URL, sld, vendorSpecificParameter, dimTime, dimElev );
    589        }
    590
    591        /**
    592         * creates a <tt>GetMapRequest</tt> from its XML representation as defined in SLD 1.0.0 specification
    593         *
    594         * <p>
    595         * This method does not yet cope with 1.3.0.
    596         * </p>
    597         *
    598         * @param id
    599         *            an unique id of the request
    600         * @param doc
    601         *            the document tree
    602         * @return an instance of <tt>GetMapRequest</tt>
    603         * @throws XMLParsingException
    604         * @throws InvalidSRSException
    605         * @throws InconsistentRequestException
    606         */
    607        public static GetMap create( String id, Document doc )
    608                                throws XMLParsingException, InvalidSRSException, InconsistentRequestException {
    609            String PSLD = CommonNamespaces.SLD_PREFIX + ':';
    610
    611            Element root = doc.getDocumentElement();
    612            NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
    613            Element sldElem = (Element) XMLTools.getRequiredNode( root, PSLD + "StyledLayerDescriptor", nsContext );
    614            XMLFragment xml = new XMLFragment();
    615            xml.setRootElement( sldElem );
    616
    617            StyledLayerDescriptor sld = SLDFactory.createSLD( xml );
    618            String version = root.getAttribute( "version" );
    619
    620            boolean is130 = false;
    621
    622            if ( "1.3.0".compareTo( version ) <= 0 ) {
    623                is130 = true;
    624            }
    625
    626            Element bboxElem = (Element) XMLTools.getRequiredNode( root, PSLD + "BoundingBox", nsContext );
    627
    628            Envelope bbox;
    629            try {
    630                bbox = GMLGeometryAdapter.wrapBox( bboxElem, null );
    631                // check for consistency
    632                if ( bbox.getMin().getX() >= bbox.getMax().getX() ) {
    633                    throw new InvalidFormatException( "minx must be lower than maxx" );
    634                }
    635
    636                if ( bbox.getMin().getY() >= bbox.getMax().getY() ) {
    637                    throw new InvalidFormatException( "miny must be lower than maxy" );
    638                }
    639            } catch ( InvalidGMLException e ) {
    640                LOG.logDebug( e.getLocalizedMessage(), e );
    641                if ( bboxElem == null ) {
    642                    throw new InconsistentRequestException( Messages.getMessage( "WMS_NO_BOUNDINGBOX" ) );
    643                }
    644                if ( is130 ) {
    645                    throw new InvalidCRSException( Messages.getMessage( "WMS_UNKNOWN_CRS",
    646                                                                        bboxElem.getAttribute( "srsName" ) ) );
    647                }
    648                throw new InvalidSRSException( Messages.getMessage( "WMS_UNKNOWN_CRS", bboxElem.getAttribute( "srsName" ) ) );
    649            } catch ( UnknownCRSException e ) {
    650                LOG.logDebug( e.getLocalizedMessage(), e );
    651                if ( bboxElem == null ) {
    652                    throw new InconsistentRequestException( Messages.getMessage( "WMS_NO_BOUNDINGBOX" ) );
    653                }
    654                if ( is130 ) {
    655                    throw new InvalidCRSException( Messages.getMessage( "WMS_UNKNOWN_CRS",
    656                                                                        bboxElem.getAttribute( "srsName" ) ) );
    657                }
    658                throw new InvalidSRSException( Messages.getMessage( "WMS_UNKNOWN_CRS", bboxElem.getAttribute( "srsName" ) ) );
    659            }
    660
    661            String srs = bbox.getCoordinateSystem().getIdentifier().toString();
    662
    663            Element output = (Element) XMLTools.getRequiredNode( root, PSLD + "Output", nsContext );
    664
    665            boolean transparent = XMLTools.getNodeAsBoolean( output, PSLD + "Transparent", nsContext, false );
    666
    667            int width = 0;
    668            int height = 0;
    669            try {
    670                Element node = (Element) XMLTools.getRequiredNode( output, PSLD + "Size", nsContext );
    671                width = XMLTools.getRequiredNodeAsInt( node, PSLD + "Width", nsContext );
    672                height = XMLTools.getRequiredNodeAsInt( node, PSLD + "Height", nsContext );
    673            } catch ( XMLParsingException e ) {
    674                throw new InconsistentRequestException( Messages.getMessage( "WMS_REQUEST_SIZE" ) );
    675            }
    676
    677            String exception = XMLTools.getNodeAsString( output, PSLD + "Exceptions", nsContext,
    678                                                         "application/vnd.ogc.se_xml" );
    679            String sbgColor = XMLTools.getNodeAsString( output, PSLD + "BGColor", nsContext, "#FFFFFF" );
    680            Color bgColor = Color.decode( sbgColor );
    681
    682            String format = XMLTools.getRequiredNodeAsString( output, PSLD + "Format", nsContext );
    683            if ( format == null ) {
    684                throw new InconsistentRequestException( "FORMAT-value must be set" );
    685            }
    686            try {
    687                format = URLDecoder.decode( format, CharsetUtils.getSystemCharset() );
    688            } catch ( UnsupportedEncodingException e1 ) {
    689                e1.printStackTrace();
    690            }
    691            if ( !MimeTypeMapper.isKnownImageType( format ) ) {
    692                throw new InvalidFormatException( format + " is not a valid image/result format" );
    693            }
    694
    695            GetMap req = new GetMap( version, id, null, null, null, format, width, height, srs, bbox, transparent, bgColor,
    696                                     exception, null, null, sld, null );
    697
    698            return req;
    699        }
    700
    701        /**
    702         * Creates a new GetMapRequest object.
    703         *
    704         * @param version
    705         * @param id
    706         * @param layers
    707         * @param elevation
    708         * @param sampleDimension
    709         * @param format
    710         * @param width
    711         * @param height
    712         * @param srs
    713         * @param boundingBox
    714         * @param transparency
    715         * @param bGColor
    716         * @param exceptions
    717         * @param time
    718         * @param sldURL
    719         * @param sld
    720         * @param vendorSpecificParameter
    721         *
    722         */
    723        GetMap( String version, String id, Layer[] layers, Values elevation, Map<String, Values> sampleDimension,
    724                String format, int width, int height, String srs, Envelope boundingBox, boolean transparency,
    725                Color bGColor, String exceptions, Values time, URL sldURL, StyledLayerDescriptor sld,
    726                Map<String, String> vendorSpecificParameter ) {
    727            super( version, id, vendorSpecificParameter );
    728
    729            if ( layers != null ) {
    730                this.layers = Arrays.asList( layers );
    731            } else {
    732                this.layers = new ArrayList<Layer>();
    733            }
    734            this.sld = sld;
    735            this.elevation = elevation;
    736            this.sampleDimension = sampleDimension;
    737            this.format = format;
    738            this.width = width;
    739            this.height = height;
    740            this.srs = srs;
    741            this.boundingBox = boundingBox;
    742            this.transparency = transparency;
    743            this.bGColor = bGColor;
    744            this.exceptions = exceptions;
    745            this.time = time;
    746            this.sLD_URL = sldURL;
    747            // setWFS_URL( wFS_URL );
    748        }
    749
    750        /**
    751         * @param version
    752         * @param id
    753         * @param ls
    754         * @param format
    755         * @param width
    756         * @param height
    757         * @param srs
    758         * @param boundingBox
    759         * @param transparency
    760         * @param bgColor
    761         * @param exceptions
    762         * @param sld_url
    763         * @param sld
    764         * @param vendorSpecificParameter
    765         * @param dimTime
    766         * @param dimElev
    767         */
    768        public GetMap( String version, String id, Layer[] ls, String format, int width, int height, String srs,
    769                       Envelope boundingBox, boolean transparency, Color bgColor, String exceptions, URL sld_url,
    770                       StyledLayerDescriptor sld, Map<String, String> vendorSpecificParameter, DimensionValues dimTime,
    771                       DimensionValues dimElev ) {
    772            this( version, id, ls, null, null, format, width, height, srs, boundingBox, transparency, bgColor, exceptions,
    773                  null, sld_url, sld, vendorSpecificParameter );
    774            this.dimTime = dimTime;
    775            this.dimElev = dimElev;
    776        }
    777
    778        /**
    779         * The FORMAT parameter specifies the output format of the response to an operation.
    780         * <p>
    781         * </p>
    782         * An OGC Web CapabilitiesService may offer only a subset of the formats known for that type of operation, but the
    783         * server shall advertise in its Capabilities XML those formats it does support and shall accept requests for any
    784         * format it advertises. A CapabilitiesService Instance may optionally offer a new format not previously offered by
    785         * other instances, with the recognition that clients are not required to accept or process an unknown format. If a
    786         * request contains a Format not offered by a particular server, the server shall throw a CapabilitiesService
    787         * Exception (with code "InvalidFormat").
    788         *
    789         * @return the output format
    790         */
    791        public String getFormat() {
    792            return format;
    793        }
    794
    795        /**
    796         * sets the format
    797         *
    798         * @param format
    799         *            the requested output-format
    800         */
    801        public void setFormat( String format ) {
    802            this.format = format;
    803        }
    804
    805        /**
    806         * The required LAYERS parameter lists the map layer(s) to be returned by this GetMap request. The value of the
    807         * LAYERS parameter is a comma-separated list of one or more valid layer names. Allowed layer names are the
    808         * character data content of any <Layer><Name> element in the Capabilities XML.
    809         * <p>
    810         * </p>
    811         * A WMS shall render the requested layers by drawing the leftmost in the list bottommost, the next one over that,
    812         * and so on.
    813         * <p>
    814         * </p>
    815         * Each layer is associated to a style. Styles are also is encoded as a comma- seperated list within the GetMap
    816         * request.
    817         * <p>
    818         * </p>
    819         * The required STYLES parameter lists the style in which each layer is to be rendered. There is a one-to-one
    820         * correspondence between the values in the LAYERS parameter and the values in the STYLES parameter. Because of this
    821         * layer-style combinations are returned coupled within an array of Layer- objects. Each map in the list of LAYERS
    822         * is drawn using the corresponding style in the same position in the list of STYLES. Each style Name shall be one
    823         * that was defined in the <Name> element of a <Style> element that is either directly contained within, or
    824         * inherited by, the associated <Layer> element in Capabilities XML.
    825         *
    826         * @return The required LAYERS
    827         */
    828        public Layer[] getLayers() {
    829            return layers.toArray( new Layer[layers.size()] );
    830        }
    831
    832        /**
    833         * adds the &lt;Layer&gt;
    834         *
    835         * @param layers
    836         */
    837        public void addLayers( Layer layers ) {
    838            this.layers.add( layers );
    839        }
    840
    841        /**
    842         * sets the &lt;Layer&gt;
    843         *
    844         * @param layers
    845         *            a set of layer
    846         */
    847        public void setLayers( Layer[] layers ) {
    848            this.layers.clear();
    849
    850            if ( layers != null ) {
    851                for ( int i = 0; i < layers.length; i++ ) {
    852                    this.layers.add( layers[i] );
    853                }
    854            }
    855        }
    856
    857        /**
    858         * The required SRS parameter states which Spatial Reference System applies to the values in the BBOX parameter. The
    859         * value of the SRS parameter shall be one of the values defined in the character data section of an <SRS> element
    860         * defined or inherited by the requested layer. The same SRS applies to all layers in a single request.
    861         * <p>
    862         * </p>
    863         * If the WMS server has declared SRS=NONE for a Layer, as discussed in the Basic CapabilitiesService Elements
    864         * section, then the Layer does not have a well-defined spatial reference system and should not be shown in
    865         * conjunction with other layers. The Client shall specify SRS=NONE (case-insensitive) in the GetMap request and the
    866         * Server may issue a CapabilitiesService Exception otherwise.
    867         *
    868         * @return the spatial reference system
    869         */
    870        public String getSrs() {
    871            return srs;
    872        }
    873
    874        /**
    875         * sets the srs
    876         *
    877         * @param srs
    878         *            the spatial reference system
    879         */
    880        public void setSrs( String srs ) {
    881            this.srs = srs;
    882        }
    883
    884        /**
    885         * The required BBOX parameter allows a Client to request a particular Bounding Box. Bounding Boxes are defined in
    886         * the Basic CapabilitiesService Elements section. The value of the BBOX parameter in a GetMap request is a list of
    887         * comma-separated numbers of the form "minx,miny,maxx,maxy".
    888         * <p>
    889         * </p>
    890         * If the WMS server has declared that a Layer is not subsettable then the Client shall specify exactly the declared
    891         * Bounding Box values in the GetMap request and the Server may issue a CapabilitiesService Exception otherwise.
    892         *
    893         * @return the bounding box
    894         */
    895        public Envelope getBoundingBox() {
    896            return boundingBox;
    897        }
    898
    899        /**
    900         * @see #getBoundingBox()
    901         * @param boundingBox
    902         */
    903        public void setBoundingBox( Envelope boundingBox ) {
    904            this.boundingBox = boundingBox;
    905        }
    906
    907        /**
    908         * WIDTH specifies the number of pixels to be used between the minimum and maximum X values (inclusive) in the BBOX
    909         * parameter. The returned picture, regardless of its return format, shall have exactly the specified width and
    910         * height in pixels. In the case where the aspect ratio of the BBOX and the ratio width/height are different, the
    911         * WMS shall stretch the returned map so that the resulting pixels could themselves be rendered in the aspect ratio
    912         * of the BBOX. In other words, it should be possible using this definition to request a map for a device whose
    913         * output pixels are themselves non-square, or to stretch a map into an image area of a different aspect ratio.
    914         *
    915         * @return the width
    916         */
    917        public int getWidth() {
    918            return width;
    919        }
    920
    921        /**
    922         * @see #getWidth()
    923         * @param width
    924         */
    925        public void setWidth( int width ) {
    926            this.width = width;
    927        }
    928
    929        /**
    930         * HEIGHT specifies the number of pixels between the minimum and maximum Y values. The returned picture, regardless
    931         * of its return format, shall have exactly the specified width and height in pixels. In the case where the aspect
    932         * ratio of the BBOX and the ratio width/height are different, the WMS shall stretch the returned map so that the
    933         * resulting pixels could themselves be rendered in the aspect ratio of the BBOX. In other words, it should be
    934         * possible using this definition to request a map for a device whose output pixels are themselves non-square, or to
    935         * stretch a map into an image area of a different aspect ratio.
    936         *
    937         * @return the height
    938         */
    939        public int getHeight() {
    940            return height;
    941        }
    942
    943        /**
    944         * @see #getHeight()
    945         * @param height
    946         */
    947        public void setHeight( int height ) {
    948            this.height = height;
    949        }
    950
    951        /**
    952         * The optional TRANSPARENT parameter specifies whether the map background is to be made transparent or not.
    953         * TRANSPARENT can take on two values, "TRUE" or "FALSE". The default value is FALSE if this parameter is absent
    954         * from the request.
    955         * <p>
    956         * </p>
    957         * The ability to return pictures drawn with transparent pixels allows results of different Map requests to be
    958         * overlaid, producing a composite map. It is strongly recommended that every WMS offer a format that provides
    959         * transparency for layers which could sensibly be overlaid above others.
    960         *
    961         * @return the transparency setting
    962         */
    963        public boolean getTransparency() {
    964            return transparency;
    965        }
    966
    967        /**
    968         * The optional BGCOLOR parameter specifies the color to be used as the background of the map. The general format of
    969         * BGCOLOR is a hexadecimal encoding of an RGB value where two hexadecimal characters are used for each of Red,
    970         * Green, and Blue color values. The values can range between 00 and FF for each (0 and 255, base 10). The format is
    971         * 0xRRGGBB; either upper or lower case characters are allowed for RR, GG, and BB values. The "0x" prefix shall have
    972         * a lower case 'x'. The default value is 0xFFFFFF (corresponding to the color white) if this parameter is absent
    973         * from the request.
    974         *
    975         * @return the background color
    976         */
    977        public Color getBGColor() {
    978            return bGColor;
    979        }
    980
    981        /**
    982         * The optional EXCEPTIONS parameter states the manner in which errors are to be reported to the client. The default
    983         * value is application/vnd.ogc.se_xml if this parameter is absent from the request.
    984         * <p>
    985         * </p>
    986         * A Web Map CapabilitiesService shall offer one or more of the following exception reporting formats by listing
    987         * them in separate <Format> elements inside the <Exceptions> element of its Capabilities XML. The entire MIME type
    988         * string in <Format> is used as the value of the EXCEPTIONS parameter. The first of these formats is required to be
    989         * offered by every WMS; the others are optional.
    990         *
    991         * @return the exceptions parameter
    992         */
    993        public String getExceptions() {
    994            return exceptions;
    995        }
    996
    997        /**
    998         * This specification is based on [ISO 8601:1988(E)]; it extends ISO 8601 in the following ways:
    999         * <UL>
    1000         * <li>It defines a syntax for expressing the start, end and periodicity of a data collection.
    1001         * <li>It defines terms to represent the 7 days of the week.
    1002         * <li>It allows years before 0001 AD.
    1003         * <li>It allows times in the distant geologic past (thousands, millions or billions of years before present).
    1004         * </UL>
    1005         *
    1006         * @return the time setting
    1007         */
    1008        public Values getTime() {
    1009            return time;
    1010        }
    1011
    1012        /**
    1013         * Some geospatial information may be available at multiple elevations. An OWS may announce available elevations in
    1014         * its Capabilities XML, and some operations include a parameter for requesting a particular elevation. A single
    1015         * elevation value is an integer or real number whose units are declared by naming an EPSG datum. When providing
    1016         * elevation information, Servers should declare a default value in Capabilities XML unless there is compelling
    1017         * reason to behave otherwise, and Servers shall respond with the default value if one has been declared and the
    1018         * Client request does not include a value.
    1019         *
    1020         * @return the elevation
    1021         */
    1022        public Values getElevation() {
    1023            return elevation;
    1024        }
    1025
    1026        /**
    1027         * Some geospatial information may be available at other dimensions (for example, satellite images in different
    1028         * wavelength bands). The dimensions other than the four space-time dimensions are referred to as
    1029         * "sample dimensions". An OWS may announce available sample dimensions in its Capabilities XML, and some operations
    1030         * include a mechanism for including dimensional parameters. Each sample dimension has a Name and one or more valid
    1031         * values.
    1032         *
    1033         * @return the map
    1034         */
    1035        public Map<String, Values> getSampleDimension() {
    1036            return sampleDimension;
    1037        }
    1038
    1039        /**
    1040         * @return the URL of Styled Layer Descriptor (as defined in SLD Specification). This parameter is optional. If no
    1041         *         sld URL is defined <tt>null</tt> will be returned.
    1042         */
    1043        public URL getSLD_URL() {
    1044            return sLD_URL;
    1045        }
    1046
    1047        /**
    1048         * @return the URL of Web Feature CapabilitiesService providing features to be symbolized using SLD. This parameter
    1049         *         is optional. If no WFS URL is defined <tt>null</tt> will be returned.
    1050         */
    1051        public URL getWFS_URL() {
    1052            return wFS_URL;
    1053        }
    1054
    1055        /**
    1056         * @return the SLD the request is made of. This implies that a 'simple' HTTP GET-Request will be transformed into a
    1057         *         valid SLD. This is mandatory within a JaGo WMS.
    1058         *         <p>
    1059         *         </p>
    1060         *         This mean even if a GetMap request is send using the HTTP GET method, an implementing class has to map
    1061         *         the request to a SLD data structure.
    1062         */
    1063        public StyledLayerDescriptor getStyledLayerDescriptor() {
    1064            return sld;
    1065        }
    1066
    1067        /**
    1068         * @return the parameter of a HTTP GET request.
    1069         *
    1070         */
    1071        @Override
    1072        public String getRequestParameter()
    1073                                throws OGCWebServiceException {
    1074
    1075            // indicates if the request parameters are decoded as SLD. deegree won't
    1076            // perform SLD requests through HTTP GET
    1077            if ( boundingBox == null ) {
    1078                throw new OGCWebServiceException( "Operations can't be expressed as HTTP GET request " );
    1079            }
    1080
    1081            StringBuffer sb = new StringBuffer();
    1082
    1083            if ( getVersion().compareTo( "1.0.0" ) <= 0 ) {
    1084                sb.append( "VERSION=" ).append( getVersion() ).append( "&REQUEST=map" );
    1085                String f = StringTools.replace( getFormat(), "image/", "", false );
    1086                sb.append( "&FORMAT=" );
    1087                try {
    1088                    sb.append( URLEncoder.encode( f, CharsetUtils.getSystemCharset() ) );
    1089                } catch ( UnsupportedEncodingException e ) {
    1090                    // system encoding should be supported...
    1091                }
    1092            } else {
    1093                sb.append( "&VERSION=" ).append( getVersion() ).append( "&REQUEST=GetMap" );
    1094                sb.append( "&FORMAT=" );
    1095                try {
    1096                    sb.append( URLEncoder.encode( getFormat(), CharsetUtils.getSystemCharset() ) );
    1097                } catch ( UnsupportedEncodingException e ) {
    1098                    // system encoding should be supported...
    1099                }
    1100            }
    1101
    1102            sb.append( "&TRANSPARENT=" ).append( Boolean.toString( getTransparency() ).toUpperCase() );
    1103            sb.append( "&WIDTH=" ).append( getWidth() );
    1104            sb.append( "&HEIGHT=" ).append( getHeight() );
    1105            sb.append( "&EXCEPTIONS=" ).append( getExceptions() );
    1106            sb.append( "&BGCOLOR=" ).append( ColorUtils.toHexCode( "0x", bGColor ) );
    1107
    1108            if ( "1.3.0".compareTo( getVersion() ) <= 0 ) {
    1109                sb.append( "&BBOX=" ).append( boundingBox.getMin().getY() );
    1110                sb.append( ',' ).append( boundingBox.getMin().getX() );
    1111                sb.append( ',' ).append( boundingBox.getMax().getY() );
    1112                sb.append( ',' ).append( boundingBox.getMax().getX() );
    1113            } else {
    1114                sb.append( "&BBOX=" ).append( boundingBox.getMin().getX() );
    1115                sb.append( ',' ).append( boundingBox.getMin().getY() );
    1116                sb.append( ',' ).append( boundingBox.getMax().getX() );
    1117                sb.append( ',' ).append( boundingBox.getMax().getY() );
    1118            }
    1119
    1120            Layer[] layers = getLayers();
    1121            StringBuffer l = new StringBuffer( 500 );
    1122            StringBuffer s = new StringBuffer( 500 );
    1123
    1124            if ( sLD_URL == null ) {
    1125                for ( int i = 0; i < layers.length; i++ ) {
    1126                    try {
    1127                        l.append( URLEncoder.encode( layers[i].getName(), CharsetUtils.getSystemCharset() ) );
    1128                        l.append( ',' );
    1129                        if ( !layers[i].getStyleName().equals( "$DEFAULT" ) ) {
    1130                            s.append( URLEncoder.encode( layers[i].getStyleName(), CharsetUtils.getSystemCharset() ) );
    1131                        }
    1132                        s.append( ',' );
    1133                    } catch ( Exception e ) {
    1134                        throw new OGCWebServiceException( e.toString() );
    1135                    }
    1136                }
    1137
    1138                if ( l.length() != 0 ) {
    1139                    sb.append( "&LAYERS=" ).append( l.substring( 0, l.length() - 1 ) );
    1140                }
    1141
    1142                if ( s.length() != 0 ) {
    1143                    sb.append( "&STYLES=" ).append( s.substring( 0, s.length() - 1 ) );
    1144                }
    1145            } else if ( sLD_URL != null ) {
    1146                sb.append( "&SLD=" ).append( NetWorker.url2String( sLD_URL ) );
    1147            } else if ( sld != null ) {
    1148                String tmp = ( (Marshallable) sld ).exportAsXML();
    1149                try {
    1150                    tmp = URLEncoder.encode( tmp, CharsetUtils.getSystemCharset() );
    1151                } catch ( Exception e ) {
    1152                    throw new OGCWebServiceException( e.toString() );
    1153                }
    1154                sb.append( "&SLD_BODY=" ).append( tmp );
    1155            }
    1156
    1157            if ( "1.3.0".compareTo( getVersion() ) <= 0 ) {
    1158                sb.append( "&CRS=" ).append( getSrs() );
    1159            } else {
    1160                sb.append( "&SRS=" ).append( getSrs() );
    1161            }
    1162
    1163            // TODO
    1164            // append time, elevation and sampleDimensions
    1165
    1166            if ( getVendorSpecificParameters() != null ) {
    1167                Iterator<String> iterator = getVendorSpecificParameters().keySet().iterator();
    1168                while ( iterator.hasNext() ) {
    1169                    String key = iterator.next();
    1170                    String value = getVendorSpecificParameters().get( key );
    1171                    try {
    1172                        value = URLEncoder.encode( value, CharsetUtils.getSystemCharset() );
    1173                    } catch ( UnsupportedEncodingException e ) {
    1174                        // system encoding should be supported...
    1175                    }
    1176                    sb.append( '&' ).append( key ).append( '=' ).append( value );
    1177                }
    1178            }
    1179
    1180            return sb.toString();
    1181        }
    1182
    1183        @Override
    1184        public String toString() {
    1185            String s = "An unknown " + this.getClass().getName() + " request";
    1186            try {
    1187                s = getRequestParameter();
    1188            } catch ( OGCWebServiceException e ) {
    1189                // in that case, we just don't have the parameters...
    1190            }
    1191            return s;
    1192        }
    1193
    1194        /**
    1195         * creates a Layer object beacuse of the inner class construct.
    1196         *
    1197         * @param name
    1198         *            the name of the layer
    1199         * @param style
    1200         *            the corresponding style of the layer
    1201         * @return Layer a layer object constaining name and style
    1202         */
    1203        public static Layer createLayer( String name, String style ) {
    1204            return new Layer( name, style );
    1205        }
    1206
    1207        /**
    1208         * A Layer object. It contains the name of the layer and the corresponding style.
    1209         *
    1210         * @version $Revision: 21363 $
    1211         * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    1212         */
    1213        public static class Layer implements Serializable {
    1214
    1215            private static final long serialVersionUID = -98575941104285931L;
    1216
    1217            private String name = null;
    1218
    1219            private String styleName = null;
    1220
    1221            /**
    1222             * constructor initializing the class with the <Layer>
    1223             *
    1224             * @param name
    1225             * @param styleName
    1226             */
    1227            public Layer( String name, String styleName ) {
    1228                this.name = name;
    1229                this.styleName = styleName;
    1230            }
    1231
    1232            /**
    1233             * @return the <Name>
    1234             */
    1235            public String getName() {
    1236                return name;
    1237            }
    1238
    1239            /**
    1240             * @return the <StyleName>
    1241             */
    1242            public String getStyleName() {
    1243                return styleName;
    1244            }
    1245
    1246        }
    1247
    1248        /**
    1249         * @return the dimTime
    1250         */
    1251        public DimensionValues getDimTime() {
    1252            return dimTime;
    1253        }
    1254
    1255        /**
    1256         * @param dimTime
    1257         *            the dimTime to set
    1258         */
    1259        public void setDimTime( DimensionValues dimTime ) {
    1260            this.dimTime = dimTime;
    1261        }
    1262
    1263        /**
    1264         * @return the dimElev
    1265         */
    1266        public DimensionValues getDimElev() {
    1267            return dimElev;
    1268        }
    1269
    1270        /**
    1271         * @param dimElev
    1272         *            the dimElev to set
    1273         */
    1274        public void setDimElev( DimensionValues dimElev ) {
    1275            this.dimElev = dimElev;
    1276        }
    1277
    1278    }