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 }