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