001 //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/ogcwebservices/wmps/PrintMapHandler.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
037 package org.deegree.ogcwebservices.wmps;
038
039 import java.awt.Color;
040 import java.awt.Graphics;
041 import java.awt.Graphics2D;
042 import java.awt.Image;
043 import java.awt.geom.AffineTransform;
044 import java.awt.image.AffineTransformOp;
045 import java.awt.image.BufferedImage;
046 import java.io.ByteArrayOutputStream;
047 import java.io.File;
048 import java.io.FileOutputStream;
049 import java.io.IOException;
050 import java.io.InputStream;
051 import java.io.OutputStream;
052 import java.io.StringReader;
053 import java.net.MalformedURLException;
054 import java.net.URI;
055 import java.net.URISyntaxException;
056 import java.net.URL;
057 import java.sql.Connection;
058 import java.sql.SQLException;
059 import java.text.MessageFormat;
060 import java.util.ArrayList;
061 import java.util.HashMap;
062 import java.util.List;
063 import java.util.Map;
064
065 import net.sf.jasperreports.engine.JREmptyDataSource;
066 import net.sf.jasperreports.engine.JRException;
067 import net.sf.jasperreports.engine.JasperExportManager;
068 import net.sf.jasperreports.engine.JasperFillManager;
069 import net.sf.jasperreports.engine.JasperPrint;
070 import net.sf.jasperreports.engine.JasperPrintManager;
071
072 import org.deegree.datatypes.values.Values;
073 import org.deegree.framework.log.ILogger;
074 import org.deegree.framework.log.LoggerFactory;
075 import org.deegree.framework.util.ImageUtils;
076 import org.deegree.framework.util.MapUtils;
077 import org.deegree.framework.util.StringTools;
078 import org.deegree.framework.xml.NamespaceContext;
079 import org.deegree.framework.xml.XMLFragment;
080 import org.deegree.framework.xml.XMLParsingException;
081 import org.deegree.framework.xml.XMLTools;
082 import org.deegree.graphics.sld.StyledLayerDescriptor;
083 import org.deegree.graphics.transformation.WorldToScreenTransform;
084 import org.deegree.i18n.Messages;
085 import org.deegree.model.coverage.grid.WorldFile;
086 import org.deegree.model.crs.CRSFactory;
087 import org.deegree.model.crs.CoordinateSystem;
088 import org.deegree.model.crs.UnknownCRSException;
089 import org.deegree.model.spatialschema.Envelope;
090 import org.deegree.model.spatialschema.GeometryFactory;
091 import org.deegree.model.spatialschema.Point;
092 import org.deegree.ogcbase.CommonNamespaces;
093 import org.deegree.ogcwebservices.InconsistentRequestException;
094 import org.deegree.ogcwebservices.OGCWebServiceException;
095 import org.deegree.ogcwebservices.wmps.configuration.PrintMapParam;
096 import org.deegree.ogcwebservices.wmps.configuration.WMPSConfiguration;
097 import org.deegree.ogcwebservices.wmps.operation.PrintMap;
098 import org.deegree.ogcwebservices.wmps.operation.PrintMapResponseDocument;
099 import org.deegree.ogcwebservices.wmps.operation.TextArea;
100 import org.deegree.ogcwebservices.wms.capabilities.Layer;
101 import org.deegree.ogcwebservices.wms.capabilities.LegendURL;
102 import org.deegree.ogcwebservices.wms.capabilities.ScaleHint;
103 import org.deegree.ogcwebservices.wms.capabilities.Style;
104 import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
105 import org.deegree.ogcwebservices.wms.configuration.LocalWCSDataSource;
106 import org.deegree.ogcwebservices.wms.configuration.RemoteWCSDataSource;
107 import org.deegree.ogcwebservices.wms.configuration.RemoteWMSDataSource;
108 import org.deegree.ogcwebservices.wms.operation.GetMap;
109 import org.w3c.dom.Document;
110 import org.w3c.dom.Element;
111 import org.w3c.dom.Node;
112
113 /**
114 * Handles the PrintMap request. Retrieves the request from the DB and creates a pdf file.
115 *
116 * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh</a>
117 * @author last edited by: $Author: apoth $
118 *
119 * @version 2.0, $Revision: 21191 $, $Date: 2009-12-02 19:41:35 +0100 (Wed, 02 Dec 2009) $
120 */
121 public class PrintMapHandler implements Runnable {
122
123 private static final ILogger LOG = LoggerFactory.getLogger( PrintMapHandler.class );
124
125 private final double TILE_MAX_SIZE = 800;
126
127 private final String FORMAT = ".png";
128
129 private final String MIMETYPE = "image/png";
130
131 private final String EXCEPTION = "application/vnd.ogc.se_inimage";
132
133 private WMPSConfiguration configuration;
134
135 private String message;
136
137 /**
138 * Creates a new instance of the PrintMapHandler for the current configuration.
139 *
140 * @param configuration
141 */
142 public PrintMapHandler( WMPSConfiguration configuration ) {
143 this.configuration = configuration;
144 }
145
146 /**
147 * Run a new thread for each PrintMap request. This Thread runs till no more PrintMap requests are available in the
148 * DB.
149 *
150 * @see java.lang.Runnable#run()
151 */
152 public void run() {
153
154 RequestManager manager = null;
155 PrintMapResponseDocument response = null;
156 WMPSDatabase wmpsDB = null;
157 Connection connection = null;
158 try {
159 wmpsDB = new WMPSDatabase( this.configuration.getDeegreeParams().getCacheDatabase() );
160
161 while ( true ) {
162 connection = wmpsDB.acquireConnection();
163 // get request from DB
164 PrintMap printMap = wmpsDB.selectPrintMapRequest( connection );
165 if ( printMap == null ) {
166 break;
167 }
168
169 try {
170 LOG.logDebug( "Performing print map" );
171 manager = new DefaultRequestManager( this.configuration, printMap );
172 performPrintMap( printMap, false );
173 wmpsDB.updateDB( connection, printMap.getId(), printMap.getTimestamp(), "TRUE" );
174 response = manager.createFinalResponse( this.message, null );
175 manager.sendEmail( response );
176 } catch ( Exception e ) {
177 LOG.logError( e.getMessage(), e );
178 wmpsDB.updateDB( connection, printMap.getId(), printMap.getTimestamp(), "FAILED" );
179 sendExceptionMail( manager, response, e );
180 } finally {
181 releaseConnection( wmpsDB, connection );
182 }
183 LOG.logDebug( "Done performing PrintMap request." );
184 }
185 } catch ( Exception e ) {
186 LOG.logError( e.getMessage(), e );
187 sendExceptionMail( manager, response, e );
188 } finally {
189 releaseConnection( wmpsDB, connection );
190 }
191 }
192
193 private void sendExceptionMail( RequestManager manager, PrintMapResponseDocument response, Exception e ) {
194 if ( manager != null ) {
195 try {
196 response = manager.createFinalResponse( "print map failed", e.getMessage() );
197 manager.sendEmail( response );
198 } catch ( Exception e1 ) {
199 // should just happen if mail server is not reachable
200 // in this case the error just can be logged
201 XMLFragment doc = new XMLFragment( response.getRootElement() );
202 LOG.logDebug( doc.getAsString() );
203 LOG.logError( e.getMessage(), e );
204 }
205 }
206 }
207
208 private void releaseConnection( WMPSDatabase wmpsDB, Connection connection ) {
209 try {
210 if ( !connection.isClosed() ) {
211 wmpsDB.releaseConnection( connection );
212 }
213 } catch ( SQLException e ) {
214 // should never happen
215 LOG.logError( e.getMessage(), e );
216 }
217 }
218
219 /**
220 * performs a synchronous printMap processing
221 *
222 * @param printMap
223 * @return byte[]
224 * @throws Exception
225 */
226 public byte[] runSynchronous( PrintMap printMap )
227 throws Exception {
228 return performPrintMap( printMap, true );
229 }
230
231 /**
232 * From each PrintMap request run the WMS GetMap request.
233 *
234 * @param printMap
235 * @param synchronous
236 * @return byte[]
237 * @throws PrintMapServiceException
238 * @throws IOException
239 */
240 private byte[] performPrintMap( PrintMap printMap, boolean synchronous )
241 throws PrintMapServiceException, IOException {
242
243 Map<String, Layer> config_layers = retrieveLayersFromConfig( printMap );
244
245 int[] mapParams = getMapParamsFromTemplate( printMap );
246 int scaleDenominator = printMap.getScaleDenominator();
247 Envelope bbox = printMap.getBBOX();
248 if ( bbox == null ) {
249 LOG.logDebug( "BBOX not defined. Using the center and scale to calculate a new BBOX." );
250 Point center = printMap.getCenter();
251 bbox = createBBOX( printMap, center, scaleDenominator, mapParams[0], mapParams[1] );
252 } else { // Adjust aspect ratio of bbox to aspect ratio of template map area
253 double bboxAspectRatio = bbox.getWidth() / bbox.getHeight();
254 double printAspectRatio = ( (double) mapParams[0] ) / mapParams[1];
255 if ( bboxAspectRatio > printAspectRatio ) {
256 double centerY = bbox.getMin().getY() + ( ( bbox.getMax().getY() - bbox.getMin().getY() ) / 2d );
257 double height = bbox.getWidth() * ( 1.0 / printAspectRatio );
258 double minY = centerY - ( height / 2d );
259 double maxY = centerY + ( height / 2d );
260 bbox = GeometryFactory.createEnvelope( bbox.getMin().getX(), minY, bbox.getMax().getX(), maxY,
261 bbox.getCoordinateSystem() );
262 } else {
263 double centerX = bbox.getMin().getX() + ( ( bbox.getMax().getX() - bbox.getMin().getX() ) / 2d );
264 double width = bbox.getHeight() * printAspectRatio;
265 double minX = centerX - ( width / 2d );
266 double maxX = centerX + ( width / 2d );
267 bbox = GeometryFactory.createEnvelope( minX, bbox.getMin().getY(), maxX, bbox.getMax().getY(),
268 bbox.getCoordinateSystem() );
269 }
270 }
271 if ( scaleDenominator == -1 ) {
272 LOG.logDebug( "Scale not defined. Using MapUtil to calculate the scale denominator for the current bbox and map sizes" );
273 double pixelSize = WMPSConfiguration.INCH2M
274 / configuration.getDeegreeParams().getPrintMapParam().getTargetResolution();
275 scaleDenominator = (int) MapUtils.calcScale( mapParams[0], mapParams[1], bbox, bbox.getCoordinateSystem(),
276 pixelSize );
277 LOG.logDebug( "calculated map scale denominator: ", scaleDenominator );
278 }
279 BufferedImage mapImage = null;
280 try {
281 mapImage = performBuildMapImage( config_layers, printMap, bbox, mapParams[0], mapParams[1] );
282 saveImageToDisk( printMap, mapImage, "MAP", bbox );
283 String s = StringTools.concat( 100, "Retrieved PrintMap request '", printMap.getId(), "' and saved to disk" );
284 LOG.logDebug( s );
285 } catch ( OGCWebServiceException e ) {
286 LOG.logError( e.getMessage(), e );
287 throw new PrintMapServiceException( Messages.getMessage( "WMPS_ERROR_PERFORMING_PRINTMAP" ) );
288 } catch ( IOException e ) {
289 LOG.logError( e.getMessage(), e );
290 throw new PrintMapServiceException( Messages.getMessage( "WMPS_ERROR_WRITING_MAP_TMP_FILE" ) );
291 }
292 if ( printMap.getLegend() ) {
293 try {
294 BufferedImage legendImage = performGetLegend( config_layers, printMap, mapParams );
295 saveImageToDisk( printMap, legendImage, "LEGEND", null );
296 LOG.logDebug( "Saved the legend image file to disk." );
297 } catch ( IOException e ) {
298 LOG.logError( e.getMessage(), e );
299 throw new PrintMapServiceException( Messages.getMessage( "WMPS_ERROR_WRITING_LEGEND_TMP_FILE" ) );
300 }
301 }
302 return exportOutput( printMap, scaleDenominator, synchronous );
303 }
304
305 /**
306 * Build the Map image for the current PrintMap request. Vector and Raster layers are handled seperately.
307 *
308 * @param config_layers
309 * @param printMap
310 * @param bbox
311 * @param width
312 * @param height
313 * @return BufferedImage
314 * @throws OGCWebServiceException
315 */
316 private BufferedImage performBuildMapImage( Map<String, Layer> config_layers, PrintMap printMap, Envelope bbox,
317 double width, double height )
318 throws OGCWebServiceException {
319
320 BufferedImage targetImage = new BufferedImage( (int) width, (int) height, BufferedImage.TYPE_INT_ARGB );
321 Graphics2D g = (Graphics2D) targetImage.getGraphics();
322
323 if ( !printMap.getTransparent() ) {
324 g.setBackground( printMap.getBGColor() );
325 }
326
327 handleLayerDatasources( config_layers, printMap, bbox, width, height, g );
328 g.dispose();
329
330 return targetImage;
331 }
332
333 /**
334 * Determines the datasource for each layer(vector, raster).
335 *
336 * @param config_layers
337 * @param printMap
338 * @param bbox
339 * @param width
340 * @param height
341 * @param g
342 * @throws OGCWebServiceException
343 * @throws InconsistentRequestException
344 */
345 private void handleLayerDatasources( Map<String, Layer> config_layers, PrintMap printMap, Envelope bbox,
346 double width, double height, Graphics g )
347 throws OGCWebServiceException, InconsistentRequestException {
348
349 int dpi = printMap.getDpi();
350 if ( dpi < 0 ) {
351 dpi = configuration.getDeegreeParams().getPrintMapParam().getTargetResolution();
352 }
353 double px = WMPSConfiguration.INCH2M / dpi;
354 CoordinateSystem crs;
355 try {
356 crs = CRSFactory.create( printMap.getSRS() );
357 } catch ( UnknownCRSException e1 ) {
358 throw new InconsistentRequestException( e1.getMessage() );
359 }
360 double scale = MapUtils.calcScale( (int) width, (int) height, bbox, crs, px );
361 GetMap.Layer[] printMapLayers = printMap.getLayers();
362 for ( int i = 0; i < printMapLayers.length; i++ ) {
363 String name = printMapLayers[i].getName();
364
365 Layer configLayer = config_layers.get( name );
366 ScaleHint scaleHint = configLayer.getScaleHint();
367 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
368 LOG.logDebug( "current scale", scale );
369 LOG.logDebug( "valid layer min scale", scaleHint.getMin() );
370 LOG.logDebug( "valid layer max scale", scaleHint.getMax() );
371 }
372 if ( scale >= scaleHint.getMin() && scale < scaleHint.getMax() ) {
373 String type = determineDatasourceType( configLayer, scale );
374 if ( type != null && "vector".equalsIgnoreCase( type ) ) {
375
376 GetMap.Layer[] lay = null;
377 if ( ( printMapLayers.length - i ) > 1 ) {
378 lay = getContinuousVectorLayer( config_layers, printMapLayers, scale, i );
379 } else {
380 lay = new GetMap.Layer[] { printMapLayers[i] };
381 }
382 try {
383 for ( int j = 0; j < lay.length; j++ ) {
384 LOG.logDebug( "handle as vector layer: ", lay[j].getName() );
385 }
386 handleVectorDataLayer( printMap, bbox, width, height, g, lay );
387 } catch ( OGCWebServiceException e ) {
388 LOG.logError( e.getMessage(), e );
389 throw new OGCWebServiceException( Messages.getMessage( "WMPS_ERROR_HANDLING_GETMAP", name ) );
390 }
391 // Skip the number of layers already handled.
392 if ( lay.length != 1 ) {
393 i = i + ( lay.length - 1 );
394 }
395 } else {
396 // must be a raster data layer
397 GetMap.Layer[] lay = new GetMap.Layer[] { printMapLayers[i] };
398 LOG.logDebug( "handle as raster layer: ", printMapLayers[i].getName() );
399 try {
400 handleRasterDataLayer( printMap, bbox, width, height, g, lay );
401 } catch ( OGCWebServiceException e ) {
402 LOG.logError( e.getMessage(), e );
403 throw new OGCWebServiceException( Messages.getMessage( "WMPS_ERROR_HANDLING_GETMAP", name ) );
404 }
405 }
406 } else {
407 String s = StringTools.concat( 100, "No Datasource available for layer: ", name, " at scale: ", scale );
408 LOG.logInfo( s );
409 }
410 }
411
412 }
413
414 /**
415 * returns an array of layers that:
416 * <ul>
417 * <li>a) made of vector data
418 * <li>b) are continous in the requested list of layers
419 * </ul>
420 *
421 * @param config_layers
422 * @param printMapLayers
423 * @param mapScale
424 * scale of the entire map
425 * @param i
426 * @return Layer[]
427 */
428 private GetMap.Layer[] getContinuousVectorLayer( Map<String, Layer> config_layers, GetMap.Layer[] printMapLayers,
429 double mapScale, int i ) {
430
431 List<GetMap.Layer> layers = new ArrayList<GetMap.Layer>( printMapLayers.length );
432 int counter = 0;
433 for ( ; i < printMapLayers.length; i++ ) {
434 String name = printMapLayers[i].getName();
435 Layer configLayer = config_layers.get( name );
436 String type = determineDatasourceType( configLayer, mapScale );
437 if ( "vector".equals( type ) ) {
438 layers.add( counter, printMapLayers[i] );
439 counter++;
440 } else {
441 break;
442 }
443 }
444
445 return layers.toArray( new GetMap.Layer[layers.size()] );
446 }
447
448 /**
449 * Perform the GetMap request for vector layers.
450 *
451 * @param printMap
452 * @param bbox
453 * @param width
454 * @param height
455 * @param g
456 * @param lay
457 * @throws OGCWebServiceException
458 */
459 private void handleVectorDataLayer( PrintMap printMap, Envelope bbox, double width, double height, Graphics g,
460 GetMap.Layer[] lay )
461 throws OGCWebServiceException {
462
463 URL sldURL = null;
464 StyledLayerDescriptor sld = null;
465
466 GetMap getMap = GetMap.create( printMap.getVersion(), printMap.getId(), lay, null, null, this.MIMETYPE,
467 (int) width, (int) height, printMap.getSRS(), bbox, printMap.getTransparent(),
468 printMap.getBGColor(), this.EXCEPTION, null, sldURL, sld,
469 printMap.getVendorSpecificParameters() );
470 DefaultGetMapHandler gmh = new DefaultGetMapHandler( this.configuration, getMap );
471 gmh.performGetMap( printMap, g );
472
473 }
474
475 /**
476 * Perform the GetMap request for each raster layer. Here the raster layer is divided into tiles for memory handling
477 * efficiency.
478 *
479 * @param printMap
480 * @param bbox
481 * @param width
482 * @param height
483 * @param g
484 * @param lay
485 * @throws OGCWebServiceException
486 */
487 private void handleRasterDataLayer( PrintMap printMap, Envelope bbox, double width, double height, Graphics g,
488 GetMap.Layer[] lay )
489 throws OGCWebServiceException {
490
491 // Get Map (missing) parameters.
492 Values elevation = null;
493 Map<String, Values> sampleDimension = null;
494 Values time = null;
495 URL sldURL = null;
496 StyledLayerDescriptor sld = null;
497
498 boolean xRemainder = false;
499 int wtx = (int) width % (int) this.TILE_MAX_SIZE;
500 int nkx = (int) width / (int) this.TILE_MAX_SIZE;
501 if ( wtx > 0 ) {
502 xRemainder = true;
503 nkx++;
504 }
505
506 boolean yRemainder = false;
507 int wty = (int) height % (int) this.TILE_MAX_SIZE;
508 int nky = (int) height / (int) this.TILE_MAX_SIZE;
509 if ( wty > 0 ) {
510 yRemainder = true;
511 nky++;
512 }
513
514 WorldToScreenTransform trans = new WorldToScreenTransform( bbox.getMin().getX(), bbox.getMin().getY(),
515 bbox.getMax().getX(), bbox.getMax().getY(), 0d, 0d,
516 width - 1, height - 1 );
517
518 for ( int x = 0; x < nkx; x++ ) {
519 double tileWidth = this.TILE_MAX_SIZE;
520 if ( xRemainder ) {
521 if ( x == nkx - 1 ) {
522 tileWidth = wtx;
523 }
524 }
525 for ( int y = 0; y < nky; y++ ) {
526 double tileHeight = this.TILE_MAX_SIZE;
527 if ( yRemainder ) {
528 if ( y == nky - 1 ) {
529 tileHeight = wty;
530 }
531 }
532 BufferedImage bi = new BufferedImage( (int) tileWidth, (int) tileHeight, BufferedImage.TYPE_INT_ARGB );
533 Graphics tileg = bi.getGraphics();
534 // calc bbox
535 Envelope bb = calculateTileBBOX( trans, x, y, tileWidth, tileHeight, bbox.getCoordinateSystem() );
536 // create GetMap
537 GetMap getMap = GetMap.create( printMap.getVersion(), printMap.getId(), lay, elevation,
538 sampleDimension, this.MIMETYPE, (int) tileWidth, (int) tileHeight,
539 printMap.getSRS(), bb, printMap.getTransparent(), printMap.getBGColor(),
540 this.EXCEPTION, time, sldURL, sld,
541 printMap.getVendorSpecificParameters() );
542
543 // performGetMap( tileg );
544 DefaultGetMapHandler gmh = new DefaultGetMapHandler( this.configuration, getMap );
545 gmh.performGetMap( printMap, tileg );
546 tileg.dispose();
547 g.drawImage( bi, (int) Math.round( x * this.TILE_MAX_SIZE ),
548 (int) Math.round( y * this.TILE_MAX_SIZE ), (int) Math.round( tileWidth ),
549 (int) Math.round( tileHeight + 1 ), null );
550 }
551 }
552
553 }
554
555 /**
556 * Calculate the tile BBOX for the raster datalayer.
557 *
558 * @param trans
559 * @param x
560 * @param y
561 * @param tileWidth
562 * @param tileHeight
563 * @param crs
564 * @return Envelope
565 */
566 private Envelope calculateTileBBOX( WorldToScreenTransform trans, int x, int y, double tileWidth,
567 double tileHeight, CoordinateSystem crs ) {
568
569 double x1 = x * this.TILE_MAX_SIZE;
570 double y1 = y * this.TILE_MAX_SIZE;
571 double x2 = x1 + tileWidth;
572 double y2 = y1 + tileHeight;
573
574 double minX = trans.getSourceX( x1 );
575 double maxX = trans.getSourceX( x2 );
576 double minY = trans.getSourceY( y2 );
577 double maxY = trans.getSourceY( y1 );
578
579 return GeometryFactory.createEnvelope( minX, minY, maxX, maxY, crs );
580 }
581
582 /**
583 * Parses the Layer datastores to determine the type of the layer. Layers having a vector datasource as well as a
584 * raster datasource for the passed mapScale will be treated as raster layers
585 *
586 * @param layer
587 * @param mapScale
588 * scale of the entire map
589 * @return String either raster, vector or nodatasource
590 */
591 private String determineDatasourceType( Layer layer, double mapScale ) {
592
593 AbstractDataSource[] ads = layer.getDataSource();
594 String type = null;
595
596 boolean[] mixed = new boolean[] { false, false };
597 for ( int i = 0; i < ads.length; i++ ) {
598 ScaleHint scaleHint = ads[i].getScaleHint();
599 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
600 LOG.logDebug( "mapscale", mapScale );
601 LOG.logDebug( "valid datasource min scale", scaleHint.getMin() );
602 LOG.logDebug( "valid datasource max scale", scaleHint.getMax() );
603 }
604 if ( mapScale >= scaleHint.getMin() && mapScale < scaleHint.getMax() ) {
605 if ( ( ads[i] instanceof RemoteWMSDataSource ) || ( ads[i] instanceof RemoteWCSDataSource )
606 || ( ads[i] instanceof LocalWCSDataSource ) ) {
607 type = "raster";
608 mixed[0] = true;
609 } else {
610 type = "vector";
611 mixed[1] = true;
612 }
613 }
614 }
615 if ( mixed[0] && mixed[1] ) {
616 // Layers having a vector datasource as well as a raster datasource
617 // for the passed mapScale will be treated as raster layers
618 type = "raster";
619 }
620
621 return type;
622 }
623
624 /**
625 * Retrieve the legend images from the URL given in the configuration layers.
626 *
627 *
628 * @param layerDefs
629 * @param printMap
630 * @param mapParams
631 * @return BufferedImage
632 * @throws OGCWebServiceException
633 * @throws InconsistentRequestException
634 */
635 private BufferedImage performGetLegend( Map<String, Layer> layerDefs, PrintMap printMap, int[] mapParams ) {
636
637 GetMap.Layer[] layers = printMap.getLayers();
638
639 Map<String, Image> legendImg = new HashMap<String, Image>( layers.length );
640 int height = 0;
641 int maxWidth = 0;
642 for ( int i = 0; i < layers.length; i++ ) {
643 String name = layers[i].getName();
644 String styleName = layers[i].getStyleName();
645
646 Layer configLayer = layerDefs.get( name );
647 Style style = null;
648 if ( "$DEFAULT".equals( styleName ) ) {
649 style = configLayer.getStyleResource( "default:" + name );
650 } else {
651 style = configLayer.getStyleResource( styleName );
652 }
653 LegendURL[] lu = style.getLegendURL();
654 if ( lu != null && lu.length > 0 ) {
655 int k = 0;
656 boolean drawn = false;
657 while ( k < lu.length && !drawn ) {
658 URL url = lu[k++].getOnlineResource();
659 try {
660 Image img = ImageUtils.loadImage( url );
661 legendImg.put( name, img );
662 drawn = true;
663 } catch ( IOException e ) {
664 // we do not throw the exception bacause there are maybe
665 // further URLs we can try and even if not the user will
666 // be informed by a special legend symbol that no correct
667 // symbol can be accessed
668 LOG.logError( "can not access LegendURL: " + url, e );
669 } catch ( Exception e ) {
670 LOG.logError( "can not read image from LegendURL: " + url, e );
671 }
672 }
673 if ( !drawn ) {
674 // if legend URL(s) are defined but none of them can
675 // be accessed
676 String s = StringTools.concat( 100, "no legend URL accessable for layer: ", name, "; style: ",
677 styleName, " using dummy legend image" );
678 LOG.logError( s );
679 BufferedImage img = drawMissingLegendURLImage( s );
680 legendImg.put( name, img );
681 }
682 } else {
683 // if no legend URL has been defined which probably is the case
684 // for WMS no supporting GetLegendGraphic operation
685 String s = StringTools.concat( 100, "no legend URL available for layer: ", name, "; style: ",
686 styleName, " using dummy legend image" );
687 LOG.logError( s );
688 BufferedImage img = drawMissingLegendURLImage( s );
689 legendImg.put( name, img );
690 }
691 // update all over legend height and width
692 BufferedImage img = (BufferedImage) legendImg.get( name );
693 if ( img.getWidth() > maxWidth ) {
694 maxWidth = img.getWidth();
695 }
696 height += img.getHeight();
697 }
698
699 // depending on the size of the legend all legend symbols must scaled by
700 // the same factor to fit the legend size defined in the current template
701 double dh = calcDeltaLegend( mapParams[2], mapParams[3], height, maxWidth );
702
703 // create an empty basic image as target for painting all legend symbols
704 BufferedImage actualLegendImage = null;
705 if ( mapParams[2] > 0 && mapParams[3] > 0 ) {
706 actualLegendImage = new BufferedImage( mapParams[2], mapParams[3], BufferedImage.TYPE_INT_ARGB );
707
708 Graphics2D g = (Graphics2D) actualLegendImage.getGraphics();
709
710 int y = 0;
711 for ( int i = layers.length; i > 0; i-- ) {
712 // draw all legend symbols in correct order
713 String name = layers[i - 1].getName();
714 BufferedImage img = scaleImage( (BufferedImage) legendImg.get( name ), dh );
715 g.drawImage( img, 0, y, null );
716 y += img.getHeight();
717 }
718
719 g.dispose();
720 } else {
721 // create empty legend image if size is not valid
722 actualLegendImage = new BufferedImage( 10, 10, BufferedImage.TYPE_INT_ARGB );
723 }
724
725 return actualLegendImage;
726 }
727
728 private BufferedImage drawMissingLegendURLImage( String text ) {
729 BufferedImage img = new BufferedImage( 550, 50, BufferedImage.TYPE_INT_ARGB );
730 Graphics g = img.getGraphics();
731 g.setColor( Color.YELLOW );
732 g.fillRect( 0, 0, img.getWidth(), img.getHeight() );
733 g.setColor( Color.RED );
734 g.drawString( text, 10, 20 );
735 g.dispose();
736 return img;
737 }
738
739 /**
740 * calculates factor for resizing legend images
741 *
742 * @param legendWidth
743 * The width of the legend area
744 * @param legendHeight
745 * The height of the legend area
746 * @param height
747 * The height of all legends put together
748 * @param maxWidth
749 * The width of the wides legend
750 * @return Returns the factor for resizing legend images
751 */
752 private double calcDeltaLegend( int legendWidth, int legendHeight, int height, int maxWidth ) {
753 double dh = legendHeight / (double) height;
754 double dw = legendWidth / (double) maxWidth;
755 if ( dw < dh ) {
756 return dw;
757 }
758 return dh;
759 }
760
761 /**
762 * Scale Image.
763 *
764 * @param image
765 * @param ratio
766 * @return BufferedImage
767 */
768 private BufferedImage scaleImage( BufferedImage image, double ratio ) {
769
770 AffineTransform tx = new AffineTransform();
771 tx.scale( ratio, ratio );
772 AffineTransformOp op = new AffineTransformOp( tx, AffineTransformOp.TYPE_BILINEAR );
773
774 return op.filter( image, null );
775 }
776
777 /**
778 * Save the GetMap image to the disk.
779 *
780 * @param printMap
781 * @param image
782 * @param type
783 * @param bbox
784 * @throws IOException
785 */
786 private void saveImageToDisk( PrintMap printMap, BufferedImage image, String type, Envelope bbox )
787 throws IOException {
788
789 PrintMapParam printMapParam = this.configuration.getDeegreeParams().getPrintMapParam();
790 String fileName = null;
791 String templateName = printMap.getTemplate();
792 if ( type.equalsIgnoreCase( "MAP" ) ) {
793 fileName = StringTools.concat( 200, "Map_", templateName, '_', printMap.getId(), this.FORMAT );
794 WorldFile wf = new WorldFile( bbox.getWidth() / image.getWidth(), bbox.getHeight() / image.getHeight(), 0,
795 0, bbox );
796 String wffn = StringTools.concat( 200, "Map_", templateName, '_', printMap.getId(), ".wld" );
797 URL url = new URL( printMapParam.getPlotImageDir() + '/' + wffn );
798 OutputStream os = null;
799 try {
800 os = new FileOutputStream( new File( url.toURI() ) );
801 } catch ( URISyntaxException e ) {
802 // should never happen because each valid URL is a valid URI too
803 LOG.logError( e.getMessage(), e );
804 }
805 WorldFile.writeWorldFile( os, wf );
806 } else if ( type.equalsIgnoreCase( "LEGEND" ) ) {
807 fileName = StringTools.concat( 200, "Legend_", templateName, '_', printMap.getId(), this.FORMAT );
808 }
809
810 String path = printMapParam.getPlotImageDir() + '/' + fileName;
811 URL downloadDirectory = new URL( path );
812
813 try {
814 ImageUtils.saveImage( image, new File( downloadDirectory.toURI() ), 1 );
815 } catch ( URISyntaxException e ) {
816 // should never happen because each valid URL is a valid URI too
817 LOG.logError( e.getMessage(), e );
818 }
819
820 }
821
822 /**
823 * Use JasperReports to create a pdf file. The Jasper Template will be loaded and a dynamic link will be created to
824 * the image on the disk.
825 *
826 * @param printMap
827 * @param scaleDenominator
828 * @param synchronous
829 * @return byte[]
830 * @throws PrintMapServiceException
831 */
832 private byte[] exportOutput( PrintMap printMap, int scaleDenominator, boolean synchronous )
833 throws PrintMapServiceException {
834
835 // generate a file using JasperReports.
836 byte[] b = null;
837 try {
838 JasperPrint print = fillJasperTemplate( printMap, scaleDenominator );
839 b = doJasperPrintExport( printMap, print, synchronous );
840 } catch ( Exception e ) {
841 LOG.logError( e.getMessage(), e );
842 throw new PrintMapServiceException( Messages.getMessage( "WMPS_ERROR_SAVING_PDF" ) );
843 }
844
845 return b;
846 }
847
848 /**
849 * Open the JasperAPI to process the PrintMap request.
850 *
851 * @param printMap
852 * @param scaleDenominator
853 * @return JasperPrint
854 * @throws InconsistentRequestException
855 * @throws JRException
856 * @throws MalformedURLException
857 */
858 private JasperPrint fillJasperTemplate( PrintMap printMap, int scaleDenominator )
859 throws JRException, MalformedURLException {
860
861 URL templatePath = null;
862 try {
863 String templateName = printMap.getTemplate();
864 templatePath = getTemplatePath( templateName, true );
865 } catch ( IOException e ) {
866 LOG.logError( e.getMessage(), e );
867 throw new MalformedURLException( Messages.getMessage( "WMPS_ERROR_CREATING_TEMPLATEPATH",
868 printMap.getTemplate() ) );
869 }
870
871 Map<String, Object> parameters = new HashMap<String, Object>();
872 URL mapImagePath = getResultImagePath( printMap, "Map" );
873 parameters.put( "MAP", mapImagePath.getFile() );
874 if ( printMap.getLegend() ) {
875 URL legendImagePath = getResultImagePath( printMap, "Legend" );
876 parameters.put( "LEGEND", legendImagePath.getFile() );
877 }
878
879 String scale = "1:" + scaleDenominator;
880
881 if ( printMap.getScaleBar() == true ) {
882 parameters.put( "SCALE", scale );
883 }
884
885 TextArea[] textAreas = printMap.getTextAreas();
886 if ( textAreas != null && textAreas.length > 0 ) {
887 for ( int i = 0; i < textAreas.length; i++ ) {
888 TextArea textArea = textAreas[i];
889 LOG.logDebug( "Names and text fields entered, extracted." );
890 String name = textArea.getName();
891 String text = textArea.getText();
892 if ( name != null ) {
893 LOG.logDebug( "If name is not null, allocate it to the hashmap 'parameters' in uppercase." );
894 parameters.put( name.toUpperCase(), text );
895 parameters.put( name, text );
896 }
897 }
898 }
899 String title = printMap.getTitle();
900 if ( title != null ) {
901 parameters.put( "TITLE", title );
902 }
903 String copyright = printMap.getCopyright();
904 if ( copyright != null ) {
905 parameters.put( "COPYRIGHT", copyright );
906 }
907 String note = printMap.getNote();
908 if ( note != null ) {
909 parameters.put( "NOTE", note );
910 }
911 LOG.logDebug( "JASPER Parameter: ", parameters );
912 JasperPrint print = null;
913 try {
914 print = JasperFillManager.fillReport( templatePath.getFile(), parameters, new JREmptyDataSource() );
915 } catch ( JRException e ) {
916 LOG.logError( e.getMessage(), e );
917 throw new JRException( Messages.getMessage( "WMPS_ERROR_BUILDING_TEMPLATE", templatePath ) );
918 }
919
920 return print;
921 }
922
923 /**
924 * Retrieve the result map image file path for the current request.
925 *
926 * @param printMap
927 * @param type
928 * @return URL
929 * @throws MalformedURLException
930 */
931 private URL getResultImagePath( PrintMap printMap, String type )
932 throws MalformedURLException {
933
934 String templateName = printMap.getTemplate();
935 String fileName = type + "_" + templateName + "_" + printMap.getId() + this.FORMAT;
936 PrintMapParam printMapParam = this.configuration.getDeegreeParams().getPrintMapParam();
937 String path = printMapParam.getPlotImageDir() + '/' + fileName;
938 URL imagePath = new URL( path );
939
940 return imagePath;
941
942 }
943
944 /**
945 * Print the layer to a the specified format.
946 *
947 * @param printMap
948 * @param print
949 * @param synchronous
950 * @return byte[]
951 * @throws JRException
952 * @throws IOException
953 */
954 private byte[] doJasperPrintExport( PrintMap printMap, JasperPrint print, boolean synchronous )
955 throws JRException, IOException {
956
957 String format = this.configuration.getDeegreeParams().getPrintMapParam().getFormat();
958 String templateName = printMap.getTemplate();
959 String filename = StringTools.concat( 200, format, '_', templateName, '_', printMap.getId(), '.', format );
960 String directory = this.configuration.getDeegreeParams().getPrintMapParam().getPlotDirectory();
961
962 URL downloadFile = new URL( directory + '/' + filename );
963
964 byte[] b = null;
965 try {
966 if ( synchronous ) {
967 b = doSynchronousProcessing( print, format );
968 } else {
969 doSaveResultDocument( print, format, downloadFile );
970 createMailLink( filename );
971 }
972 } catch ( JRException e ) {
973 LOG.logError( e.getMessage(), e );
974 throw new JRException( Messages.getMessage( "WMPS_ERROR_PRINTING_REPORT", format, downloadFile.getFile() ) );
975 }
976
977 return b;
978 }
979
980 /**
981 * Create a mail link to be sent to the user email address. The mail link allows the user to open the pdf document
982 * for viewing and downloading purposes. Here 2 cases are taken into consideration
983 * <ul>
984 * <li>An authentification servlet link will be sent to the client.
985 * <li>A direct access to the clients data file.
986 * </ul>
987 *
988 * @param printMap
989 * @param filename
990 */
991 private void createMailLink( String filename ) {
992 PrintMapParam pmp = this.configuration.getDeegreeParams().getPrintMapParam();
993 String onlineResource = pmp.getOnlineResource();
994 String template = pmp.getMailTextTemplate();
995 this.message = MessageFormat.format( template, new Object[] { onlineResource, filename.trim() } );
996 }
997
998 /**
999 * Save the result document using the JasperExportManager to the file specified.
1000 *
1001 * @param print
1002 * @param format
1003 * @param downloadDirectory
1004 * @throws JRException
1005 * @throws IOException
1006 */
1007 private void doSaveResultDocument( JasperPrint print, String format, URL downloadDirectory )
1008 throws JRException, IOException {
1009 if ( format.equalsIgnoreCase( "pdf" ) ) {
1010 LOG.logDebug( "Exporting as pdf to file " + downloadDirectory.getFile() );
1011 JasperExportManager.exportReportToPdfFile( print, downloadDirectory.getFile() );
1012 } else if ( format.equalsIgnoreCase( "html" ) ) {
1013 LOG.logDebug( "Exporting as html to file " + downloadDirectory.getFile() );
1014 JasperExportManager.exportReportToHtmlFile( print, downloadDirectory.getFile() );
1015 } else if ( format.equalsIgnoreCase( "xml" ) ) {
1016 LOG.logDebug( "Exporting as xml to file " + downloadDirectory.getFile() );
1017 JasperExportManager.exportReportToXmlFile( print, downloadDirectory.getFile(), false );
1018 } else if ( format.equalsIgnoreCase( "png" ) ) {
1019 LOG.logDebug( "Exporting as xml to file " + downloadDirectory.getFile() );
1020 Image image = JasperPrintManager.printPageToImage( print, 0, 1 );
1021 ImageUtils.saveImage( (BufferedImage) image, new File( downloadDirectory.getFile() ), 1f );
1022 }
1023
1024 }
1025
1026 /**
1027 * Export the result document to a stream to be returend to the waiting client.
1028 *
1029 * @param print
1030 * @param format
1031 * @return byte[]
1032 * @throws JRException
1033 */
1034 private byte[] doSynchronousProcessing( JasperPrint print, String format )
1035 throws JRException {
1036
1037 byte[] b;
1038 ByteArrayOutputStream bos = new ByteArrayOutputStream( 100000 );
1039 if ( format.equalsIgnoreCase( "pdf" ) ) {
1040 JasperExportManager.exportReportToPdfStream( print, bos );
1041 } else if ( format.equalsIgnoreCase( "xml" ) ) {
1042 JasperExportManager.exportReportToXmlStream( print, bos );
1043 }
1044 b = bos.toByteArray();
1045
1046 return b;
1047 }
1048
1049 /**
1050 * Retrieve PrintMap request layers from the WMPSConfiguration file. Counter check if the layer has been defined and
1051 * also get the type of datasource used by the layer.
1052 *
1053 * @param printMap
1054 * @return Map key-> layer name, value -> configLayer
1055 * @throws PrintMapServiceException
1056 */
1057 private Map<String, Layer> retrieveLayersFromConfig( PrintMap printMap )
1058 throws PrintMapServiceException {
1059
1060 GetMap.Layer[] requestedLayers = printMap.getLayers();
1061 Map<String, Layer> layers = new HashMap<String, Layer>();
1062 for ( int i = 0; i < requestedLayers.length; i++ ) {
1063 GetMap.Layer layer = requestedLayers[i];
1064
1065 Layer configLayer = this.configuration.getLayer( layer.getName() );
1066 if ( configLayer != null ) {
1067 layers.put( layer.getName(), configLayer );
1068 } else {
1069 throw new PrintMapServiceException( Messages.getMessage( "WMPS_UNKNOWN_LAYER", layer.getName() ) );
1070 }
1071 }
1072
1073 return layers;
1074 }
1075
1076 /**
1077 * Create a bounding box if no bounding box has been passed along with the PrintMap request.
1078 *
1079 * @param printMap
1080 * @param center
1081 * @param scaleDenominator
1082 * @param mapWidth
1083 * @param mapHeight
1084 * @return Envelope
1085 */
1086 private Envelope createBBOX( PrintMap printMap, Point center, int scaleDenominator, double mapWidth,
1087 double mapHeight ) {
1088 int dpi = printMap.getDpi();
1089 if ( dpi < 0 ) {
1090 dpi = configuration.getDeegreeParams().getPrintMapParam().getTargetResolution();
1091 }
1092 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
1093 LOG.logDebug( "calculating BBOX using folloing parameter:" );
1094 LOG.logDebug( "map center: ", center );
1095 LOG.logDebug( "target scale: ", scaleDenominator );
1096 LOG.logDebug( "target resolution (dpi): ", dpi );
1097 LOG.logDebug( "map width: ", mapWidth );
1098 LOG.logDebug( "map height: ", mapHeight );
1099 }
1100 // screen -> world projection
1101 double pixelSize = WMPSConfiguration.INCH2M / dpi;
1102 double w2 = ( scaleDenominator * pixelSize * mapWidth ) / 2d;
1103 double x1 = center.getX() - w2;
1104 double x2 = center.getX() + w2;
1105 w2 = ( scaleDenominator * pixelSize * mapHeight ) / 2d;
1106 double y1 = center.getY() - w2;
1107 double y2 = center.getY() + w2;
1108
1109 Envelope bbox = GeometryFactory.createEnvelope( x1, y1, x2, y2, center.getCoordinateSystem() );
1110
1111 LOG.logDebug( "calculated BBOX: ", bbox );
1112 return bbox;
1113
1114 }
1115
1116 /**
1117 * Returns the current configuration used to initialise the PrintMapHandler.
1118 *
1119 * @return WMPSConfiguration
1120 */
1121 public WMPSConfiguration getConfiguration() {
1122 return this.configuration;
1123 }
1124
1125 /**
1126 * Parse the Template and retrieve the page width, page height information.
1127 *
1128 * @param printMap
1129 * @return int[]
1130 * @throws PrintMapServiceException
1131 * @throws IOException
1132 */
1133 private int[] getMapParamsFromTemplate( PrintMap printMap )
1134 throws PrintMapServiceException, IOException {
1135 String templateName = printMap.getTemplate();
1136 int[] mapParams = null;
1137 URL file = null;
1138 // try {
1139 boolean isCompiled = false;
1140 file = getTemplatePath( templateName, isCompiled );
1141 if ( file != null ) {
1142 Document dom = null;
1143 try {
1144 InputStream is = file.openStream();
1145 int c = 0;
1146 StringBuffer sb = new StringBuffer( 10000 );
1147 while ( ( c = is.read() ) > -1 ) {
1148 sb.append( (char) c );
1149 }
1150 is.close();
1151 // hack to ensure reporting engine is working even if the
1152 // jasper-report server is not available
1153 String s = StringTools.replace(
1154 sb.toString(),
1155 "<!DOCTYPE jasperReport PUBLIC \"//JasperReports//DTD Report Design//EN\" \"http://jasperreports.sourceforge.net/dtds/jasperreport.dtd\">",
1156 "", false );
1157
1158 dom = XMLTools.parse( new StringReader( s ) );
1159 // XMLFragment xml = new XMLFragment( file );
1160 mapParams = parseImageNodes( printMap, dom.getDocumentElement() );
1161 } catch ( Exception e ) {
1162 LOG.logError( e.getMessage(), e );
1163 throw new PrintMapServiceException( Messages.getMessage( "WMPS_ERROR_PARSING_TEMPLATE", file ) );
1164 }
1165 }
1166
1167 return mapParams;
1168 }
1169
1170 /**
1171 * Return the url for the current (jasper reports) template.
1172 *
1173 * @param templateName
1174 * @param isCompiled
1175 * @return URL
1176 * @throws PrintMapServiceException
1177 */
1178 private URL getTemplatePath( String templateName, boolean isCompiled )
1179 throws IOException {
1180
1181 if ( isCompiled ) {
1182 templateName = templateName + ".jasper";
1183 } else {
1184 templateName = templateName + ".jrxml";
1185 }
1186
1187 PrintMapParam printMapParam = this.configuration.getDeegreeParams().getPrintMapParam();
1188 URL fileURL = new URL( printMapParam.getTemplateDirectory() + templateName );
1189
1190 LOG.logDebug( "Retrieved the template file url. " + fileURL );
1191
1192 return fileURL;
1193 }
1194
1195 /**
1196 * Gets the Image node defined to hold the 'Map' and the node defined to hold the 'Legend'.
1197 *
1198 * @param root
1199 * @return List
1200 * @throws PrintMapServiceException
1201 */
1202 private int[] parseImageNodes( PrintMap printMap, Element root )
1203 throws PrintMapServiceException {
1204
1205 int[] mapParams = new int[4];
1206 int mapCount = 0;
1207 try {
1208 NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
1209 nsc.addNamespace( "jasper", URI.create( "http://jasperreports.sourceforge.net/jasperreports" ) );
1210 List<Node> images = XMLTools.getNodes( root, "detail/band/image", null );
1211 if ( images == null || images.size() == 0 ) {
1212 images = XMLTools.getNodes( root, "jasper:detail/jasper:band/jasper:image", nsc );
1213 }
1214 for ( int i = 0; i < images.size(); i++ ) {
1215 Node image = images.get( i );
1216 // e.g. $P{MAP}
1217 String value = XMLTools.getNodeAsString( image, "imageExpression", null, null );
1218 if ( value == null ) {
1219 value = XMLTools.getRequiredNodeAsString( image, "jasper:imageExpression", nsc );
1220 }
1221 int idx = value.indexOf( "{" );
1222 if ( idx != -1 ) {
1223
1224 String tmp = value.substring( idx + 1, value.length() - 1 );
1225 Element reportElement = (Element) XMLTools.getNode( image, "reportElement", null );
1226 if ( reportElement == null ) {
1227 reportElement = (Element) XMLTools.getRequiredNode( image, "jasper:reportElement", nsc );
1228 }
1229 String width = reportElement.getAttribute( "width" );
1230 String height = reportElement.getAttribute( "height" );
1231
1232 double dpi = printMap.getDpi();
1233 if ( dpi < 0 ) {
1234 dpi = configuration.getDeegreeParams().getPrintMapParam().getTargetResolution();
1235 }
1236 // Templates created by iReport assumes a resolution of 72 dpi
1237 if ( tmp.startsWith( "MAP" ) ) {
1238 mapParams[0] = (int) ( Integer.parseInt( width ) / 72d * dpi );
1239 mapParams[1] = (int) ( Integer.parseInt( height ) / 72d * dpi );
1240 mapCount = mapCount + 1;
1241 } else if ( tmp.startsWith( "LEGEND" ) ) {
1242 mapParams[2] = (int) ( Integer.parseInt( width ) / 72d * dpi );
1243 mapParams[3] = (int) ( Integer.parseInt( height ) / 72d * dpi );
1244 }
1245 }
1246 }
1247 if ( ( mapCount == 0 ) || ( mapCount > 1 ) ) {
1248 throw new PrintMapServiceException( Messages.getMessage( "WMPS_TOO_MANY_MAPAREAS", mapCount ) );
1249 }
1250 } catch ( XMLParsingException e ) {
1251 LOG.logError( e.getMessage(), e );
1252 throw new PrintMapServiceException( Messages.getMessage( "WMPS_INVALID_JASPER_TEMPLATE" ) );
1253 }
1254
1255 return mapParams;
1256 }
1257
1258 }