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