001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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: 21191 $, $Date: 2009-12-02 19:41:35 +0100 (Mi, 02 Dez 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 }