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