    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/ogcwebservices/wmps/operation/PrintMap.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.wmps.operation;
    037
    038    import java.awt.Color;
    039    import java.io.Serializable;
    040    import java.io.UnsupportedEncodingException;
    041    import java.net.URLDecoder;
    042    import java.sql.Timestamp;
    043    import java.util.ArrayList;
    044    import java.util.Arrays;
    045    import java.util.HashMap;
    046    import java.util.List;
    047    import java.util.Map;
    048    import java.util.StringTokenizer;
    049
    050    import org.deegree.framework.log.ILogger;
    051    import org.deegree.framework.log.LoggerFactory;
    052    import org.deegree.framework.util.CharsetUtils;
    053    import org.deegree.framework.util.StringTools;
    054    import org.deegree.framework.xml.NamespaceContext;
    055    import org.deegree.framework.xml.XMLParsingException;
    056    import org.deegree.framework.xml.XMLTools;
    057    import org.deegree.model.crs.CRSFactory;
    058    import org.deegree.model.crs.CoordinateSystem;
    059    import org.deegree.model.crs.UnknownCRSException;
    060    import org.deegree.model.spatialschema.Envelope;
    061    import org.deegree.model.spatialschema.GMLGeometryAdapter;
    062    import org.deegree.model.spatialschema.GeometryException;
    063    import org.deegree.model.spatialschema.GeometryFactory;
    064    import org.deegree.model.spatialschema.Point;
    065    import org.deegree.ogcbase.CommonNamespaces;
    066    import org.deegree.ogcbase.InvalidGMLException;
    067    import org.deegree.ogcwebservices.InconsistentRequestException;
    068    import org.deegree.ogcwebservices.wms.InvalidFormatException;
    069    import org.deegree.ogcwebservices.wms.operation.GetMap;
    070    import org.deegree.ogcwebservices.wms.operation.GetMap.Layer;
    071    import org.w3c.dom.Element;
    072    import org.w3c.dom.Node;
    073
    074    /**
    075     * This interface describes the access to the parameters of a PrintMap request. It is expected that there are two kinds
    076     * of request. The first is the 'normal' HTTP GET request with name-value-pair enconding and the second is a HTTP POST
    077     * request containing a SLD. It is possible to access the values of a HTTP GET request throught its bean accessor
    078     * methods. The request shall be mapped to a SLD data structure, accessible using the <code>getSLD()</code> method.
    079     *
    080     * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh</a>
    081     * @version 2.0
    082     */
    083    public class PrintMap extends WMPSRequestBase implements Serializable {
    084
    085        private static final long serialVersionUID = 6898492018448337645L;
    086
    087        private static final ILogger LOG = LoggerFactory.getLogger( PrintMap.class );
    088
    089        private static final NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
    090
    091        private List<Layer> layers;
    092
    093        private String srs;
    094
    095        private Envelope boundingBox;
    096
    097        private Point center;
    098
    099        private int scaleDenominator = -1;
    100
    101        private boolean transparent;
    102
    103        private Color bgColor;
    104
    105        private String title;
    106
    107        private String copyright;
    108
    109        private boolean legend;
    110
    111        private boolean scaleBar;
    112
    113        private String note;
    114
    115        private String template;
    116
    117        private String emailaddress;
    118
    119        private Timestamp timestamp;
    120
    121        private TextArea[] textAreas;
    122
    123        private int dpi;
    124
    125        /**
    126         * Create a new PrintMap instance.
    127         *
    128         * @param id
    129         * @param version
    130         * @param layers
    131         * @param srs
    132         * @param boundingBox
    133         * @param center
    134         * @param scaleDenominator
    135         * @param transparent
    136         * @param bgColor
    137         * @param title
    138         * @param copyright
    139         * @param legend
    140         * @param scaleBar
    141         * @param note
    142         * @param template
    143         * @param emailaddress
    144         * @param timestamp
    145         * @param textAreas
    146         * @param dpi
    147         * @param vendorSpecificParameter
    148         */
    149        PrintMap( String id, String version, Layer[] layers, String srs, Envelope boundingBox, Point center,
    150                  int scaleDenominator, boolean transparent, Color bgColor, String title, String copyright, boolean legend,
    151                  boolean scaleBar, String note, String template, String emailaddress, Timestamp timestamp,
    152                  TextArea[] textAreas, int dpi, Map<String, String> vendorSpecificParameter ) {
    153
    154            super( version, id, vendorSpecificParameter );
    155
    156            setLayers( layers );
    157            this.srs = srs;
    158            this.boundingBox = boundingBox;
    159            this.center = center;
    160            this.scaleDenominator = scaleDenominator;
    161            this.transparent = transparent;
    162            this.bgColor = bgColor;
    163            this.title = title;
    164            this.copyright = copyright;
    165            this.legend = legend;
    166            this.scaleBar = scaleBar;
    167            this.note = note;
    168            this.template = template;
    169            this.emailaddress = emailaddress;
    170            setTimestamp( timestamp );
    171            this.textAreas = textAreas;
    172            this.dpi = dpi;
    173        }
    174
    175        /**
    176         * @return the dpi
    177         */
    178        public int getDpi() {
    179            return dpi;
    180        }
    181
    182        /**
    183         * @param dpi
    184         *            the dpi to set
    185         */
    186        public void setDpi( int dpi ) {
    187            this.dpi = dpi;
    188        }
    189
    190        /**
    191         * Set the time stamp.
    192         *
    193         * @param timestamp
    194         */
    195        private void setTimestamp( Timestamp timestamp ) {
    196
    197            if ( timestamp != null ) {
    198                this.timestamp = timestamp;
    199            } else {
    200                this.timestamp = getCurrentTime();
    201            }
    202        }
    203
    204        /**
    205         * Gets the Current System Time where the request was recieved.
    206         *
    207         * @return Date
    208         */
    209        private static Timestamp getCurrentTime() {
    210            long now = System.currentTimeMillis();
    211            return new Timestamp( now );
    212        }
    213
    214        /**
    215         * The required LAYERS parameter lists the map layer(s) to be returned by this PrintMapRequest request. The value of
    216         * the LAYERS parameter is a comma-separated list of one or more valid layer names. Allowed layer names are the
    217         * character data content of any <Layer><Name> element in the Capabilities XML.
    218         * <p>
    219         * </p>
    220         * A WMS shall render the requested layers by drawing the leftmost in the list bottommost, the next one over that,
    221         * and so on.
    222         * <p>
    223         * </p>
    224         * Each layer is associated to a style. Styles are also is encoded as a comma- seperated list within the
    225         * PrintMapRequest request.
    226         * <p>
    227         * </p>
    228         * The required STYLES parameter lists the style in which each layer is to be rendered. There is a one-to-one
    229         * correspondence between the values in the LAYERS parameter and the values in the STYLES parameter. Because of this
    230         * layer-style combinations are returned coupled within an array of Layer- objects. Each map in the list of LAYERS
    231         * is drawn using the corresponding style in the same position in the list of STYLES. Each style Name shall be one
    232         * that was defined in the <Name> element of a <Style> element that is either directly contained within, or
    233         * inherited by, the associated <Layer> element in Capabilities XML.
    234         *
    235         * @return The required LAYERS
    236         */
    237        public Layer[] getLayers() {
    238            return this.layers.toArray( new Layer[this.layers.size()] );
    239        }
    240
    241        /**
    242         * adds the <Layer>
    243         *
    244         * @param layer
    245         */
    246        protected void addLayers( Layer layer ) {
    247            this.layers.add( layer );
    248        }
    249
    250        /**
    251         * sets the <Layer>
    252         *
    253         * @param layers
    254         *            a set of layer
    255         */
    256        private void setLayers( Layer[] layers ) {
    257            this.layers = new ArrayList<Layer>( layers.length );
    258            this.layers.clear();
    259            if ( layers != null ) {
    260                this.layers = Arrays.asList( layers );
    261            }
    262        }
    263
    264        /**
    265         * creates a <tt>PrintMapRequest</tt> from its XML representation as defined in the specification.
    266         *
    267         * @param root
    268         *            Element
    269         * @return an instance of <tt>PrintMapRequest</tt>
    270         * @throws InconsistentRequestException
    271         * @throws XMLParsingException
    272         */
    273        public static PrintMap create( Element root )
    274                                throws InconsistentRequestException, XMLParsingException {
    275
    276            LOG.logInfo( "Validating PrintMapRequest request." );
    277            // Validation
    278            if ( !root.getLocalName().equals( "PrintMap" ) ) {
    279                StringBuffer sb = new StringBuffer( 50 );
    280                sb.append( "Unable to create a 'PrintMapRequest' operation for node '" );
    281                sb.append( root.getLocalName() + "'. Please check the node to be parsed." );
    282                throw new InconsistentRequestException( sb.toString() );
    283            }
    284            // VERSION
    285            String version;
    286            try {
    287                version = XMLTools.getRequiredAttrValue( "version", null, root );
    288            } catch ( XMLParsingException e ) {
    289                throw new XMLParsingException( "Error parsing required attribute parameter 'Version'. " + e.getMessage() );
    290            }
    291
    292            // LAYERS & STYLES
    293            List<Layer> layerList = new ArrayList<Layer>();
    294            List<Node> layerElements = null;
    295            try {
    296                layerElements = XMLTools.getNodes( root, "deegreewmps:Layers", nsContext );
    297            } catch ( XMLParsingException e ) {
    298                throw new XMLParsingException( "Error parsing required parameter 'Layer(s)'. " + e.getMessage() );
    299            }
    300
    301            for ( int i = 0; i < layerElements.size(); i++ ) {
    302                Element layer = (Element) layerElements.get( i );
    303                List<Node> namedLayers = null;
    304                try {
    305                    namedLayers = XMLTools.getNodes( layer, "sld:NamedLayer", nsContext );
    306                    layerList = createLayers( namedLayers, layerList );
    307                } catch ( XMLParsingException e ) {
    308                    throw new XMLParsingException( "Error parsing parameter 'NamedLayer'." );
    309                }
    310                List<Node> userLayers = null;
    311                try {
    312                    userLayers = XMLTools.getNodes( layer, "sld:UserLayer", nsContext );
    313                    layerList = createLayers( userLayers, layerList );
    314                } catch ( XMLParsingException e ) {
    315                    throw new XMLParsingException( "Error parsing  parameter 'UserLayer'." );
    316                }
    317                if ( ( layerList == null ) || ( layerList.size() == 0 ) ) {
    318                    throw new InconsistentRequestException( "Atleast one 'NamedLayer' or one "
    319                                                            + "'UserLayer' has to be specified." );
    320                }
    321            }
    322            Layer[] layers = layerList.toArray( new Layer[layerList.size()] );
    323
    324            // BBOX
    325            Element bbox = null;
    326            String srsName = null;
    327            Envelope boundingBox = null;
    328            try {
    329                bbox = (Element) XMLTools.getNode( root, "gml:Envelope", nsContext );
    330                if ( bbox != null ) {
    331                    try {
    332                        srsName = XMLTools.getAttrValue( bbox, null, "srsName", null );
    333                        boundingBox = GMLGeometryAdapter.wrapBox( bbox, null );
    334                    } catch ( InvalidGMLException e ) {
    335                        throw new XMLParsingException( "Error creating a bounding box for the " + "'BBOX' parameter." );
    336                    } catch ( UnknownCRSException e ) {
    337                        throw new InconsistentRequestException( e.getMessage() );
    338                    }
    339                }
    340            } catch ( XMLParsingException e ) {
    341                throw new XMLParsingException( "Error parsing optional parameter 'BoundingBox'. " + e.getMessage() );
    342            }
    343
    344            // Center
    345            Point center = null;
    346            try {
    347                Element centerElement = (Element) XMLTools.getNode( root, "deegreewmps:Center", nsContext );
    348                if ( centerElement != null ) {
    349                    try {
    350                        srsName = XMLTools.getAttrValue( centerElement, null, "srsName", null );
    351                        center = (Point) GMLGeometryAdapter.wrap( centerElement, null );
    352                    } catch ( GeometryException e ) {
    353                        throw new XMLParsingException( "Error creating a Point for the 'Center' " + "parameter. "
    354                                                       + e.getMessage() );
    355                    }
    356                }
    357            } catch ( XMLParsingException e ) {
    358                throw new XMLParsingException( "Error parsing optional parameter 'Center'. " + e.getMessage() );
    359            }
    360
    361            // ScaleDenominator
    362            int scaleDenominator = -1;
    363            try {
    364                scaleDenominator = XMLTools.getNodeAsInt( root, "deegreewmps:ScaleDenominator", nsContext, -1 );
    365            } catch ( XMLParsingException e ) {
    366                throw new XMLParsingException( "Error parsing optional parameter 'Center'. " + e.getMessage() );
    367            }
    368
    369            if ( boundingBox == null ) {
    370                if ( center == null ) {
    371                    throw new InconsistentRequestException( "Both 'BoundingBox' and 'Center' are not specified. Either of "
    372                                                            + "the two must be set. Both values cannot be null" );
    373                }
    374                if ( scaleDenominator == -1 ) {
    375                    throw new InconsistentRequestException( "Scale Denominator must be specified if the Bounding Box has "
    376                                                            + "not been specified. Please check the 'SCALEDENOMINATOR' "
    377                                                            + "parameter." );
    378                }
    379            }
    380
    381            // TRANSPARENT
    382            boolean transparent = XMLTools.getNodeAsBoolean( root, "deegreewmps:Transparent", nsContext, false );
    383
    384            //
    385            int dpi = XMLTools.getNodeAsInt( root, "deegreewmps:DPI", nsContext, -1 );
    386
    387            // BGCOLOR
    388            Color bgColor = null;
    389            String colorstring = XMLTools.getNodeAsString( root, "deegreewmps:BGColor", nsContext, null );
    390            if ( colorstring == null ) {
    391                bgColor = Color.WHITE;
    392            } else {
    393                try {
    394                    bgColor = Color.decode( colorstring );
    395                } catch ( Exception e ) {
    396                    throw new InconsistentRequestException( "Error parsing 'BGCOLOR' parameter. The color '" + colorstring
    397                                                            + "' is not a hexadecimal definition of a valid color. "
    398                                                            + e.getMessage() );
    399                }
    400            }
    401
    402            boolean legend = XMLTools.getNodeAsBoolean( root, "deegreewmps:Legend", nsContext, false );
    403
    404            boolean scaleBar = XMLTools.getNodeAsBoolean( root, "deegreewmps:ScaleBar", nsContext, false );
    405
    406            String template = XMLTools.getNodeAsString( root, "deegreewmps:Template", nsContext, "default" );
    407
    408            String emailAdd = XMLTools.getNodeAsString( root, "deegreewmps:EMailAddress", nsContext, null );
    409
    410            List<Node> list = XMLTools.getNodes( root, "deegreewmps:TextAreas/deegreewmps:TextArea", nsContext );
    411
    412            TextArea[] textAreas = null;
    413            String title = null;
    414            String copyright = null;
    415            String note = null;
    416            if ( list != null ) {
    417                textAreas = new TextArea[list.size()];
    418                for ( int i = 0; i < list.size(); i++ ) {
    419                    Node textArea = (Node) list.get( i );
    420                    String name = XMLTools.getRequiredNodeAsString( textArea, "deegreewmps:Name", nsContext );
    421                    String value = XMLTools.getRequiredNodeAsString( textArea, "deegreewmps:Text", nsContext );
    422                    if ( name.equalsIgnoreCase( "TITLE" ) ) {
    423                        title = value;
    424                    }
    425                    if ( name.equalsIgnoreCase( "COPYRIGHT" ) ) {
    426                        copyright = value;
    427                    }
    428                    if ( name.equalsIgnoreCase( "NOTE" ) ) {
    429                        note = value;
    430                    }
    431                    textAreas[i] = new TextArea( name, value );
    432
    433                }
    434            }
    435            Map<String, String> vendorSpecificParameter = getVendorSpecificParameter( root );
    436
    437            String id = "" + System.currentTimeMillis();
    438
    439            LOG.logInfo( "Created PrintMap request request with id '" + id + "'." );
    440
    441            return new PrintMap( id, version, layers, srsName, boundingBox, center, scaleDenominator, transparent, bgColor,
    442                                 title, copyright, legend, scaleBar, note, template, emailAdd, getCurrentTime(), textAreas,
    443                                 dpi, vendorSpecificParameter );
    444
    445        }
    446
    447        /**
    448         * Returns the vendorspecific parameters as a map. Currently handles only the 'session id'
    449         *
    450         * @param root
    451         * @return Map
    452         */
    453        private static Map<String, String> getVendorSpecificParameter( Element root ) {
    454
    455            Map<String, String> vendorspecific = new HashMap<String, String>();
    456
    457            String sessionID = XMLTools.getAttrValue( root, null, "sessionID", null );
    458            if ( sessionID != null ) {
    459                LOG.logInfo( "vendor specific parameter 'sessionid' retrieved" );
    460                vendorspecific.put( "SESSIONID", sessionID );
    461            }
    462
    463            return vendorspecific;
    464        }
    465
    466        /**
    467         * Create Layer objects for each of namedLayer and userLayer.
    468         *
    469         * @param layerNodes
    470         * @param layers
    471         * @return List list of layer objects
    472         * @throws XMLParsingException
    473         */
    474        private static List<Layer> createLayers( List<Node> layerNodes, List<Layer> layers )
    475                                throws XMLParsingException {
    476
    477            if ( layerNodes != null ) {
    478                for ( int i = 0; i < layerNodes.size(); i++ ) {
    479                    Node layerNode = (Node) layerNodes.get( i );
    480                    try {
    481                        String layerName = XMLTools.getRequiredNodeAsString( layerNode, "sld:Name", nsContext );
    482                        String styleName = XMLTools.getRequiredNodeAsString( layerNode, "sld:NamedStyle/sld:Name",
    483                                                                             nsContext );
    484                        layers.add( new Layer( layerName, styleName ) );
    485                    } catch ( XMLParsingException e ) {
    486                        throw new XMLParsingException( "Error creating a Layer from the Node '" + layerNode.getNodeName()
    487                                                       + "'. " + e.getMessage() );
    488                    }
    489                }
    490            }
    491
    492            return layers;
    493        }
    494
    495        /**
    496         * creates a <tt>PrintMapRequest</tt> from a <tt>HashMap</tt> that contains the request parameters as
    497         * key-value-pairs. Keys are expected to be in upper case notation.
    498         *
    499         * @param model
    500         *            <tt>HashMap</tt> containing the request parameters
    501         * @return an instance of <tt>PrinttMapRequest</tt>
    502         * @throws InconsistentRequestException
    503         */
    504        public static PrintMap create( Map<String, String> model )
    505                                throws InconsistentRequestException {
    506
    507            retrieveRequestParameter( model );
    508
    509            String version = retrieveVersionParameter( model );
    510
    511            Layer[] layers = retrieveLayerAndStyleParameters( model );
    512
    513            String srs = retrieveSRSParameter( model );
    514
    515            Envelope boundingBox = null;
    516            Point center = null;
    517            try {
    518                boundingBox = retrieveBBOXParameter( model, srs );
    519                center = retrieveCenterParameter( model, srs );
    520            } catch ( UnknownCRSException e ) {
    521                throw new InconsistentRequestException( e.getMessage() );
    522            }
    523
    524            int scaleDenominator = retrieveScaleDenominatorParameter( model );
    525
    526            if ( boundingBox == null ) {
    527                if ( center == null ) {
    528                    throw new InconsistentRequestException( "Both 'BoundingBox' and 'Center' are not specified. Either of "
    529                                                            + "the 2 must be set.  Both values cannot be null" );
    530                }
    531                if ( scaleDenominator == -1 ) {
    532                    throw new InconsistentRequestException( "Scale Denominator must be specified if the Bounding Box has "
    533                                                            + "not been specified. Please check the 'SCALEDENOMINATOR' "
    534                                                            + "parameter." );
    535                }
    536            }
    537
    538            boolean transparent = retrieveTransparentParameter( model );
    539
    540            Color bgColor = retrieveBGColorParameter( model );
    541
    542            String title = retrieveTitleParameter( model );
    543
    544            String copyRightNote = retrieveCopyrightParameter( model );
    545
    546            boolean legend = retrieveLegendParameter( model );
    547
    548            boolean scaleBar = retrieveScaleBarParameter( model );
    549
    550            String note = retrieveNoteParameter( model );
    551
    552            String template = retrieveTemplateParameter( model );
    553
    554            String emailaddress = retrieveEmailParameter( model );
    555
    556            int dpi = retrieveDPIParameter( model );
    557
    558            TextArea[] textAreas = retrieveTextAreas( model );
    559
    560            Map<String, String> vendorSpecificParameter = model;
    561
    562            String id = "" + System.currentTimeMillis();
    563
    564            return new PrintMap( id, version, layers, srs, boundingBox, center, scaleDenominator, transparent, bgColor,
    565                                 title, copyRightNote, legend, scaleBar, note, template, emailaddress, getCurrentTime(),
    566                                 textAreas, dpi, vendorSpecificParameter );
    567
    568        }
    569
    570        /**
    571         * Retrieve the Text Areas to be displayed on the PDF output file. Extract the comma seperated list of name, value
    572         * pairs. The name and value should be seperated with a ':'. E.g.-> name:value,name:value,name:value
    573         *
    574         * @param model
    575         * @return TextArea
    576         */
    577        private static TextArea[] retrieveTextAreas( Map<String,String> model ) {
    578
    579            List<TextArea> texts = new ArrayList<TextArea>();
    580            if ( model.containsKey( "TEXTAREAS" ) ) {
    581                String textstring = (String) model.remove( "TEXTAREAS" );
    582                if ( textstring != null ) {
    583                    String[] nameValue = StringTools.toArray( textstring, ",", true );
    584                    if ( nameValue != null ) {
    585                        for ( int i = 0; i < nameValue.length; i++ ) {
    586                            String tmp = nameValue[i].trim();
    587                            int idx = tmp.indexOf( ":" );
    588                            if ( idx != -1 ) {
    589                                String name = tmp.substring( 0, idx );
    590                                String value = tmp.substring( idx + 1, tmp.length() );
    591                                if ( ( name != null ) && ( value != null ) ) {
    592                                    TextArea area = new TextArea( name.toUpperCase(), value );
    593                                    texts.add( area );
    594                                }
    595                            }
    596                        }
    597                    }
    598                }
    599            }
    600
    601            return texts.toArray( new TextArea[texts.size()] );
    602
    603        }
    604
    605        /**
    606         * Parse 'Template' Parameter.
    607         *
    608         * @param model
    609         * @return String
    610         * @throws InconsistentRequestException
    611         */
    612        private static String retrieveTemplateParameter( Map<String,String> model )
    613                                throws InconsistentRequestException {
    614
    615            String templatestring = null;
    616            if ( model.containsKey( "TEMPLATE" ) ) {
    617                templatestring = (String) model.remove( "TEMPLATE" );
    618
    619            }
    620            if ( templatestring == null ) {
    621                throw new InconsistentRequestException( "No Template defined. A Template name has to be specified "
    622                                                        + "along with the 'PrintMap' request." );
    623            }
    624
    625            return templatestring;
    626        }
    627
    628        /**
    629         * Retrieve Email parameter
    630         *
    631         * @param model
    632         * @return String
    633         * @throws InconsistentRequestException
    634         */
    635        private static String retrieveEmailParameter( Map<String,String> model )
    636                                throws InconsistentRequestException {
    637
    638            String email = null;
    639            if ( model.containsKey( "EMAIL" ) ) {
    640                email = (String) model.remove( "EMAIL" );
    641            }
    642
    643            if ( email == null ) {
    644                throw new InconsistentRequestException( "EMail parameter must be set." );
    645            }
    646
    647            return email;
    648        }
    649
    650        /**
    651         * Parse 'Note' Parameter.
    652         *
    653         * @param model
    654         * @return String
    655         */
    656        private static String retrieveNoteParameter( Map<String,String> model ) {
    657
    658            String note = null;
    659            if ( model.containsKey( "NOTE" ) ) {
    660                note = (String) model.remove( "NOTE" );
    661            }
    662
    663            return note;
    664        }
    665
    666        /**
    667         * Parse 'ScaleBar' Parameter.
    668         *
    669         * @param model
    670         * @return boolean
    671         * @throws InconsistentRequestException
    672         */
    673        private static boolean retrieveScaleBarParameter( Map<String,String> model )
    674                                throws InconsistentRequestException {
    675
    676            boolean showScaleBar = false;
    677            if ( model.containsKey( "SCALEBAR" ) ) {
    678                String scaleBar = (String) model.remove( "SCALEBAR" );
    679                if ( scaleBar == null ) {
    680                    showScaleBar = false;
    681                } else if ( scaleBar.equalsIgnoreCase( "True" ) ) {
    682                    showScaleBar = true;
    683                } else if ( scaleBar.equalsIgnoreCase( "False" ) ) {
    684                    showScaleBar = false;
    685                } else {
    686                    throw new InconsistentRequestException( "The 'ScaleBar' parameter can only have 'True', 'False' "
    687                                                            + "values. Here it is '" + scaleBar + "'." );
    688                }
    689            }
    690
    691            return showScaleBar;
    692        }
    693
    694        /**
    695         * Parse 'Legend' Parameter.
    696         *
    697         * @param model
    698         * @return boolean
    699         * @throws InconsistentRequestException
    700         */
    701        private static boolean retrieveLegendParameter( Map<String,String> model )
    702                                throws InconsistentRequestException {
    703
    704            boolean showLegend = false;
    705            if ( model.containsKey( "LEGEND" ) ) {
    706                String legend = (String) model.remove( "LEGEND" );
    707                if ( legend == null ) {
    708                    showLegend = false;
    709                } else if ( legend.equalsIgnoreCase( "True" ) ) {
    710                    showLegend = true;
    711                } else if ( legend.equalsIgnoreCase( "False" ) ) {
    712                    showLegend = false;
    713                } else {
    714                    throw new InconsistentRequestException( "The 'Legend' parameter can only have 'True', 'False' values. "
    715                                                            + "Here it is '" + legend + "'." );
    716                }
    717            }
    718
    719            return showLegend;
    720
    721        }
    722
    723        /**
    724         * Parse 'Copyright' Parameter.
    725         *
    726         * @param model
    727         * @return String
    728         */
    729        private static String retrieveCopyrightParameter( Map<String,String> model ) {
    730
    731            String copyright = null;
    732            if ( model.containsKey( "COPYRIGHT" ) ) {
    733                copyright = (String) model.remove( "COPYRIGHT" );
    734            }
    735
    736            return copyright;
    737        }
    738
    739        /**
    740         * @param model
    741         * @return
    742         */
    743        private static int retrieveDPIParameter( Map<String, String> model ) {
    744            String tmp = "-1";
    745            if ( model.containsKey( "DPI" ) ) {
    746                tmp = (String) model.remove( "DPI" );
    747            }
    748
    749            return Integer.parseInt( tmp );
    750        }
    751
    752        /**
    753         * Parse 'Title' Parameter.
    754         *
    755         * @param model
    756         * @return String
    757         */
    758        private static String retrieveTitleParameter( Map<String, String> model ) {
    759
    760            String title = null;
    761            if ( model.containsKey( "TITLE" ) ) {
    762                title = (String) model.remove( "TITLE" );
    763            }
    764
    765            return title;
    766        }
    767
    768        /**
    769         * Parse 'BGColor' Parameter.
    770         *
    771         * @param model
    772         * @return Color
    773         * @throws InconsistentRequestException
    774         */
    775        private static Color retrieveBGColorParameter( Map<String,String> model )
    776                                throws InconsistentRequestException {
    777
    778            Color bgColor = Color.WHITE;
    779            if ( model.containsKey( "BGCOLOR" ) ) {
    780                String colorstring = (String) model.remove( "BGCOLOR" );
    781                if ( ( colorstring != null ) || ( colorstring == "" ) ) {
    782                    try {
    783                        bgColor = Color.decode( colorstring );
    784                    } catch ( Exception e ) {
    785                        throw new InconsistentRequestException( "Error parsing 'BGCOLOR' parameter. The color '"
    786                                                                + colorstring + "' is not a hexadecimal "
    787                                                                + "definition of a valid color. " + e.getMessage() );
    788                    }
    789                }
    790            }
    791
    792            return bgColor;
    793        }
    794
    795        /**
    796         * Parse 'Transparent' Parameter.
    797         *
    798         * @param model
    799         * @return boolean
    800         * @throws InconsistentRequestException
    801         */
    802        private static boolean retrieveTransparentParameter( Map<String,String> model )
    803                                throws InconsistentRequestException {
    804
    805            boolean isTransparent = false;
    806            if ( model.containsKey( "TRANSPARENT" ) ) {
    807                String transparent = (String) model.remove( "TRANSPARENT" );
    808                if ( transparent == null ) {
    809                    isTransparent = false;
    810                } else if ( transparent.equalsIgnoreCase( "True" ) ) {
    811                    isTransparent = true;
    812                } else if ( transparent.equalsIgnoreCase( "False" ) ) {
    813                    isTransparent = false;
    814                } else {
    815                    throw new InconsistentRequestException( "The 'Transparent' parameter can only have "
    816                                                            + "'True', 'False' values. Here it has '" + transparent + "'." );
    817                }
    818            }
    819
    820            return isTransparent;
    821        }
    822
    823        /**
    824         * Parse 'ScaleDenominator' Parameter.
    825         *
    826         * @param model
    827         * @return String
    828         */
    829        private static int retrieveScaleDenominatorParameter( Map<String,String> model ) {
    830
    831            int scale = -1;
    832            if ( model.containsKey( "SCALE" ) ) {
    833                String value = (String) model.remove( "SCALE" );
    834                if ( value != null ) {
    835                    scale = Integer.parseInt( value );
    836                }
    837            }
    838
    839            return scale;
    840
    841        }
    842
    843        /**
    844         * Parse 'Center' Parameter and create a point.
    845         *
    846         * @param model
    847         * @param srs
    848         * @return Point to represent the x,y coordinates.
    849         * @throws InconsistentRequestException
    850         * @throws UnknownCRSException
    851         */
    852        private static Point retrieveCenterParameter( Map<String,String> model, String srs )
    853                                throws InconsistentRequestException, UnknownCRSException {
    854
    855            Point center = null;
    856            if ( model.containsKey( "CENTER" ) ) {
    857                String centerstring = (String) model.remove( "CENTER" );
    858
    859                String[] values = centerstring.split( "," );
    860                if ( values.length != 2 ) {
    861                    throw new InconsistentRequestException( "Centre should be defined as a Point with 'X' and 'Y' "
    862                                                            + "values. The current length is '" + values.length
    863                                                            + "'. It should " + "be '2'." );
    864                }
    865                double x = -1;
    866                double y = -1;
    867                try {
    868                    x = Double.parseDouble( values[0] );
    869                    y = Double.parseDouble( values[1] );
    870                } catch ( Exception e ) {
    871                    throw new InconsistentRequestException( "Error converting 'X','Y' coordinates in the request "
    872                                                            + "parameter 'CENTER' to double. Please check the "
    873                                                            + "values entered." );
    874                }
    875
    876                CoordinateSystem crs = CRSFactory.create( srs );
    877                center = GeometryFactory.createPoint( x, y, crs );
    878
    879            }
    880
    881            return center;
    882        }
    883
    884        /**
    885         * Parse 'Envelope' Parameter and create an envelope.
    886         *
    887         * @param model
    888         * @param srs
    889         * @return Envelope
    890         * @throws InconsistentRequestException
    891         * @throws InvalidFormatException
    892         * @throws UnknownCRSException
    893         */
    894        private static Envelope retrieveBBOXParameter( Map<String,String> model, String srs )
    895                                throws InconsistentRequestException, InvalidFormatException, UnknownCRSException {
    896
    897            Envelope bbox = null;
    898
    899            if ( model.containsKey( "BBOX" ) ) {
    900                String boxstring = (String) model.remove( "BBOX" );
    901                StringTokenizer st = new StringTokenizer( boxstring, "," );
    902                String s = st.nextToken().replace( ' ', '+' );
    903                double minx = Double.parseDouble( s );
    904                s = st.nextToken().replace( ' ', '+' );
    905                double miny = Double.parseDouble( s );
    906                s = st.nextToken().replace( ' ', '+' );
    907                double maxx = Double.parseDouble( s );
    908                s = st.nextToken().replace( ' ', '+' );
    909                double maxy = Double.parseDouble( s );
    910
    911                if ( minx >= maxx ) {
    912                    throw new InvalidFormatException( "minx must be lesser than maxx" );
    913                }
    914
    915                if ( miny >= maxy ) {
    916                    throw new InvalidFormatException( "miny must be lesser than maxy" );
    917                }
    918
    919                CoordinateSystem crs = CRSFactory.create( srs );
    920                bbox = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, crs );
    921            }
    922
    923            return bbox;
    924        }
    925
    926        /**
    927         * Parse 'SRS' Parameter.
    928         *
    929         * @param model
    930         * @return String
    931         * @throws InconsistentRequestException
    932         */
    933        private static String retrieveSRSParameter( Map<String,String> model )
    934                                throws InconsistentRequestException {
    935
    936            String srs = null;
    937            if ( model.containsKey( "SRS" ) ) {
    938                srs = (String) model.remove( "SRS" );
    939            }
    940            if ( srs == null ) {
    941                throw new InconsistentRequestException( "SRS-value must be set" );
    942            }
    943
    944            return srs;
    945        }
    946
    947        /**
    948         * Parse 'Layer' and 'Style' Parameter.
    949         *
    950         * @param model
    951         * @return Layer[]
    952         * @throws InconsistentRequestException
    953         */
    954        private static Layer[] retrieveLayerAndStyleParameters( Map<String,String> model )
    955                                throws InconsistentRequestException {
    956
    957            String layersstring = null;
    958            if ( model.containsKey( "LAYERS" ) ) {
    959                layersstring = (String) model.remove( "LAYERS" );
    960            }
    961            String stylesstring = null;
    962            if ( model.containsKey( "STYLES" ) ) {
    963                stylesstring = (String) model.remove( "STYLES" );
    964            }
    965
    966            // normalize styles parameter
    967            if ( ( stylesstring == null ) || stylesstring.trim().equals( "" ) ) {
    968                stylesstring = "$DEFAULT";
    969            }
    970            if ( stylesstring.startsWith( "," ) ) {
    971                stylesstring = "$DEFAULT" + stylesstring;
    972            }
    973            String tmp = ",$DEFAULT,";
    974            stylesstring = StringTools.replace( stylesstring, ",,", tmp, true );
    975            if ( stylesstring.endsWith( "," ) ) {
    976                stylesstring = stylesstring + "$DEFAULT";
    977            }
    978            List<String> layers = new ArrayList<String>();
    979            List<String> styles = new ArrayList<String>();
    980            GetMap.Layer[] ls = null;
    981            if ( ( layersstring != null ) && !layersstring.trim().equals( "" ) ) {
    982                StringTokenizer st = new StringTokenizer( layersstring, "," );
    983                int a = 0;
    984                while ( st.hasMoreTokens() ) {
    985                    String s = st.nextToken();
    986                    layers.add( s );
    987                }
    988                st = new StringTokenizer( stylesstring, "," );
    989                for ( int i = 0; i < layers.size(); i++ ) {
    990                    styles.add( "$DEFAULT" );
    991                }
    992                a = 0;
    993                while ( st.hasMoreTokens() ) {
    994                    String s = st.nextToken();
    995                    styles.set( a++, s );
    996                }
    997
    998                // At last, build up the Layer object
    999                ls = new GetMap.Layer[layers.size()];
    1000
    1001                for ( int i = 0; i < layers.size(); i++ ) {
    1002                    try {
    1003                        String l = URLDecoder.decode( layers.get( i ), CharsetUtils.getSystemCharset() );
    1004                        ls[i] = PrintMap.createLayer( l, styles.get( i ) );
    1005                    } catch ( UnsupportedEncodingException e2 ) {
    1006                        e2.printStackTrace();
    1007                    }
    1008                }
    1009            }
    1010
    1011            if ( ( ls == null || ls.length == 0 ) ) {
    1012                throw new InconsistentRequestException( "No layers defined in PrintMapRequest request" );
    1013            }
    1014
    1015            return ls;
    1016        }
    1017
    1018        /**
    1019         * Parse the Request parameter to check if the request is actually a 'PrintMapRequest' request
    1020         *
    1021         * @param model
    1022         * @throws InconsistentRequestException
    1023         */
    1024        private static void retrieveRequestParameter( Map<String,String> model )
    1025                                throws InconsistentRequestException {
    1026
    1027            String request = null;
    1028            if ( model.containsKey( "REQUEST" ) ) {
    1029                request = (String) model.remove( "REQUEST" );
    1030            } else {
    1031                throw new InconsistentRequestException( "Unable to create a PrintMapRequest operation. "
    1032                                                        + "The request parameter is missing." );
    1033            }
    1034            if ( request == null || !( request.equals( "PrintMap" ) ) ) {
    1035                throw new InconsistentRequestException( "Unable to create a PrintMapRequest operation for request '"
    1036                                                        + request + "'." );
    1037            }
    1038
    1039        }
    1040
    1041        /**
    1042         * Parse 'Version' Parameter.
    1043         *
    1044         * @param model
    1045         * @return String version (default=1.0.0)
    1046         */
    1047        private static String retrieveVersionParameter( Map<String,String> model ) {
    1048
    1049            String version = null;
    1050            if ( model.containsKey( "VERSION" ) ) {
    1051                version = (String) model.remove( "VERSION" );
    1052            }
    1053            if ( version == null ) {
    1054                /** default value set as per the WMPS draft specifications. */
    1055                version = "1.0.0";
    1056            }
    1057
    1058            return version;
    1059        }
    1060
    1061        /**
    1062         * Get TimeStamp
    1063         *
    1064         * @return TimeStamp
    1065         */
    1066        public Timestamp getTimestamp() {
    1067            return this.timestamp;
    1068        }
    1069
    1070        /**
    1071         * Get SRS
    1072         *
    1073         * @return String
    1074         */
    1075        public String getSRS() {
    1076            return this.srs;
    1077        }
    1078
    1079        /**
    1080         * Get bounding box
    1081         *
    1082         * @return Envelope maybe null
    1083         */
    1084        public Envelope getBBOX() {
    1085            return this.boundingBox;
    1086        }
    1087
    1088        /**
    1089         * Get center
    1090         *
    1091         * @return Point maybe null
    1092         */
    1093        public Point getCenter() {
    1094            return this.center;
    1095        }
    1096
    1097        /**
    1098         * Get ScaleDenominator
    1099         *
    1100         * @return String maybe null
    1101         */
    1102        public int getScaleDenominator() {
    1103            return this.scaleDenominator;
    1104        }
    1105
    1106        /**
    1107         * Get Transparency
    1108         *
    1109         * @return boolean
    1110         */
    1111        public boolean getTransparent() {
    1112            return this.transparent;
    1113        }
    1114
    1115        /**
    1116         * Get BGColor
    1117         *
    1118         * @return Color default is White.
    1119         */
    1120        public Color getBGColor() {
    1121            return this.bgColor;
    1122        }
    1123
    1124        /**
    1125         * Get Map Title
    1126         *
    1127         * @return String maybe null
    1128         */
    1129        public String getTitle() {
    1130            return this.title;
    1131        }
    1132
    1133        /**
    1134         * Get Copyright
    1135         *
    1136         * @return String maybe null
    1137         */
    1138        public String getCopyright() {
    1139            return this.copyright;
    1140        }
    1141
    1142        /**
    1143         * Get Legend
    1144         *
    1145         * @return boolean
    1146         */
    1147        public boolean getLegend() {
    1148            return this.legend;
    1149        }
    1150
    1151        /**
    1152         * Get Scale Bar
    1153         *
    1154         * @return boolean
    1155         */
    1156        public boolean getScaleBar() {
    1157            return this.scaleBar;
    1158        }
    1159
    1160        /**
    1161         * Get Note (extra descriptive text)
    1162         *
    1163         * @return String maybe null
    1164         */
    1165        public String getNote() {
    1166            return this.note;
    1167        }
    1168
    1169        /**
    1170         * Get Template
    1171         *
    1172         * @return String
    1173         */
    1174        public String getTemplate() {
    1175            return this.template;
    1176        }
    1177
    1178        /**
    1179         * Get Email Address
    1180         *
    1181         * @return String
    1182         */
    1183        public String getEmailAddress() {
    1184            return this.emailaddress;
    1185        }
    1186
    1187        /**
    1188         * Get Text Areas
    1189         *
    1190         * @return TextArea[]
    1191         */
    1192        public TextArea[] getTextAreas() {
    1193            return this.textAreas;
    1194        }
    1195
    1196        /**
    1197         * Retrieve ( if available ) the current text area identified by 'name' from the list of text areas defined. May
    1198         * return null.
    1199         *
    1200         * @param name
    1201         * @return TextArea
    1202         */
    1203        public TextArea getTextArea( String name ) {
    1204
    1205            TextArea textArea = null;
    1206            if ( this.textAreas != null && this.textAreas.length > 0 ) {
    1207                for ( int i = 0; i < this.textAreas.length; i++ ) {
    1208                    TextArea tmp = this.textAreas[i];
    1209                    if ( tmp.getName().equalsIgnoreCase( name ) ) {
    1210                        textArea = tmp;
    1211                        break;
    1212                    }
    1213                }
    1214            }
    1215
    1216            return textArea;
    1217        }
    1218
    1219        /**
    1220         * creates a Layer object beacuse of the inner class construct.
    1221         *
    1222         * @param name
    1223         *            the name of the layer
    1224         * @param style
    1225         *            the corresponding style of the layer
    1226         * @return Layer a layer object constaining name and style
    1227         */
    1228        public static Layer createLayer( String name, String style ) {
    1229            return new Layer( name, style );
    1230        }
    1231
    1232        /**
    1233         * Returns a new PrintMap instance.
    1234         *
    1235         * @param id
    1236         * @param version
    1237         * @param layers
    1238         * @param srs
    1239         * @param bbox
    1240         * @param center
    1241         * @param scaleDenominator
    1242         * @param transparent
    1243         * @param bgColor
    1244         * @param title
    1245         * @param copyright
    1246         * @param legend
    1247         * @param scaleBar
    1248         * @param note
    1249         * @param template
    1250         * @param emailAddress
    1251         * @param timestamp
    1252         * @param textAreas
    1253         * @param dpi
    1254         * @param vendorSpecificParameters
    1255         *
    1256         * @return PrintMap
    1257         */
    1258        public static PrintMap create( String id, String version, Layer[] layers, String srs, Envelope bbox, Point center,
    1259                                       int scaleDenominator, boolean transparent, Color bgColor, String title,
    1260                                       String copyright, boolean legend, boolean scaleBar, String note, String template,
    1261                                       String emailAddress, Timestamp timestamp, TextArea[] textAreas, int dpi,
    1262                                       Map<String, String> vendorSpecificParameters ) {
    1263
    1264            return new PrintMap( id, version, layers, srs, bbox, center, scaleDenominator, transparent, bgColor, title,
    1265                                 copyright, legend, scaleBar, note, template, emailAddress, timestamp, textAreas,
    1266                                 dpi, vendorSpecificParameters );
    1267        }
    1268
    1269        /**
    1270         * Overwrite the toString() method to export the current request as a readable statement. Currently only the id,
    1271         * version and layer names will be given out. TODO the rest
    1272         *
    1273         * @return String
    1274         */
    1275        @Override
    1276        public String toString() {
    1277
    1278            StringBuffer sb = new StringBuffer( 200 );
    1279            sb.append( "id: " );
    1280            sb.append( getId() );
    1281            sb.append( "\n" );
    1282            sb.append( "version: " );
    1283            sb.append( getVersion() );
    1284            sb.append( "\n" );
    1285            if ( this.layers != null ) {
    1286                sb.append( "layer(s): " );
    1287                for ( int i = 0; i < this.layers.size(); i++ ) {
    1288                    sb.append( this.layers.get( i ).getName() );
    1289                    sb.append( "\n" );
    1290                }
    1291            }
    1292            return sb.toString();
    1293        }
    1294    }