001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_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: 27593 $, $Date: 2010-10-28 15:43:43 +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 }