001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/portal/standard/wms/control/DynLegendListener.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 package org.deegree.portal.standard.wms.control; 037 038 import static org.deegree.enterprise.WebUtils.enableProxyUsage; 039 040 import java.awt.Color; 041 import java.awt.Graphics; 042 import java.awt.Rectangle; 043 import java.awt.geom.Rectangle2D; 044 import java.awt.image.BufferedImage; 045 import java.io.File; 046 import java.io.FileOutputStream; 047 import java.io.IOException; 048 import java.io.InputStreamReader; 049 import java.net.MalformedURLException; 050 import java.net.URL; 051 import java.util.ArrayList; 052 import java.util.HashMap; 053 import java.util.Iterator; 054 import java.util.List; 055 import java.util.Map; 056 import java.util.Properties; 057 import java.util.StringTokenizer; 058 import java.util.UUID; 059 060 import javax.servlet.http.HttpServletRequest; 061 import javax.servlet.http.HttpSession; 062 063 import org.apache.commons.httpclient.HttpClient; 064 import org.apache.commons.httpclient.methods.GetMethod; 065 import org.deegree.datatypes.QualifiedName; 066 import org.deegree.enterprise.control.FormEvent; 067 import org.deegree.enterprise.control.RPCMember; 068 import org.deegree.enterprise.control.RPCMethodCall; 069 import org.deegree.enterprise.control.RPCParameter; 070 import org.deegree.enterprise.control.RPCStruct; 071 import org.deegree.enterprise.control.RPCWebEvent; 072 import org.deegree.framework.log.ILogger; 073 import org.deegree.framework.log.LoggerFactory; 074 import org.deegree.framework.util.IDGenerator; 075 import org.deegree.framework.util.ImageUtils; 076 import org.deegree.framework.util.StringTools; 077 import org.deegree.framework.xml.XMLFragment; 078 import org.deegree.ogcbase.ImageURL; 079 import org.deegree.ogcwebservices.InconsistentRequestException; 080 import org.deegree.ogcwebservices.wms.capabilities.LegendURL; 081 import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities; 082 import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument; 083 import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory; 084 import org.deegree.ogcwebservices.wms.operation.GetLegendGraphic; 085 import org.deegree.ogcwebservices.wms.operation.GetMap; 086 import org.deegree.owscommon_new.HTTP; 087 import org.deegree.owscommon_new.Operation; 088 import org.deegree.portal.Constants; 089 import org.deegree.portal.context.GeneralExtension; 090 import org.deegree.portal.context.IOSettings; 091 import org.deegree.portal.context.Layer; 092 import org.deegree.portal.context.LayerList; 093 import org.deegree.portal.context.ViewContext; 094 095 /** 096 * Will be called if the client forces a dynamic legend. There are two different ways of retreiving the legend for each 097 * layer: 098 * 099 * First, we try to get the legend from the layer information in the WMC. 100 * 101 * Second, we try to get the legend from the WMS serving this layer: It is attempted to get the legend url from style 102 * info in the WMS Capabilities, first with the passed style info, second for the default style, third for the only 103 * available style. (If the WMS capabilities holds more than one style, but no style was passed with the layer info, 104 * then one cannot know "the right style". Therefore no style is taken from WMS capabilities, in this case.) Then, it is 105 * attempted to get the legend image from a GetLegendGraphics request, if the WMS capabilities state, that this request 106 * is supported by the WMS. 107 * 108 * If this all fails, the missingImage is taken if defined in init params. 109 * 110 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 111 * @author last edited by: $Author: mays$ 112 * 113 * @version $Revision: 27568 $, $Date: 2010-10-28 08:49:01 +0200 (Do, 28 Okt 2010) $ 114 */ 115 public class DynLegendListener extends AbstractMapListener { 116 117 private static final ILogger LOG = LoggerFactory.getLogger( DynLegendListener.class ); 118 119 private int leftMargin = 15; 120 121 private int rightMargin = 15; 122 123 private int topMargin = 20; 124 125 private int bottomMargin = 20; 126 127 private boolean useLayerTitle = true; 128 129 private BufferedImage separator; 130 131 private BufferedImage missingImg; 132 133 private static Map<String, Object> wmscache = new HashMap<String, Object>(); 134 135 private static Map<String, BufferedImage> legendSymCache = new HashMap<String, BufferedImage>(); 136 137 private List<String> missing = null; 138 139 private int maxNNLegendSize = 50; 140 141 private Properties userNames = new Properties(); 142 143 private Properties passwords = new Properties(); 144 145 /* 146 * (non-Javadoc) 147 * 148 * @see 149 * org.deegree.portal.standard.wms.control.AbstractMapListener#actionPerformed(org.deegree.enterprise.control.FormEvent 150 * ) 151 */ 152 @Override 153 public void actionPerformed( FormEvent event ) { 154 155 super.actionPerformed( event ); 156 missing = new ArrayList<String>(); 157 158 try { 159 init(); 160 } catch ( IOException e ) { 161 LOG.logError( "Error occurred initializing DynLegendListener: ", e ); 162 gotoErrorPage( "Error occurred initializing DynLegendListener: " + e ); 163 } 164 165 RPCWebEvent rpc = (RPCWebEvent) event; 166 RPCMethodCall mc = rpc.getRPCMethodCall(); 167 RPCParameter[] para = mc.getParameters(); 168 RPCStruct struct = (RPCStruct) para[0].getValue(); 169 HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession(); 170 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT ); 171 172 // check if at least one layer is visible 173 Layer[] layers = vc.getLayerList().getLayers(); 174 boolean required = false; 175 for ( Layer layer : layers ) { 176 if ( !layer.isHidden() ) { 177 required = true; 178 break; 179 } 180 } 181 // if no layer is visible send an empty image 182 if ( !required ) { 183 BufferedImage bi = new BufferedImage( 1, 1, BufferedImage.TYPE_INT_RGB ); 184 saveImage( vc, bi ); 185 getRequest().setAttribute( "LEGENDWIDTH", String.valueOf( bi.getWidth() ) ); 186 getRequest().setAttribute( "LEGENDHEIGHT", String.valueOf( bi.getHeight() ) ); 187 return; 188 } 189 190 HashMap<String, String>[] model = createWMSRequestModel( struct ); 191 192 try { 193 GetLegendGraphic legendParam = getLegendRequestParameter(); 194 HashMap<String, Object> symbols = (HashMap<String, Object>) readLegendSymbols( legendParam, model, vc ); 195 Rectangle rect = calcLegendSize( symbols ); 196 BufferedImage bi = new BufferedImage( rect.width + leftMargin + rightMargin, rect.height + topMargin 197 + bottomMargin, 198 BufferedImage.TYPE_INT_RGB ); 199 Color color = Color.decode( (String) struct.getMember( "bgColor" ).getValue() ); 200 bi = drawSymbolsToBI( symbols, bi, color ); 201 saveImage( vc, bi ); 202 203 getRequest().setAttribute( "LEGENDWIDTH", String.valueOf( bi.getWidth() ) ); 204 getRequest().setAttribute( "LEGENDHEIGHT", String.valueOf( bi.getHeight() ) ); 205 } catch ( Exception e ) { 206 LOG.logError( "Error occurred in DynLegendListener: ", e ); 207 gotoErrorPage( "Error occurred in DynLegendListener: " + e ); 208 } 209 210 } 211 212 /** 213 * Reads the initParams from the controller.xml and assigns them to the global variables 214 * 215 * @throws IOException 216 */ 217 private void init() 218 throws IOException { 219 String path = null; 220 221 String tmp = getInitParameter( "leftMargin" ); 222 if ( tmp != null ) { 223 leftMargin = Integer.parseInt( tmp ); 224 } 225 tmp = getInitParameter( "rightMargin" ); 226 if ( tmp != null ) { 227 rightMargin = Integer.parseInt( tmp ); 228 } 229 tmp = getInitParameter( "topMargin" ); 230 if ( tmp != null ) { 231 topMargin = Integer.parseInt( tmp ); 232 } 233 tmp = getInitParameter( "bottomMargin" ); 234 if ( tmp != null ) { 235 bottomMargin = Integer.parseInt( tmp ); 236 } 237 tmp = getInitParameter( "useLayerTitle" ); 238 useLayerTitle = "true".equalsIgnoreCase( tmp ); 239 240 tmp = getInitParameter( "separator" ); 241 if ( tmp != null ) { 242 path = StringTools.concat( 200, getHomePath(), tmp ); 243 LOG.logDebug( "PATH = ", path ); 244 separator = ImageUtils.loadImage( path ); 245 } 246 247 tmp = getInitParameter( "missingImage" ); 248 if ( tmp != null ) { 249 path = StringTools.concat( 200, getHomePath(), tmp ); 250 LOG.logDebug( "PATH = ", path ); 251 try { 252 missingImg = ImageUtils.loadImage( path ); 253 } catch ( Exception e ) { 254 LOG.logError( e.getLocalizedMessage() ); 255 missingImg = new BufferedImage( 10, 10, BufferedImage.TYPE_INT_ARGB ); 256 } 257 } else { 258 missingImg = new BufferedImage( 10, 10, BufferedImage.TYPE_INT_ARGB ); 259 } 260 tmp = getInitParameter( "maxNNLegendSize" ); 261 if ( tmp != null ) { 262 maxNNLegendSize = Integer.parseInt( tmp ); 263 } 264 tmp = getInitParameter( "users" ); 265 if ( tmp != null ) { 266 String[] t = StringTools.toArray( tmp, ";|", false ); 267 for ( int i = 0; i < t.length; i += 3 ) { 268 userNames.put( t[i], t[i + 1] ); 269 passwords.put( t[i], t[i + 2] ); 270 } 271 } 272 } 273 274 /** 275 * takes in a HashMap holding the properties of the legend and returns the size of the legend to be 276 * 277 * @param map 278 * Hashmap holding the GetLegendGraphic properties 279 * @return A rectangle holding the legend size 280 */ 281 private Rectangle calcLegendSize( HashMap<String, Object> map ) { 282 283 String[] layers = (String[]) map.get( "NAMES" ); 284 String[] titles = (String[]) map.get( "TITLES" ); 285 BufferedImage[] legs = (BufferedImage[]) map.get( "IMAGES" ); 286 287 int w = 0; 288 int h = 0; 289 for ( int i = 0; i < layers.length; i++ ) { 290 h += legs[i].getHeight() + 5; 291 if ( separator != null && i < layers.length - 1 ) { 292 h += separator.getHeight() + 5; 293 } 294 Graphics g = legs[i].getGraphics(); 295 if ( useLayerTitle && legs[i].getHeight() < maxNNLegendSize && !missing.contains( layers[i] ) ) { 296 Rectangle2D rect = g.getFontMetrics().getStringBounds( titles[i], g ); 297 g.dispose(); 298 if ( ( rect.getWidth() + legs[i].getWidth() ) > w ) { 299 w = (int) rect.getWidth() + legs[i].getWidth(); 300 } 301 } else { 302 if ( legs[i].getWidth() > w ) { 303 w = legs[i].getWidth(); 304 } 305 } 306 } 307 // w += 20; 308 309 return new Rectangle( w, h ); 310 } 311 312 /** 313 * Draws the given symbol to the given image 314 * 315 * @param map 316 * Hashmap holding the properties of the legend 317 * @param bi 318 * image of the legend 319 * @param color 320 * color to fill the graphic 321 * @return The drawn BufferedImage 322 */ 323 private BufferedImage drawSymbolsToBI( HashMap<String, Object> map, BufferedImage bi, Color color ) { 324 325 Graphics g = bi.getGraphics(); 326 g.setColor( color ); 327 g.fillRect( 0, 0, bi.getWidth(), bi.getHeight() ); 328 329 String[] layers = (String[]) map.get( "NAMES" ); 330 String[] titles = (String[]) map.get( "TITLES" ); 331 BufferedImage[] legs = (BufferedImage[]) map.get( "IMAGES" ); 332 int h = topMargin; 333 for ( int i = layers.length - 1; i >= 0; i-- ) { 334 g.drawImage( legs[i], leftMargin, h, null ); 335 g.setColor( Color.BLACK ); 336 // just draw title if the flag has been set in listener configuration, 337 // the legend image is less than a defined value and a legend image 338 // (not missing) has been accessed 339 if ( useLayerTitle && legs[i].getHeight() < maxNNLegendSize && !missing.contains( layers[i] ) ) { 340 g.drawString( titles[i], leftMargin + legs[i].getWidth() + 10, h + (int) ( legs[i].getHeight() / 1.2 ) ); 341 } 342 h += legs[i].getHeight() + 5; 343 if ( separator != null && i > 0 ) { 344 g.drawImage( separator, leftMargin, h, null ); 345 h += separator.getHeight() + 5; 346 } 347 } 348 g.dispose(); 349 return bi; 350 } 351 352 /** 353 * Receives an RPCStruct(WMSRequest) and extracts all its properties to a HashMap 354 * 355 * @param struct 356 * @return a HashMap contains the WMSRequest properties 357 */ 358 @SuppressWarnings("unchecked") 359 private HashMap<String, String>[] createWMSRequestModel( RPCStruct struct ) { 360 RPCMember[] member = struct.getMembers(); 361 String request = ""; 362 List<Map<String, String>> list = new ArrayList<Map<String, String>>( member.length - 1 ); 363 for ( int i = 0; i < member.length; i++ ) { 364 if ( !member[i].getName().equals( "bgColor" ) && !member[i].getName().equals( "sessionID" ) ) { 365 request = (String) member[i].getValue(); 366 LOG.logDebug( "request = ", request ); 367 Map<String, String> map = toMap( request ); 368 StringTokenizer st = new StringTokenizer( request, "?" ); 369 GetMap gm = null; 370 try { 371 map.put( "ID", UUID.randomUUID().toString() ); 372 gm = GetMap.create( map ); 373 map = toMap( request ); 374 } catch ( Exception e ) { 375 e.printStackTrace(); 376 } 377 StringBuilder sb = new StringBuilder(); 378 sb.append( st.nextToken() ).append( '?' ); 379 Map<String, String> vp = gm.getVendorSpecificParameters(); 380 Iterator<String> iter = vp.keySet().iterator(); 381 while ( iter.hasNext() ) { 382 String key = (String) iter.next(); 383 sb.append( key ).append( "=" ).append( vp.get( key ) ).append( '&' ); 384 } 385 LOG.logDebug( "base URL = ", sb ); 386 map.put( "URL", sb.toString() ); 387 list.add( map ); 388 } 389 } 390 HashMap<String, String>[] getMR = new HashMap[list.size()]; 391 return list.toArray( getMR ); 392 } 393 394 /** 395 * Saves the given image to the print/images directory of the given ViewContext 396 * 397 * @param vc 398 * @param bg 399 */ 400 private void saveImage( ViewContext vc, BufferedImage bg ) { 401 402 GeneralExtension ge = vc.getGeneral().getExtension(); 403 IOSettings ios = ge.getIOSettings(); 404 String dir = ios.getPrintDirectory().getDirectoryName(); 405 String format = "png"; 406 long l = IDGenerator.getInstance().generateUniqueID(); 407 String file = StringTools.concat( 50, "legend", l, ".", format ); 408 int pos = dir.lastIndexOf( '/' ); 409 String access = StringTools.concat( 100, "./", dir.substring( pos + 1, dir.length() ), "/", file ); 410 411 String temp = StringTools.concat( 100, "legend", ( l - 50 ), ".", format ); 412 File f = new File( StringTools.concat( 100, "./", dir.substring( pos + 1, dir.length() ), "/", temp ) ); 413 try { 414 if ( f.exists() ) { 415 f.delete(); 416 } 417 } catch ( Exception e ) { 418 if ( LOG.getLevel() == ILogger.LOG_ERROR ) { 419 LOG.logError( StringTools.concat( 100, "The temporary image file: ", f.getPath(), 420 " could not be deleted" ) ); 421 } 422 } 423 try { 424 String path = new String( StringTools.concat( 100, dir, "/", file ) ); 425 if ( path.startsWith( "file:/" ) ) { 426 path = new URL( path ).getFile(); 427 } 428 FileOutputStream fos = new FileOutputStream( new File( path ) ); 429 ImageUtils.saveImage( bg, fos, format, 1 ); 430 fos.close(); 431 432 } catch ( Exception e ) { 433 LOG.logError( "Error occurred in saving legend image: ", e ); 434 } 435 this.getRequest().setAttribute( "LEGENDURL", access ); 436 437 } 438 439 /** 440 * Creates a GetLegendGraphic Request 441 * 442 * @return An instance of GetLegendGraphic 443 * @throws InconsistentRequestException 444 */ 445 private GetLegendGraphic getLegendRequestParameter() 446 throws InconsistentRequestException { 447 448 HashMap<String, String> legend = toMap( "VERSION=1.1.1&REQUEST=GetLegendGraphic&FORMAT=image/png&WIDTH=50&HEIGHT=50&" 449 + "EXCEPTIONS=application/vnd.ogc.se_inimage&LAYER=europe:major_rivers&STYLE=default" ); 450 451 GetLegendGraphic legendReq = GetLegendGraphic.create( legend ); 452 453 return legendReq; 454 } 455 456 /** 457 * Creates legend symbols and stores them in a hashmap through the given params 458 * 459 * There are two different ways of retreiving the legend. First, we try to get the legend from the layer information 460 * in the WMC. Second, we try to get the legend from the WMS serving this layer. 461 * 462 * If both fails, the missingImage as defined in init params is taken. 463 * 464 * @param glr 465 * @param model 466 * A HashMap holding the Request params (with URL holding the service address itself) 467 * @param vc 468 * Current layer list 469 * @return A HashMap holding the legend symbols as read from the cash 470 * @throws IOException 471 */ 472 private Map<String, Object> readLegendSymbols( GetLegendGraphic glr, HashMap<String, String>[] model, ViewContext vc ) 473 throws IOException { 474 475 ArrayList<String> list1 = new ArrayList<String>(); 476 ArrayList<BufferedImage> list2 = new ArrayList<BufferedImage>(); 477 ArrayList<String> list3 = new ArrayList<String>(); 478 479 LayerList ll = vc.getLayerList(); 480 481 StringTokenizer st = null; 482 String format = glr.getFormat(); 483 if ( format.equals( "image/jpg" ) ) { 484 format = "image/jpeg"; 485 } 486 487 int lgHeight = 0; 488 for ( int i = 0; i < model.length; i++ ) { 489 if ( model[i].get( "LAYERS" ) != null ) { 490 String style = (String) model[i].get( "STYLES" ); 491 String[] styles = new String[100]; 492 if ( style != null ) { 493 style = StringTools.replace( style, ",,", ",default,", true ); 494 if ( style.startsWith( "," ) ) { 495 style = "default" + style; 496 } 497 if ( style.endsWith( "," ) ) { 498 style = style + "default"; 499 } 500 styles = StringTools.toArray( style, ",", false ); 501 } 502 503 // read capabilities for current service (URL) or - if avalable - 504 // read it from the cache 505 String addr = (String) model[i].get( "URL" ); 506 if ( wmscache.get( addr ) == null ) { 507 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 508 LOG.logDebug( StringTools.concat( 200, "Adding the caps of ", addr, " to the hash map" ) ); 509 } 510 wmscache.put( addr, getCapabilities( addr, (String) model[i].get( "VERSION" ) ) ); 511 } else { 512 LOG.logDebug( "read capabilities from cache" ); 513 514 } 515 LOG.logDebug( "caps ", addr ); 516 WMSCapabilities capa = (WMSCapabilities) wmscache.get( addr ); 517 518 st = new StringTokenizer( (String) model[i].get( "LAYERS" ), "," ); 519 int k = 0; 520 while ( st.hasMoreTokens() ) { 521 if ( styles == null || styles.length == 0 || styles[k] == null || styles[k].equals( "" ) ) { 522 style = "default"; 523 } else { 524 style = styles[k]; 525 } 526 k++; 527 528 String layer = st.nextToken(); 529 String title = layer; 530 if ( capa.getLayer( layer ) != null ) { 531 title = capa.getLayer( layer ).getTitle(); 532 } 533 534 BufferedImage legendGraphic = null; 535 String path = StringTools.concat( 200, addr, "%%", layer, "%%", style ); 536 if ( legendSymCache.get( path ) != null ) { 537 legendGraphic = legendSymCache.get( path ); 538 LOG.logDebug( "read legendsymbol from cache for ", layer ); 539 } else { 540 // first attempt to get legend image: access layer from WMC. 541 // (If current WMC does not offer a layer named like the passed name, the layer 542 // may have been added dynamically => see second attempt further below.) 543 LOG.logDebug( "legendURL for layer", layer, " from ", addr ); 544 Layer lay = ll.getLayer( layer, addr ); 545 if ( lay == null ) { 546 LOG.logWarning( "layer '" + layer + "' not found in layer list" ); 547 } 548 ImageURL imgUrl = null; 549 URL url = null; 550 if ( lay != null && lay.getStyleList() != null && lay.getStyleList().getStyle( style ) != null 551 && ( imgUrl = lay.getStyleList().getStyle( style ).getLegendURL() ) != null ) { 552 LOG.logDebug( "An image url could be fetched from WMC" ); 553 url = imgUrl.getOnlineResource(); 554 } else { 555 LOG.logDebug( "No url found from WMC for layer ", layer ); 556 } 557 558 lgHeight = lgHeight + 30; 559 560 if ( url != null ) { 561 LOG.logDebug( "URL is valid. Loading Legend Graphic..." ); 562 LOG.logDebug( "ImgUrl is: ", url.toExternalForm() ); 563 // TODO catch error from loadImage, but also log the error message. 564 // error might occure, if configuration is wrong. 565 // (trying to read from a not existing feature) 566 try { 567 legendGraphic = ImageUtils.loadImage( url ); 568 } catch ( Exception e ) { 569 // nothing to do 570 } 571 } 572 573 // second attempt to get legend image: necessary if layer has been added dynamically. 574 if ( legendGraphic == null ) { 575 LOG.logDebug( "SECOND ATTEMPT for the legend image, because layer was not in WMC LayerList" ); 576 legendGraphic = createLegendSybmbol( (WMSCapabilities) wmscache.get( addr ), layer, style ); 577 } 578 579 // store legend in cache 580 legendSymCache.put( path, legendGraphic ); 581 } 582 list1.add( layer ); 583 list2.add( legendGraphic ); 584 list3.add( title ); 585 } 586 } 587 } 588 589 String[] layers = list1.toArray( new String[list1.size()] ); 590 BufferedImage[] legs = list2.toArray( new BufferedImage[list2.size()] ); 591 String[] titles = list3.toArray( new String[list3.size()] ); 592 Map<String, Object> map = new HashMap<String, Object>(); 593 map.put( "NAMES", layers ); 594 map.put( "TITLES", titles ); 595 map.put( "IMAGES", legs ); 596 597 return map; 598 } 599 600 /** 601 * This method is called, when no legend image could be retreived from the information given in the WebMapContext 602 * document. The layer was probably added during runtime dynamically. 603 * 604 * It is attempted to get the legend url from style info in the WMS Capabilities, first with the passed style info, 605 * second for the default style, third for the only available style. (If the WMS capabilities holds more than one 606 * style, but no style was passed with the layer info, then one cannot know "the right style". Therefore no style is 607 * taken from WMS capabilities, in this case.) 608 * 609 * Then, it is attempted to get the legend image from a GetLegendGraphics request, if the WMS capabilities state, 610 * that this request is supported by the WMS. 611 * 612 * If all this fails, the image is taken from init param "missingImage". 613 * 614 * @param wmsCapa 615 * @param layer 616 * @param style 617 * @return the legend image or the missingImage 618 */ 619 private BufferedImage createLegendSybmbol( WMSCapabilities wmsCapa, String layer, String style ) { 620 621 URL url = null; 622 org.deegree.ogcwebservices.wms.capabilities.Layer ogcLayer = wmsCapa.getLayer( layer ); 623 624 if ( style == null ) { 625 style = "default"; 626 } 627 try { 628 // 1. get style for layer 629 // first try with "default" and then with "" (empty string) as style name 630 org.deegree.ogcwebservices.wms.capabilities.Style ogcStyle = ogcLayer.getStyleResource( style ); 631 if ( ogcStyle == null ) { 632 ogcStyle = ogcLayer.getStyleResource( "" ); 633 } 634 // try to get another style for layer (only, if there is just one style definition) 635 if ( ogcStyle == null ) { 636 LOG.logDebug( "Layer ", layer, " has no valid default style definition." ); 637 org.deegree.ogcwebservices.wms.capabilities.Style[] styles = ogcLayer.getStyles(); 638 if ( styles.length == 1 ) { 639 // using the only available style definition as default style definition 640 LOG.logDebug( "Layer ", layer, " has only one style definition. Assuming this as default style." ); 641 ogcStyle = styles[0]; 642 } else { 643 // more than one style definition available, but non is the default style. 644 // Therefore no style definition can be chosen. Nothing happens here. 645 } 646 } 647 648 // 2. try to get legend url from style definition 649 if ( ogcStyle != null ) { 650 LegendURL[] legendUrls = ogcStyle.getLegendURL(); 651 if ( legendUrls != null && legendUrls.length > 0 ) { 652 // First field of the array contains a url to the legend 653 LOG.logDebug( "Obtaining legend url from the OGCStyle for layer: ", layer ); 654 url = legendUrls[0].getOnlineResource(); 655 } 656 } 657 658 // 3. try to get legend url from getLegendGraphic request 659 if ( ogcStyle == null || url == null ) { 660 // either layer does not have a style info at all 661 // or layer has a style info, but this style does not contain a legend url 662 QualifiedName name = new QualifiedName( "GetLegendGraphic" ); 663 Operation op = wmsCapa.getOperationMetadata().getOperation( name ); 664 LOG.logDebug( "Obtaining the legend graphic from the metadata of the wms for layer: ", layer ); 665 if ( op != null ) { 666 HTTP http = (HTTP) op.getDCP().get( 0 ); 667 url = http.getGetOnlineResources().get( 0 ); 668 LOG.logDebug( "legend url obtained from operation metadata" ); 669 } else { 670 LOG.logDebug( "GetLegendGrpahic not served by the service." ); 671 } 672 LOG.logDebug( "LegendURLs can not be extracted from ogcStyle." ); 673 } 674 } catch ( Exception e ) { 675 LOG.logError( e.getLocalizedMessage() ); 676 } 677 678 if ( url == null ) { 679 return createMissingLegend( ogcLayer.getTitle() ); 680 } else { 681 try { 682 return ImageUtils.loadImage( url ); 683 } catch ( Exception e ) { 684 LOG.logError( e.getLocalizedMessage() ); 685 return createMissingLegend( ogcLayer.getTitle() ); 686 } 687 } 688 } 689 690 /** 691 * In case the legend can not be obtained from the OGCLayer, this method is called to create a dummy legend image 692 * plus the legend title 693 * 694 * @param layerName 695 * @return BufferedImage holding the created dummy legend 696 */ 697 private BufferedImage createMissingLegend( String layerName ) { 698 LOG.logDebug( "URL is null. Drawing the image from a missingImage variable in init params" ); 699 BufferedImage missingLegend = new BufferedImage( 80, 15, BufferedImage.TYPE_INT_RGB ); 700 Graphics g = missingLegend.getGraphics(); 701 Rectangle2D rect = g.getFontMetrics().getStringBounds( layerName, g ); 702 g.dispose(); 703 missingLegend = new BufferedImage( rect.getBounds().width + 80, missingImg.getHeight() + 15, 704 BufferedImage.TYPE_INT_ARGB ); 705 g = missingLegend.getGraphics(); 706 g.drawImage( missingImg, 0, 0, null ); 707 g.setColor( Color.RED ); 708 if ( useLayerTitle ) { 709 g.drawString( layerName, missingImg.getWidth() + 5, missingImg.getHeight() / 2 + g.getFont().getSize() / 2 ); 710 } 711 g.dispose(); 712 713 return missingLegend; 714 } 715 716 /** 717 * Performs a GetCapabilities request (now also with proxy usage enabled) 718 * 719 * @param url 720 * @param version 721 * @return the obtained WMSCapbilities 722 */ 723 private WMSCapabilities getCapabilities( String url, String version ) { 724 725 WMSCapabilities capa = null; 726 HttpClient httpclient = new HttpClient(); 727 try { 728 enableProxyUsage( httpclient, new URL( url ) ); 729 } catch ( MalformedURLException e ) { 730 LOG.logError( "the passed url was not well formed.", e ); 731 } 732 733 httpclient.getHttpConnectionManager().getParams().setSoTimeout( 15000 ); 734 StringBuffer sb = new StringBuffer( 500 ); 735 sb.append( url ); 736 if ( url.indexOf( "?" ) < 0 ) { 737 sb.append( "?" ); 738 } else if ( url.charAt( url.length() - 1 ) != '&' ) { 739 sb.append( "&" ); 740 } 741 sb.append( "request=GetCapabilities&service=WMS&version=" ); 742 sb.append( version ); 743 744 if ( userNames.get( url ) != null ) { 745 sb.append( "&USER=" ).append( userNames.get( url ) ); 746 sb.append( "&PASSWORD=" ); 747 if ( passwords.get( url ) != null ) { 748 sb.append( passwords.get( url ) ); 749 } 750 } 751 LOG.logDebug( sb.toString() ); 752 GetMethod httpget = new GetMethod( sb.toString() ); 753 try { 754 httpclient.executeMethod( httpget ); 755 XMLFragment xml = new XMLFragment(); 756 xml.load( new InputStreamReader( httpget.getResponseBodyAsStream() ), XMLFragment.DEFAULT_URL ); 757 WMSCapabilitiesDocument cdoc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( xml.getRootElement() ); 758 capa = (WMSCapabilities) cdoc.parseCapabilities(); 759 } catch ( Exception e ) { 760 LOG.logError( "GetCaps failed for " + sb.toString() ); 761 } 762 return capa; 763 } 764 }