001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wms/DefaultGetMapHandler.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2008 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstr. 19 030 53177 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 ---------------------------------------------------------------------------*/ 043 package org.deegree.ogcwebservices.wms; 044 045 import java.awt.Color; 046 import java.awt.Font; 047 import java.awt.Graphics; 048 import java.awt.Graphics2D; 049 import java.awt.RenderingHints; 050 import java.awt.image.BufferedImage; 051 import java.util.ArrayList; 052 import java.util.LinkedList; 053 import java.util.List; 054 import java.util.concurrent.Callable; 055 import java.util.concurrent.CancellationException; 056 057 import org.apache.batik.svggen.SVGGraphics2D; 058 import org.deegree.framework.concurrent.ExecutionFinishedEvent; 059 import org.deegree.framework.concurrent.Executor; 060 import org.deegree.framework.log.ILogger; 061 import org.deegree.framework.log.LoggerFactory; 062 import org.deegree.framework.util.ImageUtils; 063 import org.deegree.framework.util.MapUtils; 064 import org.deegree.framework.util.MimeTypeMapper; 065 import org.deegree.graphics.MapFactory; 066 import org.deegree.graphics.Theme; 067 import org.deegree.graphics.optimizers.LabelOptimizer; 068 import org.deegree.graphics.sld.AbstractLayer; 069 import org.deegree.graphics.sld.AbstractStyle; 070 import org.deegree.graphics.sld.NamedLayer; 071 import org.deegree.graphics.sld.NamedStyle; 072 import org.deegree.graphics.sld.StyledLayerDescriptor; 073 import org.deegree.graphics.sld.UserLayer; 074 import org.deegree.graphics.sld.UserStyle; 075 import org.deegree.i18n.Messages; 076 import org.deegree.model.crs.CRSFactory; 077 import org.deegree.model.crs.CoordinateSystem; 078 import org.deegree.model.crs.GeoTransformer; 079 import org.deegree.model.spatialschema.Envelope; 080 import org.deegree.model.spatialschema.Geometry; 081 import org.deegree.model.spatialschema.GeometryFactory; 082 import org.deegree.ogcbase.InvalidSRSException; 083 import org.deegree.ogcwebservices.InconsistentRequestException; 084 import org.deegree.ogcwebservices.OGCWebServiceException; 085 import org.deegree.ogcwebservices.OGCWebServiceResponse; 086 import org.deegree.ogcwebservices.wms.capabilities.ScaleHint; 087 import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource; 088 import org.deegree.ogcwebservices.wms.configuration.WMSConfigurationType; 089 import org.deegree.ogcwebservices.wms.configuration.WMSConfiguration_1_3_0; 090 import org.deegree.ogcwebservices.wms.configuration.WMSDeegreeParams; 091 import org.deegree.ogcwebservices.wms.operation.GetMap; 092 import org.deegree.ogcwebservices.wms.operation.GetMapResult; 093 import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory; 094 import org.deegree.ogcwebservices.wms.operation.GetMap.Layer; 095 import org.w3c.dom.Element; 096 097 /** 098 * 099 * 100 * @version $Revision: 9697 $ 101 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 102 */ 103 public class DefaultGetMapHandler implements GetMapHandler { 104 105 private static final ILogger LOG = LoggerFactory.getLogger( DefaultGetMapHandler.class ); 106 107 private GetMap request = null; 108 109 // private Object[] themes = null; 110 111 private double scale = 0; 112 113 private CoordinateSystem reqCRS = null; 114 115 private WMSConfigurationType configuration = null; 116 117 private BufferedImage copyrightImg = null; 118 119 boolean version130 = false; 120 121 /** 122 * Creates a new GetMapHandler object. 123 * 124 * @param configuration 125 * @param request 126 * request to perform 127 */ 128 public DefaultGetMapHandler( WMSConfigurationType configuration, GetMap request ) { 129 this.request = request; 130 this.configuration = configuration; 131 132 try { 133 // get copyright image if possible 134 copyrightImg = ImageUtils.loadImage( configuration.getDeegreeParams().getCopyRight() ); 135 } catch ( Exception e ) { 136 // don't use copyright 137 } 138 139 } 140 141 /** 142 * returns the configuration used by the handler 143 * 144 * @return the configuration document 145 */ 146 public WMSConfigurationType getConfiguration() { 147 return configuration; 148 } 149 150 /** 151 * performs a GetMap request and retruns the result encapsulated within a <tt>GetMapResult</tt> 152 * object. 153 * <p> 154 * The method throws an WebServiceException that only shall be thrown if an fatal error occurs 155 * that makes it imposible to return a result. If something wents wrong performing the request 156 * (none fatal error) The exception shall be encapsulated within the response object to be 157 * returned to the client as requested (GetMap-Request EXCEPTION-Parameter). 158 * 159 * @return response to the GetMap response 160 */ 161 public OGCWebServiceResponse performGetMap() 162 throws OGCWebServiceException { 163 164 // some initialization is done here because the constructor is called by reflection 165 // and the exceptions won't be properly handled in that case 166 try { 167 reqCRS = CRSFactory.create( request.getSrs().toLowerCase() ); 168 } catch ( Exception e ) { 169 throw new InvalidSRSException( Messages.getMessage( "WMS_UNKNOWN_CRS", request.getSrs() ) ); 170 } 171 172 version130 = "1.3.0".equals( request.getVersion() ); 173 174 // exceeds the max allowed map width ? 175 int maxWidth = configuration.getDeegreeParams().getMaxMapWidth(); 176 if ( ( maxWidth != 0 ) && ( request.getWidth() > maxWidth ) ) { 177 throw new InconsistentRequestException( Messages.getMessage( "WMS_EXCEEDS_WIDTH", new Integer( maxWidth ) ) ); 178 } 179 180 // exceeds the max allowed map height ? 181 int maxHeight = configuration.getDeegreeParams().getMaxMapHeight(); 182 if ( ( maxHeight != 0 ) && ( request.getHeight() > maxHeight ) ) { 183 throw new InconsistentRequestException( 184 Messages.getMessage( "WMS_EXCEEDS_HEIGHT", new Integer( maxHeight ) ) ); 185 } 186 187 try { 188 double pixelSize = 1; 189 if ( version130 ) { 190 // required because for WMS 1.3.0 'scale' represents the ScaleDenominator 191 // and for WMS < 1.3.0 it represents the size of a pixel diagonal in meter 192 pixelSize = MapUtils.DEFAULT_PIXEL_SIZE; 193 } 194 195 scale = MapUtils.calcScale( request.getWidth(), request.getHeight(), request.getBoundingBox(), reqCRS, 196 pixelSize ); 197 198 LOG.logInfo( "OGC WMS scale: " + scale ); 199 } catch ( Exception e ) { 200 LOG.logError( e.getMessage(), e ); 201 throw new OGCWebServiceException( Messages.getMessage( "WMS_SCALECALC" ) ); 202 } 203 204 GetMap.Layer[] ls = request.getLayers(); 205 206 // if 1.3.0, check for maximum allowed layers 207 if ( version130 ) { 208 WMSConfiguration_1_3_0 cfg = (WMSConfiguration_1_3_0) configuration; 209 if ( ls.length > cfg.getLayerLimit() ) { 210 String ms = Messages.getMessage( "WMS_EXCEEDS_NUMBER", new Integer( cfg.getLayerLimit() ) ); 211 throw new InconsistentRequestException( ms ); 212 } 213 } 214 215 Layer[] oldLayers = ls; 216 ls = validateLayers( ls ); 217 218 LOG.logDebug( "Validated " + ls.length + " layers." ); 219 220 StyledLayerDescriptor sld = toSLD( oldLayers, request.getStyledLayerDescriptor() ); 221 222 AbstractLayer[] layers = sld.getLayers(); 223 224 LOG.logDebug( "After SLD consideration, found " + layers.length + " layers." ); 225 226 List<Callable<Object>> themes = new LinkedList<Callable<Object>>(); 227 228 for ( int i = 0; i < layers.length; i++ ) { 229 230 if ( layers[i] instanceof NamedLayer ) { 231 String styleName = null; 232 if ( i < request.getLayers().length ) { 233 styleName = request.getLayers()[i].getStyleName(); 234 } 235 invokeNamedLayer( layers[i], styleName, themes ); 236 } else { 237 double sc = scale; 238 if ( !version130 ) { 239 // required because for WMS 1.3.0 'scale' represents the ScaleDenominator 240 // and for WMS < 1.3.0 it represents the size of a pixel diagonal in meter 241 sc = scale / MapUtils.DEFAULT_PIXEL_SIZE; 242 } 243 themes.add( new GetMapServiceInvokerForUL( this, (UserLayer) layers[i], sc ) ); 244 } 245 } 246 247 Executor executor = Executor.getInstance(); 248 try { 249 List<ExecutionFinishedEvent<Object>> results; 250 results = executor.performSynchronously( themes, configuration.getDeegreeParams().getRequestTimeLimit() ); 251 252 GetMapResult res = renderMap( results ); 253 return res; 254 } catch ( InterruptedException e ) { 255 LOG.logError( e.getMessage(), e ); 256 String s = Messages.getMessage( "WMS_WAITING" ); 257 throw new OGCWebServiceException( getClass().getName(), s ); 258 } 259 } 260 261 /** 262 * this methods validates layer in two ways:<br> 263 * a) are layers available from the current WMS<br> 264 * b) If a layer is selected that includes other layers determine all its sublayers having 265 * <Name>s and return them instead 266 * 267 * @param ls 268 * @return the layers 269 * @throws LayerNotDefinedException 270 * @throws InvalidSRSException 271 */ 272 private Layer[] validateLayers( Layer[] ls ) 273 throws LayerNotDefinedException, InvalidSRSException { 274 275 List<Layer> layer = new ArrayList<Layer>( ls.length ); 276 for ( int i = 0; i < ls.length; i++ ) { 277 org.deegree.ogcwebservices.wms.capabilities.Layer l = configuration.getLayer( ls[i].getName() ); 278 279 if ( l == null ) { 280 throw new LayerNotDefinedException( Messages.getMessage( "WMS_UNKNOWNLAYER", ls[i].getName() ) ); 281 } 282 283 validateSRS( l.getSrs(), ls[i].getName() ); 284 285 layer.add( ls[i] ); 286 if ( l.getLayer() != null ) { 287 layer = addNestedLayers( l.getLayer(), ls[i].getStyleName(), layer ); 288 } 289 } 290 291 return layer.toArray( new Layer[layer.size()] ); 292 } 293 294 /** 295 * adds all direct and none direct sub-layers of the passed WMS capabilities layer as 296 * 297 * @see GetMap.Layer to the passed list. 298 * @param layer 299 * @param reqLayer 300 * @param list 301 * @return all sublayers 302 * @throws InvalidSRSException 303 */ 304 private List<Layer> addNestedLayers( org.deegree.ogcwebservices.wms.capabilities.Layer[] ll, String styleName, 305 List<Layer> list ) 306 throws InvalidSRSException { 307 308 for ( int j = 0; j < ll.length; j++ ) { 309 if ( ll[j].getName() != null ) { 310 String name = ll[j].getName(); 311 validateSRS( ll[j].getSrs(), name ); 312 list.add( GetMap.createLayer( name, styleName ) ); 313 } 314 if ( ll[j].getLayer() != null ) { 315 list = addNestedLayers( ll[j].getLayer(), styleName, list ); 316 } 317 318 } 319 return list; 320 } 321 322 /** 323 * throws an exception if the requested SRS is not be supported by the passed layer (name) 324 * 325 * @param srs 326 * @param name 327 * @throws InvalidSRSException 328 */ 329 private void validateSRS( String[] srs, String name ) 330 throws InvalidSRSException { 331 boolean validSRS = false; 332 for ( int k = 0; k < srs.length; k++ ) { 333 validSRS = srs[k].equalsIgnoreCase( reqCRS.getIdentifier() ); 334 if ( validSRS ) 335 break; 336 } 337 if ( !validSRS ) { 338 String s = Messages.getMessage( "WMS_UNKNOWN_CRS_FOR_LAYER", reqCRS.getIdentifier(), name ); 339 throw new InvalidSRSException( s ); 340 } 341 } 342 343 private void invokeNamedLayer( AbstractLayer layer, String styleName, List<Callable<Object>> tasks ) 344 throws OGCWebServiceException { 345 346 org.deegree.ogcwebservices.wms.capabilities.Layer lay = configuration.getLayer( layer.getName() ); 347 348 LOG.logDebug( "Invoked layer " + layer.getName() ); 349 350 if ( validate( lay, layer.getName() ) ) { 351 352 UserStyle us = getStyles( (NamedLayer) layer, styleName ); 353 AbstractDataSource[] ds = lay.getDataSource(); 354 355 if ( ds.length == 0 ) { 356 LOG.logDebug( "No datasources for layer " + layer.getName() ); 357 } else { 358 for ( int j = 0; j < ds.length; j++ ) { 359 360 LOG.logDebug( "Invoked datasource " + ds[j].getClass() + " for layer " + layer.getName() ); 361 362 ScaleHint scaleHint = ds[j].getScaleHint(); 363 if ( scale >= scaleHint.getMin() && scale < scaleHint.getMax() 364 && isValidArea( ds[j].getValidArea() ) ) { 365 double sc = scale; 366 if ( !version130 ) { 367 // required because for WMS 1.3.0 'scale' represents the 368 // ScaleDenominator 369 // and for WMS < 1.3.0 it represents the size of a pixel diagonal in 370 // meter 371 sc = scale / MapUtils.DEFAULT_PIXEL_SIZE; 372 } 373 374 GetMapServiceInvokerForNL si = new GetMapServiceInvokerForNL( this, (NamedLayer) layer, ds[j], 375 us, sc ); 376 tasks.add( si ); 377 } else { 378 LOG.logDebug( "Not showing layer " + layer.getName() + " due to scale" ); 379 } 380 } 381 } 382 } 383 } 384 385 /** 386 * returns true if the requested boundingbox intersects with the valid area of a datasource 387 * 388 * @param validArea 389 */ 390 private boolean isValidArea( Geometry validArea ) { 391 392 if ( validArea != null ) { 393 try { 394 Envelope env = request.getBoundingBox(); 395 Geometry geom = GeometryFactory.createSurface( env, reqCRS ); 396 if ( !reqCRS.getIdentifier().equals( validArea.getCoordinateSystem().getIdentifier() ) ) { 397 // if requested CRS is not identical to the CRS of the valid area 398 // a transformation must be performed before intersection can 399 // be checked 400 GeoTransformer gt = new GeoTransformer( validArea.getCoordinateSystem() ); 401 geom = gt.transform( geom ); 402 } 403 return geom.intersects( validArea ); 404 } catch ( Exception e ) { 405 // should never happen 406 LOG.logError( "Could not validate WMS datasource area", e ); 407 } 408 } 409 return true; 410 } 411 412 /** 413 * creates a StyledLayerDocument containing all requested layer, nested layers if required and 414 * assigend styles. Not considered are nested layers for mixed requests (LAYERS- and SLD(_BODY)- 415 * parameter has been defined) 416 * 417 * @param layers 418 * @param inSLD 419 * @return a combined SLD object 420 * @throws InvalidSRSException 421 */ 422 private StyledLayerDescriptor toSLD( GetMap.Layer[] layers, StyledLayerDescriptor inSLD ) 423 throws InvalidSRSException { 424 StyledLayerDescriptor sld = null; 425 426 if ( layers != null && layers.length > 0 && inSLD == null ) { 427 // if just a list of layers has been requested 428 429 // create a SLD from the requested LAYERS and assigned STYLES 430 List<AbstractLayer> al = new ArrayList<AbstractLayer>( layers.length * 2 ); 431 for ( int i = 0; i < layers.length; i++ ) { 432 AbstractStyle[] as = new AbstractStyle[] { new NamedStyle( layers[i].getStyleName() ) }; 433 al.add( new NamedLayer( layers[i].getName(), null, as ) ); 434 435 // collect all named nested layers 436 org.deegree.ogcwebservices.wms.capabilities.Layer lla; 437 lla = configuration.getLayer( layers[i].getName() ); 438 List<GetMap.Layer> list = new ArrayList<GetMap.Layer>(); 439 addNestedLayers( lla.getLayer(), layers[i].getStyleName(), list ); 440 441 // add nested layers to list of layers to be handled 442 for ( int j = 0; j < list.size(); j++ ) { 443 GetMap.Layer nestedLayer = list.get( j ); 444 as = new AbstractStyle[] { new NamedStyle( nestedLayer.getStyleName() ) }; 445 al.add( new NamedLayer( nestedLayer.getName(), null, as ) ); 446 } 447 } 448 sld = new StyledLayerDescriptor( al.toArray( new AbstractLayer[al.size()] ), "1.0.0" ); 449 } else if ( layers != null && layers.length > 0 && inSLD != null ) { 450 // if layers not null and sld is not null then SLD layers just be 451 // considered if present in the layers list 452 // TODO 453 // layer with nested layers are not handled correctly and I think 454 // it really causes a lot of problems to use them in such a way 455 // because the style assigned to the mesting layer must be 456 // applicable for all nested layers. 457 List<String> list = new ArrayList<String>(); 458 for ( int i = 0; i < layers.length; i++ ) { 459 list.add( layers[i].getName() ); 460 } 461 462 List<AbstractLayer> newList = new ArrayList<AbstractLayer>( 20 ); 463 AbstractLayer[] al = inSLD.getLayers(); 464 for ( int i = 0; i < al.length; i++ ) { 465 if ( list.contains( al[i].getName() ) ) { 466 newList.add( al[i] ); 467 } 468 } 469 al = new AbstractLayer[newList.size()]; 470 sld = new StyledLayerDescriptor( newList.toArray( al ), inSLD.getVersion() ); 471 472 // add nested layers for mixed case, nested from original sld 473 AbstractLayer[] as = inSLD.getLayers(); 474 for ( AbstractLayer l : as ) { 475 addNestedLayers( l, sld ); 476 } 477 } else { 478 // if no layers but a SLD is defined ... 479 AbstractLayer[] as = inSLD.getLayers(); 480 for ( AbstractLayer l : as ) { 481 addNestedLayers( l, inSLD ); 482 } 483 484 sld = inSLD; 485 } 486 487 return sld; 488 } 489 490 // adds the nested layers to the sld 491 private void addNestedLayers( AbstractLayer l, StyledLayerDescriptor sld ) { 492 if ( !( l instanceof NamedLayer ) ) { 493 return; 494 } 495 if ( configuration.getLayer( l.getName() ) == null ) { 496 return; 497 } 498 499 org.deegree.ogcwebservices.wms.capabilities.Layer[] ls; 500 ls = configuration.getLayer( l.getName() ).getLayer(); 501 for ( org.deegree.ogcwebservices.wms.capabilities.Layer lay : ls ) { 502 NamedStyle sty = new NamedStyle( lay.getStyles()[0].getName() ); 503 AbstractStyle[] newSty = new AbstractStyle[] { sty }; 504 NamedLayer newLay = new NamedLayer( lay.getName(), null, newSty ); 505 sld.addLayer( newLay ); 506 } 507 } 508 509 /** 510 * returns the <tt>UserStyle</tt>s assigned to a named layer 511 * 512 * @param sldLayer 513 * layer to get the styles for 514 * @param styleName 515 * requested stylename (from the KVP encoding) 516 */ 517 private UserStyle getStyles( NamedLayer sldLayer, String styleName ) 518 throws OGCWebServiceException { 519 520 AbstractStyle[] styles = sldLayer.getStyles(); 521 UserStyle us = null; 522 523 // to avoid retrieving the layer again for each style 524 org.deegree.ogcwebservices.wms.capabilities.Layer layer = null; 525 layer = configuration.getLayer( sldLayer.getName() ); 526 int i = 0; 527 while ( us == null && i < styles.length ) { 528 if ( styles[i] instanceof NamedStyle ) { 529 // styles will be taken from the WMS's style repository 530 us = getPredefinedStyle( styles[i].getName(), sldLayer.getName(), layer ); 531 } else { 532 // if the requested style fits the name of the defined style or 533 // if the defined style is marked as default and the requested 534 // style if 'default' the condition is true. This includes that 535 // if more than one style with the same name or more than one 536 // style is marked as default always the first will be choosen 537 if ( styleName == null || ( styles[i].getName() != null && styles[i].getName().equals( styleName ) ) 538 || ( styleName.equalsIgnoreCase( "$DEFAULT" ) && ( (UserStyle) styles[i] ).isDefault() ) ) { 539 us = (UserStyle) styles[i]; 540 } 541 } 542 i++; 543 } 544 if ( us == null ) { 545 // this may happens if the SLD contains a named layer but not 546 // a style! yes this is valid according to SLD spec 1.0.0 547 us = getPredefinedStyle( styleName, sldLayer.getName(), layer ); 548 } 549 return us; 550 } 551 552 /** 553 * 554 * @param styleName 555 * @param layerName 556 * @param layer 557 * @return the style 558 * @throws StyleNotDefinedException 559 */ 560 private UserStyle getPredefinedStyle( String styleName, String layerName, 561 org.deegree.ogcwebservices.wms.capabilities.Layer layer ) 562 throws StyleNotDefinedException { 563 UserStyle us = null; 564 if ( "default".equals( styleName ) ) { 565 us = layer.getStyle( styleName ); 566 } 567 568 if ( us == null ) { 569 if ( styleName == null || styleName.length() == 0 || styleName.equals( "$DEFAULT" ) 570 || styleName.equals( "default" ) ) { 571 styleName = "default:" + layerName; 572 } 573 } 574 575 us = layer.getStyle( styleName ); 576 577 if ( us == null && !( styleName.startsWith( "default" ) ) && !( styleName.startsWith( "$DEFAULT" ) ) ) { 578 String s = Messages.getMessage( "WMS_STYLENOTDEFINED", styleName, layer ); 579 throw new StyleNotDefinedException( s ); 580 } 581 return us; 582 } 583 584 /** 585 * validates if the requested layer matches the conditions of the request if not a 586 * <tt>WebServiceException</tt> will be thrown. If the layer matches the request, but isn't 587 * able to deviever data for the requested area and/or scale false will be returned. If the 588 * layer matches the request and contains data for the requested area and/or scale true will be 589 * returned. 590 * 591 * @param layer 592 * layer as defined at the capabilities/configuration 593 * @param name 594 * name of the layer (must be submitted seperatly because the layer parameter can be 595 * <tt>null</tt> 596 */ 597 private boolean validate( org.deegree.ogcwebservices.wms.capabilities.Layer layer, String name ) 598 throws OGCWebServiceException { 599 600 // check if layer is available 601 if ( layer == null ) { 602 throw new LayerNotDefinedException( Messages.getMessage( "WMS_UNKNOWNLAYER", name ) ); 603 } 604 605 // check bounding box 606 try { 607 Envelope bbox = request.getBoundingBox(); 608 Envelope layerBbox = layer.getLatLonBoundingBox(); 609 if ( !request.getSrs().equalsIgnoreCase( "EPSG:4326" ) ) { 610 // transform the bounding box of the request to EPSG:4326 611 GeoTransformer gt = new GeoTransformer( CRSFactory.create( "epsg:4326" ) ); 612 bbox = gt.transform( bbox, reqCRS ); 613 } 614 if ( !bbox.intersects( layerBbox ) ) { 615 LOG.logDebug( "Not showing layer because the request is out of the bounding box." ); 616 return false; 617 } 618 619 } catch ( Exception e ) { 620 LOG.logError( e.getMessage(), e ); 621 throw new OGCWebServiceException( Messages.getMessage( "WMS_BBOXCOMPARSION" ) ); 622 } 623 624 return true; 625 } 626 627 /** 628 * renders the map from the <tt>DisplayElement</tt>s 629 */ 630 private GetMapResult renderMap( List<ExecutionFinishedEvent<Object>> results ) { 631 632 GetMapResult response = null; 633 OGCWebServiceException exce = null; 634 635 ArrayList<Object> list = new ArrayList<Object>( 50 ); 636 for ( ExecutionFinishedEvent<Object> evt : results ) { 637 Object o = null; 638 639 // exception handling might be handled in a better way 640 try { 641 o = evt.getResult(); 642 } catch ( CancellationException e ) { 643 exce = new OGCWebServiceException( getClass().getName(), e.toString() ); 644 } catch ( Throwable e ) { 645 exce = new OGCWebServiceException( getClass().getName(), e.toString() ); 646 } 647 648 if ( o instanceof Exception ) { 649 exce = new OGCWebServiceException( getClass().getName(), o.toString() ); 650 } 651 if ( o instanceof OGCWebServiceException ) { 652 exce = (OGCWebServiceException) o; 653 break; 654 } 655 if ( o != null ) { 656 list.add( o ); 657 } 658 } 659 660 String mime = MimeTypeMapper.toMimeType( request.getFormat() ); 661 662 // get target object for rendering 663 Object target = GraphicContextFactory.createGraphicTarget( mime, request.getWidth(), request.getHeight() ); 664 665 // get graphic context of the target 666 Graphics g = GraphicContextFactory.createGraphicContext( mime, target ); 667 if ( exce == null ) { 668 // only if no exception occured 669 try { 670 Theme[] th = list.toArray( new Theme[list.size()] ); 671 org.deegree.graphics.MapView map = null; 672 if ( th.length > 0 ) { 673 map = MapFactory.createMapView( "deegree WMS", request.getBoundingBox(), reqCRS, th, 674 MapUtils.DEFAULT_PIXEL_SIZE ); 675 } 676 g.setClip( 0, 0, request.getWidth(), request.getHeight() ); 677 678 if ( !request.getTransparency() ) { 679 if ( g instanceof Graphics2D ) { 680 // this ensures real clearing (rendering modifies the color ever so 681 // slightly) 682 ( (Graphics2D) g ).setBackground( request.getBGColor() ); 683 g.clearRect( 0, 0, request.getWidth(), request.getHeight() ); 684 } else { 685 g.setColor( request.getBGColor() ); 686 g.fillRect( 0, 0, request.getWidth(), request.getHeight() ); 687 } 688 } 689 690 if ( map != null ) { 691 Theme[] thms = map.getAllThemes(); 692 map.addOptimizer( new LabelOptimizer( thms ) ); 693 // antialiasing must be switched of for gif output format 694 // because the antialiasing may create more than 255 colors 695 // in the map/image, even just a few colors are defined in 696 // the styles 697 if ( !request.getFormat().equalsIgnoreCase( "image/gif" ) ) { 698 if ( configuration.getDeegreeParams().isAntiAliased() ) { 699 ( (Graphics2D) g ).setRenderingHint( RenderingHints.KEY_ANTIALIASING, 700 RenderingHints.VALUE_ANTIALIAS_ON ); 701 ( (Graphics2D) g ).setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, 702 RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); 703 } 704 } 705 map.paint( g ); 706 } 707 } catch ( Exception e ) { 708 LOG.logError( e.getMessage(), e ); 709 exce = new OGCWebServiceException( "GetMapHandler_Impl: renderMap", e.toString() ); 710 } 711 } 712 713 // print a copyright note at the left lower corner of the map 714 printCopyright( g, request.getHeight() ); 715 716 if ( mime.equals( "image/svg+xml" ) || mime.equals( "image/svg xml" ) ) { 717 Element root = ( (SVGGraphics2D) g ).getRoot(); 718 root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" ); 719 response = WMSProtocolFactory.createGetMapResponse( request, exce, root ); 720 } else { 721 response = WMSProtocolFactory.createGetMapResponse( request, exce, target ); 722 } 723 g.dispose(); 724 725 return response; 726 } 727 728 /** 729 * prints a copyright note at left side of the map bottom. The copyright note will be extracted 730 * from the WMS capabilities/configuration 731 * 732 * @param g 733 * graphic context of the map 734 * @param heigth 735 * height of the map in pixel 736 */ 737 private void printCopyright( Graphics g, int heigth ) { 738 WMSDeegreeParams dp = configuration.getDeegreeParams(); 739 String copyright = dp.getCopyRight(); 740 if ( copyrightImg != null ) { 741 g.drawImage( copyrightImg, 8, heigth - copyrightImg.getHeight() - 5, null ); 742 } else { 743 if ( copyright != null ) { 744 g.setFont( new Font( "SANSSERIF", Font.PLAIN, 14 ) ); 745 g.setColor( Color.BLACK ); 746 g.drawString( copyright, 8, heigth - 15 ); 747 g.drawString( copyright, 10, heigth - 15 ); 748 g.drawString( copyright, 8, heigth - 13 ); 749 g.drawString( copyright, 10, heigth - 13 ); 750 g.setColor( Color.WHITE ); 751 g.setFont( new Font( "SANSSERIF", Font.PLAIN, 14 ) ); 752 g.drawString( copyright, 9, heigth - 14 ); 753 } 754 } 755 756 } 757 758 /** 759 * @return the request that is being handled 760 */ 761 protected GetMap getRequest() { 762 return request; 763 } 764 765 /** 766 * @return the requests coordinate system 767 */ 768 protected CoordinateSystem getRequestCRS() { 769 return reqCRS; 770 } 771 772 }