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 }