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