001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 }