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