001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wms/RemoteWMService.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2007 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstr. 19 030 53115 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 043 ---------------------------------------------------------------------------*/ 044 package org.deegree.ogcwebservices.wms; 045 046 import java.io.IOException; 047 import java.io.InputStream; 048 import java.io.StringReader; 049 import java.net.URL; 050 import java.util.HashMap; 051 import java.util.List; 052 053 import javax.media.jai.JAI; 054 import javax.media.jai.RenderedOp; 055 056 import org.deegree.datatypes.QualifiedName; 057 import org.deegree.framework.log.ILogger; 058 import org.deegree.framework.log.LoggerFactory; 059 import org.deegree.framework.util.CharsetUtils; 060 import org.deegree.framework.util.MimeTypeMapper; 061 import org.deegree.framework.util.NetWorker; 062 import org.deegree.framework.util.StringTools; 063 import org.deegree.framework.xml.XMLFragment; 064 import org.deegree.ogcwebservices.OGCWebService; 065 import org.deegree.ogcwebservices.OGCWebServiceException; 066 import org.deegree.ogcwebservices.OGCWebServiceRequest; 067 import org.deegree.ogcwebservices.OWSUtils; 068 import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities; 069 import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities; 070 import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument; 071 import org.deegree.ogcwebservices.wms.operation.DescribeLayer; 072 import org.deegree.ogcwebservices.wms.operation.GetFeatureInfo; 073 import org.deegree.ogcwebservices.wms.operation.GetLegendGraphic; 074 import org.deegree.ogcwebservices.wms.operation.GetMap; 075 import org.deegree.ogcwebservices.wms.operation.GetStyles; 076 import org.deegree.ogcwebservices.wms.operation.PutStyles; 077 import org.deegree.ogcwebservices.wms.operation.WMSGetCapabilities; 078 import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory; 079 import org.deegree.owscommon_new.DCP; 080 import org.deegree.owscommon_new.HTTP; 081 import org.deegree.owscommon_new.Operation; 082 import org.deegree.owscommon_new.OperationsMetadata; 083 084 import com.sun.media.jai.codec.MemoryCacheSeekableStream; 085 086 /** 087 * An instance of the class acts as a wrapper to a remote WMS. 088 * 089 * @version $Revision: 7713 $ 090 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 091 */ 092 public class RemoteWMService implements OGCWebService { 093 094 private static ILogger LOG = LoggerFactory.getLogger( RemoteWMService.class ); 095 096 private static final String GETCAPABILITIES_NAME = "GetCapabilities"; 097 098 private static final String CAPABILITIES_NAME = "Capabilities"; 099 100 private static final String GETMAP_NAME = "GetMap"; 101 102 private static final String MAP_NAME = "Map"; 103 104 private static final String GETFEATUREINFO_NAME = "GetFeatureInfo"; 105 106 private static final String FEATUREINFO_NAME = "FeatureInfo"; 107 108 private static final String DESCRIBELAYER_NAME = "DescribeLayer"; 109 110 private static final String GETLEGENDGRAPHIC_NAME = "GetLegendGraphic"; 111 112 private static final String GETSTYLES_NAME = "GetStyles"; 113 114 private static final String PUTSTYLES_NAME = "PutStyles"; 115 116 // private static final String UNKNOWN_NAME = "Unknown"; 117 118 protected HashMap<String, URL> addresses = null; 119 120 protected WMSCapabilities capabilities = null; 121 122 /** 123 * Creates a new instance of RemoteWMService 124 * 125 * @param capabilities 126 */ 127 public RemoteWMService( WMSCapabilities capabilities ) { 128 this.capabilities = capabilities; 129 addresses = new HashMap<String, URL>(); 130 131 // get GetCapabilities operation address 132 List<DCP> dcps = null; 133 HTTP http = null; 134 135 OperationsMetadata om = capabilities.getOperationMetadata(); 136 137 if ( capabilities.getVersion().equals( "1.0.0" ) ) { 138 dcps = om.getOperation( new QualifiedName( CAPABILITIES_NAME ) ).getDCP(); 139 for ( DCP dcp : dcps ) 140 if ( dcp instanceof HTTP ) 141 http = (HTTP) dcp; 142 addresses.put( CAPABILITIES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 143 } else { 144 dcps = om.getOperation( new QualifiedName( GETCAPABILITIES_NAME ) ).getDCP(); 145 for ( DCP dcp : dcps ) 146 if ( dcp instanceof HTTP ) 147 http = (HTTP) dcp; 148 addresses.put( GETCAPABILITIES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 149 } 150 151 // get GetMap operation address 152 if ( capabilities.getVersion().equals( "1.0.0" ) ) { 153 dcps = om.getOperation( new QualifiedName( MAP_NAME ) ).getDCP(); 154 for ( DCP dcp : dcps ) 155 if ( dcp instanceof HTTP ) 156 http = (HTTP) dcp; 157 addresses.put( MAP_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 158 } else { 159 dcps = om.getOperation( new QualifiedName( GETMAP_NAME ) ).getDCP(); 160 for ( DCP dcp : dcps ) 161 if ( dcp instanceof HTTP ) 162 http = (HTTP) dcp; 163 addresses.put( GETMAP_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 164 } 165 166 // get GetFeatureInfo operation address 167 if ( capabilities.getVersion().equals( "1.0.0" ) ) { 168 Operation operation = om.getOperation( new QualifiedName( FEATUREINFO_NAME ) ); 169 170 if ( operation != null ) { 171 dcps = operation.getDCP(); 172 for ( DCP dcp : dcps ) 173 if ( dcp instanceof HTTP ) 174 http = (HTTP) dcp; 175 addresses.put( FEATUREINFO_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 176 } 177 } else { 178 Operation operation = om.getOperation( new QualifiedName( GETFEATUREINFO_NAME ) ); 179 180 if ( operation != null ) { 181 dcps = operation.getDCP(); 182 for ( DCP dcp : dcps ) 183 if ( dcp instanceof HTTP ) 184 http = (HTTP) dcp; 185 addresses.put( GETFEATUREINFO_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 186 } 187 } 188 189 // get GetLegendGraphic operation address 190 Operation operation = om.getOperation( new QualifiedName( GETLEGENDGRAPHIC_NAME ) ); 191 192 if ( operation != null ) { 193 dcps = operation.getDCP(); 194 for ( DCP dcp : dcps ) 195 if ( dcp instanceof HTTP ) 196 http = (HTTP) dcp; 197 addresses.put( GETLEGENDGRAPHIC_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 198 } 199 200 // get GetStyles operation address 201 operation = om.getOperation( new QualifiedName( GETSTYLES_NAME ) ); 202 203 if ( operation != null ) { 204 dcps = operation.getDCP(); 205 for ( DCP dcp : dcps ) 206 if ( dcp instanceof HTTP ) 207 http = (HTTP) dcp; 208 addresses.put( GETSTYLES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 209 } 210 211 // get PutStyles operation address 212 operation = om.getOperation( new QualifiedName( PUTSTYLES_NAME ) ); 213 214 if ( operation != null ) { 215 dcps = operation.getDCP(); 216 for ( DCP dcp : dcps ) 217 if ( dcp instanceof HTTP ) 218 http = (HTTP) dcp; 219 addresses.put( PUTSTYLES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 220 } 221 222 // get DescribeLayer operation address 223 operation = om.getOperation( new QualifiedName( DESCRIBELAYER_NAME ) ); 224 225 if ( operation != null ) { 226 dcps = operation.getDCP(); 227 for ( DCP dcp : dcps ) 228 if ( dcp instanceof HTTP ) 229 http = (HTTP) dcp; 230 addresses.put( DESCRIBELAYER_NAME, http.getLinks().get( 0 ).getLinkage().getHref() ); 231 } 232 233 } 234 235 public OGCCapabilities getCapabilities() { 236 return capabilities; 237 } 238 239 /** 240 * the method performs the handling of the passed OGCWebServiceEvent directly and returns the 241 * result to the calling class/method 242 * 243 * @param request 244 * request (WMS, WCS, WFS, WCAS, WCTS, WTS, Gazetter) to perform 245 * 246 * @throws OGCWebServiceException 247 */ 248 public Object doService( OGCWebServiceRequest request ) 249 throws OGCWebServiceException { 250 Object o = null; 251 if ( request instanceof GetMap ) { 252 o = handleGetMap( (GetMap) request ); 253 o = WMSProtocolFactory.createGetMapResponse( request, null, o ); 254 } else if ( request instanceof GetFeatureInfo ) { 255 o = handleFeatureInfo( (GetFeatureInfo) request ); 256 o = WMSProtocolFactory.createGetFeatureInfoResponse( request, null, (String) o ); 257 } 258 /* 259 * else if ( request instanceof WMSGetCapabilities) { handleGetCapabilities( 260 * (WMSGetCapabilities)request, client ); } else if ( request instanceof GetStyles ) { 261 * handleGetStyles( (GetStyles)request, client ); } else if ( request instanceof PutStyles ) { 262 * handlePutStyles( (PutStyles)request, client ); } else if ( request instanceof 263 * DescribeLayer ) { handleDescribeLayer( (DescribeLayer)request, client ); } else if ( 264 * request instanceof GetLegendGraphic ) { handleGetLegendGraphic( 265 * (GetLegendGraphic)request, client ); } 266 */ 267 268 return o; 269 270 } 271 272 /** 273 * performs a GetMap request against the remote service. The result contains the map decoded in 274 * the desired format as a byte array. 275 * 276 * @param request 277 * GetMap request 278 */ 279 protected Object handleGetMap( GetMap request ) 280 throws OGCWebServiceException { 281 282 URL url = null; 283 284 if ( request.getVersion().equals( "1.0.0" ) ) { 285 url = addresses.get( MAP_NAME ); 286 } else { 287 url = addresses.get( GETMAP_NAME ); 288 } 289 290 String param = request.getRequestParameter(); 291 String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param; 292 293 LOG.logDebug( "remote wms getmap", us ); 294 295 if ( capabilities.getVersion().compareTo( "1.0.0" ) <= 0 ) { 296 us = StringTools.replace( us, "TRANSPARENCY", "TRANSPARENT", false ); 297 us = StringTools.replace( us, "GetMap", "map", false ); 298 us = StringTools.replace( us, "image/", "", false ); 299 } 300 301 Object result = null; 302 try { 303 URL ur = new URL( us ); 304 // get map from the remote service 305 NetWorker nw = new NetWorker( ur ); 306 InputStream is = nw.getInputStream(); 307 308 String contentType = nw.getContentType(); 309 String[] tmp = StringTools.toArray( contentType, ";", true ); 310 for ( int i = 0; i < tmp.length; i++ ) { 311 if ( tmp[i].indexOf( "image" ) > -1 ) { 312 contentType = tmp[i]; 313 break; 314 } 315 contentType = tmp[0]; 316 } 317 318 if ( MimeTypeMapper.isImageType( contentType ) && MimeTypeMapper.isKnownImageType( contentType ) ) { 319 MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is ); 320 RenderedOp rop = JAI.create( "stream", mcss ); 321 result = rop.getAsBufferedImage(); 322 mcss.close(); 323 } else { 324 // extract remote (error) message if the response 325 // contains a known mime type 326 String res = ""; 327 if ( MimeTypeMapper.isKnownMimeType( contentType ) ) { 328 res = "; remote message: "; 329 res += getInputStreamContent( is ); 330 } 331 332 throw new OGCWebServiceException( "RemoteWMS:handleGetMap", "Response of the remote " 333 + "WMS contains wrong content type: " 334 + contentType + ";request: " + param + res ); 335 } 336 } catch ( Exception e ) { 337 throw new OGCWebServiceException( 338 "RemoteWMS:handleGetMap", 339 "Could not get map from RemoteWMS: " 340 + capabilities.getServiceIdentification().getTitle() 341 + "; " + "request: " + param + " " + e.toString() ); 342 } 343 344 return result; 345 } 346 347 /** 348 * reads feature infos from the remote WMS by performing a FeatureInfo request against it. As 349 * long the result of a FeatureInfo request is generic (for usual it is som HTML) it isn't easy 350 * to combine the result with that of other WMS's 351 * 352 * @param request 353 * feature info request 354 */ 355 protected Object handleFeatureInfo( GetFeatureInfo request ) 356 throws OGCWebServiceException { 357 358 URL url = null; 359 360 if ( request.getVersion().equals( "1.0.0" ) ) { 361 url = addresses.get( FEATUREINFO_NAME ); 362 } else { 363 url = addresses.get( GETFEATUREINFO_NAME ); 364 } 365 366 if ( url == null ) { 367 throw new OGCWebServiceException( "GetFeatureInfo is not supported by the RemoteWMS: " 368 + capabilities.getServiceIdentification().getTitle() ); 369 } 370 371 String param = request.getRequestParameter(); 372 String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param; 373 374 String result = null; 375 try { 376 LOG.logDebug( "GetFeatureInfo: ", us ); 377 URL ur = new URL( us ); 378 // get map from the remote service 379 NetWorker nw = new NetWorker( ur ); 380 byte[] b = nw.getDataAsByteArr( 20000 ); 381 String contentType = nw.getContentType(); 382 383 // extract content charset if available; otherwise use configured system charset 384 String charset = null; 385 LOG.logDebug( "content type: ", contentType ); 386 if ( contentType != null ) { 387 String[] tmp = StringTools.toArray( contentType, ";", false ); 388 if ( tmp.length == 2 ) { 389 charset = tmp[1].substring( tmp[1].indexOf( '=' ) + 1, tmp[1].length() ); 390 } else { 391 charset = CharsetUtils.getSystemCharset(); 392 } 393 } else { 394 charset = CharsetUtils.getSystemCharset(); 395 } 396 397 if ( contentType.toLowerCase().startsWith( "application/vnd.ogc.gml" ) ) { 398 result = new String( b, charset ); 399 } else { 400 throw new OGCWebServiceException( "RemoteWMS:handleFeatureInfo" ); 401 } 402 } catch ( Exception e ) { 403 e.printStackTrace(); 404 throw new OGCWebServiceException( 405 "RemoteWMS:handleFeatureInfo", 406 "Could not get map from RemoteWMS: " 407 + capabilities.getServiceIdentification().getTitle() 408 + "; request: " + param + "; " + e.toString() ); 409 } 410 411 return result; 412 } 413 414 /** 415 * reads the capabilities from the remote WMS by performing a GetCapabilities request against 416 * it. 417 * 418 * @param request 419 * capabilities request 420 */ 421 protected WMSCapabilities handleGetCapabilities( WMSGetCapabilities request ) 422 throws OGCWebServiceException { 423 424 URL url = null; 425 426 if ( request.getVersion().equals( "1.0.0" ) ) { 427 url = addresses.get( CAPABILITIES_NAME ); 428 } else { 429 url = addresses.get( GETCAPABILITIES_NAME ); 430 } 431 432 String param = request.getRequestParameter(); 433 String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param; 434 435 WMSCapabilities result = null; 436 437 try { 438 URL ur = new URL( us ); 439 // get map from the remote service 440 NetWorker nw = new NetWorker( ur ); 441 byte[] b = nw.getDataAsByteArr( 20000 ); 442 String contentType = nw.getContentType(); 443 444 if ( MimeTypeMapper.isKnownMimeType( contentType ) ) { 445 // create a WMSCapabilitiesTEMP instance from the result 446 StringReader reader = new StringReader( new String( b ) ); 447 WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument(); 448 doc.load( reader, XMLFragment.DEFAULT_URL ); 449 result = (WMSCapabilities) doc.parseCapabilities(); 450 } else { 451 throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", 452 "Response of the remote WMS contains unknown content type: " 453 + contentType + ";request: " + param ); 454 } 455 } catch ( Exception e ) { 456 throw new OGCWebServiceException( 457 "RemoteWMS:handleGetCapabilities", 458 "Could not get map from RemoteWMS: " 459 + capabilities.getServiceIdentification().getTitle() 460 + "; request: " + param + "; " + e.toString() ); 461 } 462 463 return result; 464 } 465 466 /** 467 * 468 * 469 * @param request 470 * get styles request (WMS 1.1.1 - SLD) 471 */ 472 protected Object handleGetStyles( GetStyles request ) 473 throws OGCWebServiceException { 474 475 URL url = addresses.get( GETSTYLES_NAME ); 476 477 if ( url == null ) { 478 throw new OGCWebServiceException( "GetStyles is not supported by the RemoteWMS: " 479 + capabilities.getServiceIdentification().getTitle() ); 480 } 481 482 String param = request.getRequestParameter(); 483 String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param; 484 485 // FIXME 486 // TODO 487 return null; 488 } 489 490 /** 491 * 492 * 493 * @param request 494 * put styles request (WMS 1.1.1 - SLD) 495 */ 496 protected Object handlePutStyles( PutStyles request ) 497 throws OGCWebServiceException { 498 499 URL url = addresses.get( PUTSTYLES_NAME ); 500 501 if ( url == null ) { 502 throw new OGCWebServiceException( "PUTSTYLES is not supported by the RemoteWMS: " 503 + capabilities.getServiceIdentification().getTitle() ); 504 } 505 506 String param = request.getRequestParameter(); 507 String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param; 508 509 // FIXME 510 // TODO 511 512 return null; 513 } 514 515 /** 516 * 517 * 518 * @param request 519 * describe layer request (WMS 1.1.1 - SLD) 520 */ 521 protected Object handleDescribeLayer( DescribeLayer request ) 522 throws OGCWebServiceException { 523 524 URL url = addresses.get( DESCRIBELAYER_NAME ); 525 526 if ( url == null ) { 527 throw new OGCWebServiceException( "DESCRIBELAYER is not supported by the RemoteWMS: " 528 + capabilities.getServiceIdentification().getTitle() ); 529 } 530 531 String param = request.getRequestParameter(); 532 String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param; 533 534 // FIXME 535 // TODO 536 537 return null; 538 } 539 540 /** 541 * 542 * 543 * @param request 544 * describe layer request (WMS 1.1.1 - SLD) 545 */ 546 protected Object handleGetLegendGraphic( GetLegendGraphic request ) 547 throws OGCWebServiceException { 548 549 URL url = addresses.get( GETLEGENDGRAPHIC_NAME ); 550 551 if ( url == null ) { 552 throw new OGCWebServiceException( "GETLEGENDGRAPHIC is not supported by the RemoteWMS: " 553 + capabilities.getServiceIdentification().getTitle() ); 554 } 555 556 String param = request.getRequestParameter(); 557 String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param; 558 559 // FIXME 560 // TODO 561 562 return null; 563 } 564 565 /** 566 * 567 * 568 * @param is 569 * 570 * @return thr content as String 571 * 572 * @throws IOException 573 */ 574 protected String getInputStreamContent( InputStream is ) 575 throws IOException { 576 StringBuffer sb = new StringBuffer( 1000 ); 577 int c = 0; 578 579 while ( ( c = is.read() ) >= 0 ) { 580 sb.append( (char) c ); 581 } 582 583 is.close(); 584 return sb.toString(); 585 } 586 587 }