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