    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    }