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    }