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