001    // $HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wms/GetLegendGraphicHandler.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.ogcwebservices.wms;
037    
038    import java.awt.image.BufferedImage;
039    import java.net.URL;
040    import java.util.List;
041    
042    import org.deegree.datatypes.QualifiedName;
043    import org.deegree.framework.log.ILogger;
044    import org.deegree.framework.log.LoggerFactory;
045    import org.deegree.framework.util.ImageUtils;
046    import org.deegree.framework.util.StringTools;
047    import org.deegree.graphics.legend.LegendElement;
048    import org.deegree.graphics.legend.LegendFactory;
049    import org.deegree.graphics.sld.SLDFactory;
050    import org.deegree.graphics.sld.StyledLayerDescriptor;
051    import org.deegree.graphics.sld.UserStyle;
052    import org.deegree.i18n.Messages;
053    import org.deegree.ogcwebservices.OGCWebServiceException;
054    import org.deegree.ogcwebservices.wms.capabilities.Layer;
055    import org.deegree.ogcwebservices.wms.capabilities.LegendURL;
056    import org.deegree.ogcwebservices.wms.configuration.AbstractDataSource;
057    import org.deegree.ogcwebservices.wms.configuration.ExternalDataAccessDataSource;
058    import org.deegree.ogcwebservices.wms.configuration.LocalWCSDataSource;
059    import org.deegree.ogcwebservices.wms.configuration.RemoteWCSDataSource;
060    import org.deegree.ogcwebservices.wms.configuration.RemoteWMSDataSource;
061    import org.deegree.ogcwebservices.wms.configuration.WMSConfigurationType;
062    import org.deegree.ogcwebservices.wms.dataaccess.ExternalDataAccess;
063    import org.deegree.ogcwebservices.wms.operation.GetLegendGraphic;
064    import org.deegree.ogcwebservices.wms.operation.GetLegendGraphicResult;
065    import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory;
066    import org.deegree.owscommon_new.DCP;
067    import org.deegree.owscommon_new.HTTP;
068    import org.deegree.owscommon_new.Operation;
069    import org.deegree.owscommon_new.OperationsMetadata;
070    
071    /**
072     * performs a GetLegendGraphic request. The capability of the deegree implementation is limited to handle requests
073     * containing a named style or using the (named) styles defined in a passed or referenced SLD. featuretype and rule are
074     * not supported yet.
075     *
076     * @version $Revision: 18195 $
077     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
078     * @author last edited by: $Author: mschneider $
079     *
080     * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
081     *
082     * @since 1.1
083     */
084    class GetLegendGraphicHandler {
085    
086        private static final ILogger LOG = LoggerFactory.getLogger( GetLegendGraphicHandler.class );
087    
088        private WMSConfigurationType configuration = null;
089    
090        private StyledLayerDescriptor sld = null;
091    
092        private GetLegendGraphic request = null;
093    
094        /**
095         * Creates a new GetMapHandler object.
096         *
097         * @param capabilities
098         * @param request
099         *            request to perform
100         */
101        public GetLegendGraphicHandler( WMSConfigurationType capabilities, GetLegendGraphic request ) {
102            this.configuration = capabilities;
103            this.request = request;
104        }
105    
106        /**
107         * performs the request and returns the result of it.
108         *
109         * @return the result object
110         * @throws OGCWebServiceException
111         */
112        public GetLegendGraphicResult performGetLegendGraphic()
113                                throws OGCWebServiceException {
114    
115            validate( request );
116            LegendElement lege = getSymbol( request );
117            BufferedImage bi = null;
118            try {
119                bi = lege.exportAsImage( request.getFormat() );
120            } catch ( Exception e ) {
121                LOG.logError( e.getMessage(), e );
122                throw new OGCWebServiceException( getClass().getName(), e.getMessage() );
123            }
124    
125            GetLegendGraphicResult res = WMSProtocolFactory.createGetLegendGraphicResponse( request, bi );
126    
127            return res;
128        }
129    
130        /**
131         * validates if the passed request is valid against the WMS it was sent to and the SLD maybe contained or referenced
132         * in/by the request.
133         *
134         * @param request
135         *            request to validate
136         */
137        private void validate( GetLegendGraphic request )
138                                throws OGCWebServiceException {
139    
140            String layerName = request.getLayer();
141            String style = request.getStyle();
142            if ( request.getSLD() == null && request.getSLD_Body() == null ) {
143                Layer layer = configuration.getLayer( layerName );
144                if ( layer == null ) {
145                    String s = Messages.getMessage( "WMS_UNKNOWNLAYER", layerName );
146                    throw new LayerNotDefinedException( s );
147                }
148                AbstractDataSource[] ds = layer.getDataSource();
149                boolean raster = true;
150                for ( AbstractDataSource abstractDataSource : ds ) {
151                    if ( !( abstractDataSource instanceof ExternalDataAccessDataSource )
152                         && !( abstractDataSource instanceof RemoteWMSDataSource )
153                         && !( abstractDataSource instanceof RemoteWCSDataSource )
154                         && !( abstractDataSource instanceof LocalWCSDataSource ) ) {
155                        raster = false;
156                        break;
157                    }
158                }
159                if ( !raster && getNamedStyle( style ) == null ) {
160                    String s = Messages.getMessage( "WMS_STYLENOTKNOWN", style );
161                    throw new StyleNotDefinedException( s );
162                }
163            } else {
164                try {
165                    if ( request.getSLD() != null ) {
166                        sld = SLDFactory.createSLD( request.getSLD() );
167                    } else {
168                        sld = SLDFactory.createSLD( request.getSLD_Body() );
169                    }
170                    // check if layer and style are present
171                    org.deegree.graphics.sld.AbstractLayer[] sldLayers = sld.getLayers();
172                    boolean found = false;
173                    for ( int i = 0; i < sldLayers.length; i++ ) {
174                        if ( layerName.equals( sldLayers[i].getName() ) ) {
175                            org.deegree.graphics.sld.AbstractStyle[] sldStyles = sldLayers[i].getStyles();
176                            for ( int k = 0; k < sldStyles.length; k++ ) {
177                                if ( sldStyles[k].getName() != null && sldStyles[k].getName().equals( style ) ) {
178                                    found = true;
179                                    break;
180                                }
181                            }
182                            if ( found )
183                                break;
184                        }
185                    }
186                    if ( !found ) {
187                        String s = Messages.getMessage( "WMS_LAYERNOTKNOWN", layerName );
188                        throw new OGCWebServiceException( getClass().getName(), s );
189                    }
190    
191                } catch ( Exception e ) {
192                    LOG.logError( e.getMessage(), e );
193                    String s = Messages.getMessage( "WMS_INVALIDSLDREF" );
194                    throw new OGCWebServiceException( getClass().getName(), s );
195                }
196    
197            }
198    
199        }
200    
201        private org.deegree.ogcwebservices.wms.capabilities.Style getNamedStyle( String name ) {
202            String layerName = request.getLayer();
203            Layer layer = configuration.getLayer( layerName );
204            org.deegree.ogcwebservices.wms.capabilities.Style[] styles = layer.getStyles();
205            for ( int i = 0; i < styles.length; i++ ) {
206                if ( styles[i].getName().equals( name ) ) {
207                    return styles[i];
208                }
209            }
210            return null;
211        }
212    
213        /**
214         * @param request
215         * @return the symbol
216         * @throws OGCWebServiceException
217         */
218        private LegendElement getSymbol( GetLegendGraphic request )
219                                throws OGCWebServiceException {
220    
221            LegendElement le = null;
222            try {
223                if ( request.getSLD() == null && request.getSLD_Body() == null ) {
224    
225                    // (temporary?) workaround for remote WMS layers
226                    Layer layer = configuration.getLayer( request.getLayer() );
227                    if ( layer != null && layer.getDataSource() != null && layer.getDataSource().length > 0 ) {
228                        AbstractDataSource ds = layer.getDataSource()[0];
229                        if ( ds.getType() == AbstractDataSource.REMOTEWMS ) {
230                            Object o = ( (RemoteWMSDataSource) ds ).getOGCWebService().doService( request );
231                            if ( o instanceof GetLegendGraphicResult ) {
232                                OGCWebServiceException exc = ( (GetLegendGraphicResult) o ).getException();
233                                if ( exc != null ) {
234                                    throw exc;
235                                }
236                                le = new LegendFactory().createLegendElement( (BufferedImage) ( (GetLegendGraphicResult) o ).getLegendGraphic() );
237                            }
238                        } else if ( ds.getType() == AbstractDataSource.EXTERNALDATAACCESS ) {
239                            ExternalDataAccess eda = ( (ExternalDataAccessDataSource) ds ).getExternalDataAccess();
240                            le = new LegendFactory().createLegendElement( eda.perform( request ) );
241                        }
242                    }
243    
244                    if ( le == null ) {
245                        le = getFromWellKnownStyle();
246                    }
247                } else {
248                    le = getFromSLDStyle();
249                }
250            } catch ( Exception e ) {
251                LOG.logError( e.getMessage(), e );
252                String s = Messages.getMessage( "WMS_LEGENDELEM" );
253                throw new OGCWebServiceException( getClass().getName(), s );
254            }
255    
256            return le;
257        }
258    
259        /**
260         * creates a LegendElement from a style known by the WMS
261         */
262        private LegendElement getFromWellKnownStyle()
263                                throws OGCWebServiceException {
264    
265            String layerName = request.getLayer();
266            String styleName = request.getStyle();
267            LegendElement le = null;
268            LegendFactory lf = new LegendFactory();
269    
270            try {
271                // get Layer object from the WMS capabilities
272                Layer layer = configuration.getLayer( layerName );
273                // get the Style section from the matching the requested style
274                org.deegree.ogcwebservices.wms.capabilities.Style nStyle = getNamedStyle( styleName );
275                LegendURL[] lURLs = nStyle.getLegendURL();
276                OperationsMetadata om = configuration.getOperationMetadata();
277                Operation op = om.getOperation( new QualifiedName( "GetLegendGraphic" ) );
278                URL url = null;
279                if ( op != null ) {
280                    // TODO
281                    // should check if really HTTP
282                    List<DCP> dcpList = op.getDCP();
283                    HTTP http = (HTTP) dcpList.get( 0 );
284                    url = http.getLinks().get( 0 ).getLinkage().getHref();
285                    if ( lURLs[0].getOnlineResource().getHost().equals( url.getHost() )
286                         && lURLs[0].getOnlineResource().toExternalForm().indexOf( "GetLegendGraphic" ) > -1 ) {
287                        String s = StringTools.concat( 200, "GetLegendGraphic request ",
288                                                       "to the WMS itself has been set has defined ",
289                                                       "as LegendURL for layer: ", layerName );
290                        LOG.logInfo( s );
291                        // avoid cyclic calling of WMS
292                        UserStyle style = layer.getStyle( styleName );
293                        if ( style != null ) {
294                            // drawing legend symbol
295                            String title = configuration.getLayer( layerName ).getTitle();
296                            le = lf.createLegendElement( style, request.getWidth(), request.getHeight(), title );
297                        } else {
298                            s = Messages.getMessage( "WMS_GENERALSTYLEERROR", styleName );
299                            throw new OGCWebServiceException( getClass().getName(), s );
300                        }
301                    } else {
302                        // if a legend url is defined will be used for creating the legend
303                        // symbol; otherwise it will be tried to create the legend symbol
304                        // dynamicly
305                        try {
306                            BufferedImage bi = ImageUtils.loadImage( lURLs[0].getOnlineResource() );
307                            le = lf.createLegendElement( bi );
308                        } catch ( Exception e ) {
309                            String s = StringTools.concat( 200, "can not open legen URL: ", lURLs[0].getOnlineResource(),
310                                                           "; try to create ", "legend symbol dynamicly." );
311                            LOG.logInfo( s );
312                            UserStyle style = layer.getStyle( styleName );
313                            if ( style != null ) {
314                                // drawing legend symbol
315                                String title = configuration.getLayer( layerName ).getTitle();
316                                le = lf.createLegendElement( style, request.getWidth(), request.getHeight(), title );
317                            } else {
318                                s = Messages.getMessage( "WMS_GENERALSTYLEERROR", styleName );
319                                throw new OGCWebServiceException( getClass().getName(), s );
320                            }
321                        }
322    
323                    }
324                }
325    
326            } catch ( Exception e ) {
327                LOG.logError( e.getMessage(), e );
328                throw new OGCWebServiceException( e.getMessage() );
329            }
330            return le;
331        }
332    
333        /**
334         * creates a LegendElement from a style defined in the SLD document passed/referenced by/in the request
335         */
336        private LegendElement getFromSLDStyle()
337                                throws OGCWebServiceException {
338    
339            String layerName = request.getLayer();
340            String styleName = request.getStyle();
341            LegendElement le = null;
342            LegendFactory lf = new LegendFactory();
343    
344            try {
345                org.deegree.graphics.sld.AbstractLayer[] sldLayers = sld.getLayers();
346                for ( int i = 0; i < sldLayers.length; i++ ) {
347                    if ( layerName.equals( sldLayers[i].getName() ) ) {
348                        org.deegree.graphics.sld.AbstractStyle[] sldStyles = sldLayers[i].getStyles();
349                        org.deegree.graphics.sld.AbstractStyle style = null;
350                        if ( styleName == null ) {
351                            style = sldStyles[0];
352                        } else {
353                            for ( int k = 0; k < sldStyles.length; k++ ) {
354                                if ( sldStyles[k].getName().equals( styleName ) ) {
355                                    style = sldStyles[k];
356                                    break;
357                                }
358                            }
359                        }
360                        String title = configuration.getLayer( layerName ).getTitle();
361                        le = lf.createLegendElement( style, request.getWidth(), request.getHeight(), title );
362                    }
363                }
364            } catch ( Exception e ) {
365                LOG.logError( e.getMessage(), e );
366                throw new OGCWebServiceException( StringTools.stackTraceToString( e.getStackTrace() ) );
367            }
368    
369            return le;
370        }
371    
372    }