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    }