    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_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    }