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 }