001    //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/enterprise/servlet/WMSHandler.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    
037    package org.deegree.enterprise.servlet;
038    
039    import static javax.imageio.ImageIO.write;
040    import static org.deegree.framework.util.CharsetUtils.getSystemCharset;
041    
042    import java.awt.Color;
043    import java.awt.Graphics;
044    import java.awt.image.BufferedImage;
045    import java.io.ByteArrayOutputStream;
046    import java.io.IOException;
047    import java.io.OutputStream;
048    import java.io.OutputStreamWriter;
049    import java.io.PrintWriter;
050    import java.io.StringReader;
051    import java.io.Writer;
052    import java.net.MalformedURLException;
053    import java.net.URISyntaxException;
054    import java.net.URL;
055    import java.util.LinkedList;
056    import java.util.List;
057    
058    import javax.imageio.ImageIO;
059    import javax.servlet.http.HttpServletResponse;
060    import javax.xml.transform.TransformerException;
061    
062    import org.deegree.datatypes.QualifiedName;
063    import org.deegree.datatypes.values.TypedLiteral;
064    import org.deegree.enterprise.ServiceException;
065    import org.deegree.enterprise.servlet.GetMapFilter.DummyRequest;
066    import org.deegree.framework.log.ILogger;
067    import org.deegree.framework.log.LoggerFactory;
068    import org.deegree.framework.util.CharsetUtils;
069    import org.deegree.framework.util.ImageUtils;
070    import org.deegree.framework.util.MimeTypeMapper;
071    import org.deegree.framework.util.NetWorker;
072    import org.deegree.framework.util.StringTools;
073    import org.deegree.framework.xml.DOMPrinter;
074    import org.deegree.framework.xml.XMLFragment;
075    import org.deegree.framework.xml.XSLTDocument;
076    import org.deegree.ogcwebservices.ExceptionReport;
077    import org.deegree.ogcwebservices.OGCWebService;
078    import org.deegree.ogcwebservices.OGCWebServiceException;
079    import org.deegree.ogcwebservices.OGCWebServiceRequest;
080    import org.deegree.ogcwebservices.OGCWebServiceResponse;
081    import org.deegree.ogcwebservices.wms.InvalidFormatException;
082    import org.deegree.ogcwebservices.wms.WMService;
083    import org.deegree.ogcwebservices.wms.WMServiceFactory;
084    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
085    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities_1_3_0;
086    import org.deegree.ogcwebservices.wms.configuration.WMSConfigurationType;
087    import org.deegree.ogcwebservices.wms.configuration.WMSDeegreeParams;
088    import org.deegree.ogcwebservices.wms.operation.DescribeLayerResult;
089    import org.deegree.ogcwebservices.wms.operation.GetFeatureInfo;
090    import org.deegree.ogcwebservices.wms.operation.GetFeatureInfoResult;
091    import org.deegree.ogcwebservices.wms.operation.GetLegendGraphic;
092    import org.deegree.ogcwebservices.wms.operation.GetLegendGraphicResult;
093    import org.deegree.ogcwebservices.wms.operation.GetMap;
094    import org.deegree.ogcwebservices.wms.operation.GetMapResult;
095    import org.deegree.ogcwebservices.wms.operation.GetStylesResult;
096    import org.deegree.ogcwebservices.wms.operation.PutStylesResult;
097    import org.deegree.ogcwebservices.wms.operation.WMSGetCapabilitiesResult;
098    import org.deegree.owscommon.XMLFactory;
099    import org.deegree.owscommon_new.DomainType;
100    import org.deegree.owscommon_new.Operation;
101    import org.deegree.owscommon_new.OperationsMetadata;
102    import org.w3c.dom.Node;
103    import org.xml.sax.SAXException;
104    
105    /**
106     * <code>WMSHandler</code> is the handler class for WMS requests and their results.
107     * 
108     * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
109     * @author last edited by: $Author: apoth $
110     * 
111     * @version 2.0, $Revision: 29241 $, $Date: 2011-01-12 11:07:07 +0100 (Wed, 12 Jan 2011) $
112     * 
113     * @since 2.0
114     */
115    public class WMSHandler extends AbstractOWServiceHandler {
116    
117        private static ILogger LOG = LoggerFactory.getLogger( WMSHandler.class );
118    
119        private Color bgColor = Color.WHITE;
120    
121        private HttpServletResponse resp = null;
122    
123        private OGCWebServiceRequest request = null;
124    
125        private String exceptionFormat;
126    
127        private String format = null, version = null;
128    
129        private boolean transparent = false;
130    
131        private int height = 400;
132    
133        private int width = 600;
134    
135        private WMSConfigurationType configuration = null;
136    
137        /**
138         *
139         */
140        public WMSHandler() {
141            LOG.logDebug( "New WMSHandler instance created: " + this.getClass().getName() );
142        }
143    
144        private String checkExceptionFormat( String exceptionFormat, List<String> availableExceptionFormats ) {
145            boolean found = false;
146            for ( String f : availableExceptionFormats ) {
147                if ( f.equalsIgnoreCase( exceptionFormat ) ) {
148                    found = true;
149                }
150            }
151            if ( !found ) {
152                return availableExceptionFormats.get( 0 );
153            }
154    
155            return exceptionFormat;
156        }
157    
158        /**
159         * performs the passed OGCWebServiceRequest by accessing service from the pool and passing the request to it
160         */
161        public void perform( OGCWebServiceRequest request, HttpServletResponse response )
162                                throws ServiceException {
163            this.request = request;
164            resp = response;
165            version = request.getVersion();
166    
167            try {
168    
169                OGCWebService service = WMServiceFactory.getService();
170                configuration = (WMSConfigurationType) ( (WMService) service ).getCapabilities();
171    
172                List<String> availableExceptionFormats = new LinkedList<String>();
173    
174                // add 1.1.1 names if 1.3.0 capable
175                for ( String f : configuration.getExceptions() ) {
176                    if ( f.equalsIgnoreCase( "XML" ) ) {
177                        availableExceptionFormats.add( "application/vnd.ogc.se_xml" );
178                    }
179                    if ( f.equalsIgnoreCase( "INIMAGE" ) ) {
180                        availableExceptionFormats.add( "application/vnd.ogc.se_inimage" );
181                    }
182                    if ( f.equalsIgnoreCase( "BLANK" ) ) {
183                        availableExceptionFormats.add( "application/vnd.ogc.se_blank" );
184                    }
185    
186                    availableExceptionFormats.add( f );
187                }
188    
189                // EXCEPTION HANDLING NOTES:
190                // currently, the exceptions are handled differently for each request type,
191                // change the behaviour here
192                if ( request instanceof GetMap ) {
193                    GetMap req = (GetMap) request;
194                    exceptionFormat = req.getExceptions();
195                    exceptionFormat = checkExceptionFormat( exceptionFormat, availableExceptionFormats );
196                    format = req.getFormat();
197                    bgColor = req.getBGColor();
198                    transparent = req.getTransparency();
199                    height = req.getHeight();
200                    width = req.getWidth();
201                }
202    
203                if ( request instanceof GetLegendGraphic ) {
204                    GetLegendGraphic req = (GetLegendGraphic) request;
205                    exceptionFormat = req.getExceptions();
206                    exceptionFormat = checkExceptionFormat( exceptionFormat, availableExceptionFormats );
207                    format = req.getFormat();
208                    height = req.getHeight();
209                    width = req.getWidth();
210                }
211    
212                if ( request instanceof GetFeatureInfo ) {
213                    GetFeatureInfo req = (GetFeatureInfo) request;
214                    exceptionFormat = req.getExceptions();
215                    exceptionFormat = checkExceptionFormat( exceptionFormat, availableExceptionFormats );
216                }
217    
218                fixupExceptionFormat();
219    
220                if ( request instanceof DummyRequest ) {
221                    // the dummy request is used to prevent using the response object so the handler can be
222                    // used externally. One could also rewrite the handler...
223                } else {
224    
225                    Object o = service.doService( request );
226                    if ( request instanceof GetMap ) {
227                        for ( String header : ( (GetMap) request ).warningHeaders ) {
228                            response.setHeader( "Warning", header );
229                        }
230                    }
231                    handleResponse( o );
232                }
233    
234            } catch ( OGCWebServiceException e ) {
235                LOG.logError( e.getMessage(), e );
236                writeServiceExceptionReport( e );
237            }
238        }
239    
240        private void fixupExceptionFormat() {
241            if ( exceptionFormat == null || exceptionFormat.equals( "" ) ) {
242                if ( "1.1.1".equals( version ) ) {
243                    exceptionFormat = "application/vnd.ogc.se_xml";
244                } else {
245                    exceptionFormat = "XML";
246                }
247            }
248    
249            // fixup the exception formats, 1.3.0 has it different
250            // note that XML/....se_xml are not the same format!
251            if ( "INIMAGE".equalsIgnoreCase( exceptionFormat ) ) {
252                exceptionFormat = "application/vnd.ogc.se_inimage";
253            }
254            if ( "BLANK".equalsIgnoreCase( exceptionFormat ) ) {
255                exceptionFormat = "application/vnd.ogc.se_blank";
256            }
257    
258        }
259    
260        /**
261         * 
262         * 
263         * @param result
264         */
265        private void handleResponse( Object result ) {
266            // this method may need restructuring
267    
268            // handle exception case
269            if ( result instanceof OGCWebServiceException ) {
270                writeServiceExceptionReport( (OGCWebServiceException) result );
271                return;
272            }
273    
274            try {
275                OGCWebServiceResponse response = (OGCWebServiceResponse) result;
276    
277                if ( response.getException() != null ) {
278                    // handle the case that an exception occurred during the
279                    // request performance
280                    writeServiceExceptionReport( response.getException() );
281                } else {
282                    if ( response instanceof OGCWebServiceException ) {
283                        writeServiceExceptionReport( (OGCWebServiceException) response );
284                    } else if ( response instanceof Exception ) {
285                        sendException( resp, (Exception) response );
286                    } else if ( response instanceof WMSGetCapabilitiesResult ) {
287                        handleGetCapabilitiesResponse( (WMSGetCapabilitiesResult) response );
288                    } else if ( response instanceof GetMapResult ) {
289                        handleGetMapResponse( (GetMapResult) response );
290                    } else if ( response instanceof GetFeatureInfoResult ) {
291                        handleFeatureInfoResponse( (GetFeatureInfoResult) response );
292                    } else if ( response instanceof GetStylesResult ) {
293                        handleGetStylesResponse( (GetStylesResult) response );
294                    } else if ( response instanceof PutStylesResult ) {
295                        handlePutStylesResponse( (PutStylesResult) response );
296                    } else if ( response instanceof DescribeLayerResult ) {
297                        handleDescribeLayerResponse( (DescribeLayerResult) response );
298                    } else if ( response instanceof GetLegendGraphicResult ) {
299                        handleGetLegendGraphicResponse( (GetLegendGraphicResult) response );
300                    }
301                }
302            } catch ( InvalidFormatException ife ) {
303                LOG.logError( ife.getMessage(), ife );
304                writeServiceExceptionReport( ife );
305            } catch ( Exception e ) {
306                LOG.logError( e.getMessage(), e );
307                writeServiceExceptionReport( new OGCWebServiceException( "WMS:write", e.getLocalizedMessage() ) );
308            }
309        }
310    
311        /**
312         * handles the response to a get capabilities request
313         * 
314         * @param response
315         * @throws IOException
316         * @throws TransformerException
317         */
318        private void handleGetCapabilitiesResponse( WMSGetCapabilitiesResult response )
319                                throws IOException, TransformerException {
320            WMSConfigurationType capa = response.getCapabilities();
321    
322            WMSDeegreeParams params = capa.getDeegreeParams();
323    
324            // version war follows
325    
326            boolean version130 = "1.3.0".equals( capa.calculateVersion( request.getVersion() ) );
327    
328            // version not set -> use highest supported version
329            // use request's version otherwise
330    
331            boolean support111 = false;
332            boolean support130 = false;
333            for ( String version : params.getSupportedVersions() ) {
334                if ( "1.1.1".equals( version ) )
335                    support111 = true;
336                if ( "1.3.0".equals( version ) )
337                    support130 = true;
338            }
339    
340            if ( ( !support130 ) && ( !support111 ) ) {
341                support111 = true;
342            }
343    
344            if ( version130 && support130 ) {
345                resp.setContentType( "text/xml" );
346            } else {
347                resp.setContentType( "application/vnd.ogc.wms_xml" );
348            }
349    
350            resp.setCharacterEncoding( getSystemCharset() );
351    
352            XMLFragment doc = null;
353    
354            if ( ( ( ( !version130 ) && support111 ) || ( !support130 ) ) && ( capa instanceof WMSCapabilities_1_3_0 ) ) {
355                doc = org.deegree.ogcwebservices.wms.XMLFactory.exportAs_1_1_1( (WMSCapabilities_1_3_0) capa );
356            } else {
357                doc = org.deegree.ogcwebservices.wms.XMLFactory.export( (WMSCapabilities) capa );
358            }
359    
360            if ( ( version130 && support130 ) || ( !support111 ) ) {
361                doc.getRootElement().setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
362                doc.getRootElement().setAttribute(
363                                                   "xsi:schemaLocation",
364                                                   "http://www.opengis.net/wms "
365                                                                           + "http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd"
366                                                                           + " http://www.opengis.net/sld "
367                                                                           + "http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd" );
368    
369                doc.prettyPrint( resp.getWriter() );
370            } else {
371                String xml = new XMLFragment( doc.getRootElement() ).getAsString();
372                xml = doc.getAsString();
373                String dtd = NetWorker.url2String( configuration.getDeegreeParams().getDTDLocation() );
374                StringBuffer sb = new StringBuffer();
375                sb.append( "<!DOCTYPE WMT_MS_Capabilities SYSTEM " );
376                sb.append( "'" + dtd + "' \n" );
377                sb.append( "[\n<!ELEMENT VendorSpecificCapabilities EMPTY>\n]>" );
378    
379                int p = xml.indexOf( "?>" );
380                if ( p > -1 ) {
381                    xml = xml.substring( p + 2, xml.length() );
382                }
383    
384                xml = StringTools.concat( 50000, "<?xml version=\"1.0\" encoding=\"", CharsetUtils.getSystemCharset(),
385                                          "\"?>", "\n", sb.toString(), xml );
386    
387                xml = StringTools.replace( xml, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", "", false );
388    
389                try {
390                    PrintWriter pw = resp.getWriter();
391                    pw.print( xml );
392                    pw.close();
393                } catch ( Exception e ) {
394                    LOG.logError( "-", e );
395                }
396    
397            }
398        }
399    
400        /**
401         * handles the response to a get map request
402         * 
403         * @param response
404         * @throws InvalidFormatException
405         */
406        public void handleGetMapResponse( GetMapResult response )
407                                throws InvalidFormatException {
408            // schmitz: added the toLowerCase to avoid errors
409            String mime = MimeTypeMapper.toMimeType( ( (GetMap) request ).getFormat().toLowerCase() );
410    
411            if ( !MimeTypeMapper.isImageType( mime ) ) {
412                throw new InvalidFormatException( mime + " is not a known image format" );
413            }
414    
415            writeImage( response.getMap(), mime );
416        }
417    
418        /**
419         * handles the response to a get featureinfo request
420         * 
421         * @param response
422         */
423        private void handleFeatureInfoResponse( GetFeatureInfoResult response )
424                                throws Exception {
425            GetFeatureInfo req = (GetFeatureInfo) request;
426    
427            String s = req.getInfoFormat();
428    
429            // check if GML is actually the correct one
430            // THIS IS A HACK
431            if ( req.isInfoFormatDefault() ) {
432                OperationsMetadata om = configuration.getOperationMetadata();
433                Operation op = om.getOperation( new QualifiedName( "GetFeatureInfo" ) );
434                DomainType dt = (DomainType) op.getParameter( new QualifiedName( "Format" ) );
435                List<TypedLiteral> vals = dt.getValues();
436                s = vals.get( 0 ).getValue();
437            }
438    
439            String mime = MimeTypeMapper.toMimeType( s );
440            resp.setContentType( mime + "; charset=" + CharsetUtils.getSystemCharset() );
441    
442            String fir = response.getFeatureInfo();
443    
444            String filter = FeatureInfoFilterDef.getString( s );
445    
446            if ( filter != null ) {
447                handleFilteredFeatureInfoResponse( fir, filter );
448            } else {
449                OutputStreamWriter os = null;
450                try {
451                    os = new OutputStreamWriter( resp.getOutputStream(), CharsetUtils.getSystemCharset() );
452                    os.write( fir );
453                } catch ( Exception e ) {
454                    LOG.logError( "could not write to outputstream", e );
455                } finally {
456                    if ( os != null ) {
457                        os.close();
458                    }
459                }
460            }
461        }
462    
463        /**
464         * @param fir
465         * @param filter
466         * @throws MalformedURLException
467         * @throws SAXException
468         * @throws IOException
469         * @throws URISyntaxException
470         * @throws TransformerException
471         */
472        private void handleFilteredFeatureInfoResponse( String fir, String filter )
473                                throws Exception {
474            URL url = new URL( configuration.getBaseURL(), filter );
475            LOG.logDebug( "used XSLT for transformation: ", url );
476            LOG.logDebug( "GML document to transform", fir );
477            XMLFragment xml = new XMLFragment( new StringReader( fir ) , XMLFragment.DEFAULT_URL );
478           
479            OutputStream os = null;
480            try {
481                os = resp.getOutputStream();
482                XSLTDocument xslt = new XSLTDocument( url );
483                xslt.transform( xml, os );
484            } catch ( IOException e ) {
485                LOG.logError( "could not write to outputstream", e );
486            } finally {
487                if ( os != null ) {
488                    os.close();
489                }
490            }
491        }
492    
493        /**
494         * handles the response to a get styles request
495         * 
496         * @param response
497         */
498        private void handleGetStylesResponse( GetStylesResult response ) {
499            throw new RuntimeException( "method: handleGetStylesResponse not implemented yet" );
500        }
501    
502        /**
503         * handles the response to a put styles request
504         * 
505         * @param response
506         */
507        private void handlePutStylesResponse( PutStylesResult response ) {
508            throw new RuntimeException( "method: handlePutStylesResponse not implemented yet" );
509        }
510    
511        /**
512         * handles the response to a describe layer request
513         * 
514         * @param response
515         * @throws IOException
516         * @throws TransformerException
517         */
518        private void handleDescribeLayerResponse( DescribeLayerResult response )
519                                throws TransformerException, IOException {
520            resp.setCharacterEncoding( "UTF-8" );
521            resp.setContentType( "text/xml" );
522            Writer out = resp.getWriter();
523            response.getResult().prettyPrint( out );
524            out.close();
525        }
526    
527        /**
528         * handles the response to a get legend graphic request
529         * 
530         * @param response
531         */
532        private void handleGetLegendGraphicResponse( GetLegendGraphicResult response )
533                                throws Exception {
534            String mime = MimeTypeMapper.toMimeType( ( (GetLegendGraphic) request ).getFormat() );
535    
536            if ( !MimeTypeMapper.isImageType( mime ) ) {
537                throw new InvalidFormatException( mime + " is not a known image format" );
538            }
539    
540            writeImage( response.getLegendGraphic(), mime );
541        }
542    
543        private void writeServiceExceptionReport( OGCWebServiceException exception, OutputStream out ) {
544            LOG.logInfo( "Sending exception in XML format." );
545            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
546                ExceptionReport report = new ExceptionReport( new OGCWebServiceException[] { exception } );
547                String msg;
548                if ( exceptionFormat.equals( "XML" ) ) {
549                    msg = XMLFactory.exportNS( report ).getAsPrettyString();
550                } else {
551                    msg = XMLFactory.export( report ).getAsPrettyString();
552                }
553    
554                LOG.logDebug( "Exception being sent: " + msg );
555            }
556    
557            ExceptionReport report = new ExceptionReport( new OGCWebServiceException[] { exception } );
558            try {
559                XMLFragment doc;
560    
561                if ( exceptionFormat.equals( "XML" ) ) {
562                    resp.setContentType( "text/xml" );
563                    doc = XMLFactory.exportNS( report );
564                } else {
565                    resp.setContentType( "application/vnd.ogc.se_xml" );
566                    doc = XMLFactory.export( report );
567                }
568    
569                doc.write( out );
570                out.close();
571            } catch ( Exception ex ) {
572                LOG.logError( "ERROR: " + ex.getMessage(), ex );
573            }
574        }
575    
576        /**
577         * @param eFormat
578         * @param format
579         * @param version
580         * @param response
581         */
582        public void determineExceptionFormat( String eFormat, String format, String version, HttpServletResponse response ) {
583            exceptionFormat = eFormat;
584            this.format = format;
585            this.version = version;
586            resp = response;
587    
588            fixupExceptionFormat();
589        }
590    
591        /**
592         * writes an service exception report into the <tt>OutputStream</tt> back to the client. the method considers the
593         * format an exception shall be returned to the client as defined in the request.
594         * 
595         * @param exception
596         *            the exception object containing the code and message
597         */
598        public void writeServiceExceptionReport( OGCWebServiceException exception ) {
599            String code = "none";
600            if ( exception.getCode() != null ) {
601                code = exception.getCode().value;
602            }
603            String message = exception.getMessage();
604    
605            LOG.logInfo( "sending exception in format " + exceptionFormat );
606            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
607                ExceptionReport report = new ExceptionReport( new OGCWebServiceException[] { exception } );
608                String msg;
609                if ( exceptionFormat.equals( "XML" ) ) {
610                    msg = XMLFactory.exportNS( report ).getAsPrettyString();
611                } else {
612                    msg = XMLFactory.export( report ).getAsPrettyString();
613                }
614    
615                LOG.logDebug( "Exception being sent: " + msg );
616            }
617    
618            if ( exceptionFormat.equals( "application/vnd.ogc.se_inimage" ) ) {
619                BufferedImage bi = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
620                Graphics g = bi.getGraphics();
621    
622                if ( !transparent ) {
623                    g.setColor( bgColor );
624                    g.fillRect( 0, 0, bi.getWidth(), bi.getHeight() );
625                }
626    
627                g.setColor( Color.BLUE );
628                g.drawString( code, 5, 20 );
629                int pos1 = message.indexOf( ':' );
630                g.drawString( message.substring( 0, pos1 + 1 ), 5, 50 );
631                g.drawString( message.substring( pos1 + 1, message.length() ), 5, 80 );
632                String mime = MimeTypeMapper.toMimeType( format );
633                writeImage( bi, mime );
634            } else if ( exceptionFormat.equals( "application/vnd.ogc.se_blank" ) ) {
635                BufferedImage bi = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
636                Graphics g = bi.getGraphics();
637    
638                if ( !transparent ) {
639                    g.setColor( bgColor );
640                    g.fillRect( 0, 0, bi.getWidth(), bi.getHeight() );
641                }
642    
643                g.dispose();
644                String mime = MimeTypeMapper.toMimeType( format );
645                writeImage( bi, mime );
646            } else {
647                LOG.logInfo( "Sending OGCWebServiceException to client." );
648                ExceptionReport report = new ExceptionReport( new OGCWebServiceException[] { exception } );
649                try {
650                    XMLFragment doc;
651    
652                    if ( exceptionFormat.equals( "XML" ) ) {
653                        resp.setContentType( "text/xml" );
654                        doc = XMLFactory.exportNS( report );
655                    } else {
656                        resp.setContentType( "application/vnd.ogc.se_xml" );
657                        doc = XMLFactory.export( report );
658                    }
659    
660                    OutputStream os = resp.getOutputStream();
661                    doc.write( os );
662                    os.close();
663                } catch ( Exception ex ) {
664                    LOG.logError( "ERROR: " + ex.getMessage(), ex );
665                }
666            }
667        }
668    
669        /**
670         * writes the passed image to the response output stream.
671         * 
672         * @param output
673         * @param mime
674         */
675        private void writeImage( Object output, String mime ) {
676            OutputStream os = null;
677            try {
678                resp.setContentType( mime );
679                if ( mime.equalsIgnoreCase( "image/gif" ) ) {
680                    BufferedImage img = (BufferedImage) output;
681                    ByteArrayOutputStream out = new ByteArrayOutputStream( img.getWidth() * img.getHeight() * 4 );
682                    try {
683                        ImageUtils.encodeGif( out, img );
684                    } catch ( IOException e ) {
685                        LOG.logWarning( "ACME failed to write GIF image, trying ImageIO." );
686                        LOG.logDebug( "Stack trace", e );
687                        // use imageio, it can transform the colors correctly starting from Java 1.6
688                        if ( !write( img, "gif", out ) ) {
689                            os = resp.getOutputStream();
690                            writeServiceExceptionReport( new OGCWebServiceException( e.getLocalizedMessage() ), os );
691                            os.close();
692                            return;
693                        }
694                    }
695    
696                    resp.setContentType( mime );
697                    os = resp.getOutputStream();
698    
699                    out.close();
700                    byte[] bs = out.toByteArray();
701                    out = null;
702    
703                    os.write( bs );
704                } else if ( mime.equalsIgnoreCase( "image/jpg" ) || mime.equalsIgnoreCase( "image/jpeg" ) ) {
705                    os = resp.getOutputStream();
706                    ImageUtils.saveImage( (BufferedImage) output, os, "jpeg",
707                                          configuration.getDeegreeParams().getMapQuality() );
708                } else if ( mime.equalsIgnoreCase( "image/png" ) || mime.equalsIgnoreCase( "image/png; mode=24bit" ) ) {
709                    os = resp.getOutputStream();
710                    ImageUtils.saveImage( (BufferedImage) output, os, "png", 1 );
711                } else if ( mime.equalsIgnoreCase( "image/png; mode=8bit" ) ) {
712                    os = resp.getOutputStream();
713                    ImageIO.write( (BufferedImage) output, "png", os );
714                    // ImageUtils.saveImage( (BufferedImage) output, os, "png", 1 ); // ImageUtils produces double size
715                    // images...
716                } else if ( mime.equalsIgnoreCase( "image/tif" ) || mime.equalsIgnoreCase( "image/tiff" ) ) {
717                    os = resp.getOutputStream();
718                    ImageUtils.saveImage( (BufferedImage) output, os, "tif", 1 );
719                } else if ( mime.equalsIgnoreCase( "image/bmp" ) ) {
720                    os = resp.getOutputStream();
721                    ImageUtils.saveImage( (BufferedImage) output, os, "bmp", 1 );
722                } else if ( mime.equalsIgnoreCase( "image/svg+xml" ) ) {
723                    os = resp.getOutputStream();
724                    resp.setContentType( "text/xml; charset=" + CharsetUtils.getSystemCharset() );
725                    PrintWriter pw = new PrintWriter( os );
726                    DOMPrinter.printNode( pw, (Node) output );
727                    pw.close();
728                } else {
729                    resp.setContentType( "text/xml; charset=" + CharsetUtils.getSystemCharset() );
730                    os = resp.getOutputStream();
731                    OGCWebServiceException exce = new OGCWebServiceException( "WMS:writeImage",
732                                                                              "unsupported image format: " + mime );
733                    writeServiceExceptionReport( exce, os );
734                }
735    
736                os.close();
737            } catch ( Exception e ) {
738                LOG.logError( resp.isCommitted() ? "Response is already committed!" : "Response is not committed yet." );
739                LOG.logError( "Error while writing image: ", e );
740                writeServiceExceptionReport( new OGCWebServiceException( e.getLocalizedMessage() ), os );
741            }
742        }
743    
744        /**
745         * It's a workaround to make the 'API' more usable.
746         * 
747         * @param request
748         */
749        public void setRequest( OGCWebServiceRequest request ) {
750            this.request = request;
751        }
752    
753    }