001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wms/RemoteWMService.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    package org.deegree.ogcwebservices.wms;
037    
038    import static org.deegree.enterprise.WebUtils.enableProxyUsage;
039    import static org.deegree.framework.util.MapUtils.DEFAULT_PIXEL_SIZE;
040    import static org.deegree.framework.util.MapUtils.calcScale;
041    import static org.deegree.model.spatialschema.GeometryFactory.createEnvelope;
042    import static org.deegree.ogcwebservices.OWSUtils.validateHTTPGetBaseURL;
043    
044    import java.awt.image.BufferedImage;
045    import java.io.IOException;
046    import java.io.InputStream;
047    import java.io.StringReader;
048    import java.net.MalformedURLException;
049    import java.net.URL;
050    import java.util.HashMap;
051    import java.util.HashSet;
052    import java.util.Iterator;
053    import java.util.LinkedList;
054    import java.util.List;
055    import java.util.Properties;
056    
057    import javax.imageio.ImageIO;
058    import javax.media.jai.JAI;
059    import javax.media.jai.RenderedOp;
060    
061    import org.apache.commons.httpclient.Header;
062    import org.apache.commons.httpclient.HttpClient;
063    import org.apache.commons.httpclient.HttpException;
064    import org.apache.commons.httpclient.methods.GetMethod;
065    import org.deegree.datatypes.QualifiedName;
066    import org.deegree.framework.log.ILogger;
067    import org.deegree.framework.log.LoggerFactory;
068    import org.deegree.framework.util.BootLogger;
069    import org.deegree.framework.util.CharsetUtils;
070    import org.deegree.framework.util.MimeTypeMapper;
071    import org.deegree.framework.util.NetWorker;
072    import org.deegree.framework.util.StringTools;
073    import org.deegree.framework.xml.XMLFragment;
074    import org.deegree.i18n.Messages;
075    import org.deegree.model.crs.CRSFactory;
076    import org.deegree.model.crs.CRSTransformationException;
077    import org.deegree.model.crs.CoordinateSystem;
078    import org.deegree.model.crs.GeoTransformer;
079    import org.deegree.model.crs.UnknownCRSException;
080    import org.deegree.model.spatialschema.Envelope;
081    import org.deegree.ogcwebservices.OGCWebService;
082    import org.deegree.ogcwebservices.OGCWebServiceException;
083    import org.deegree.ogcwebservices.OGCWebServiceRequest;
084    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
085    import org.deegree.ogcwebservices.wms.capabilities.Layer;
086    import org.deegree.ogcwebservices.wms.capabilities.LayerBoundingBox;
087    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
088    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
089    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
090    import org.deegree.ogcwebservices.wms.operation.DescribeLayer;
091    import org.deegree.ogcwebservices.wms.operation.GetFeatureInfo;
092    import org.deegree.ogcwebservices.wms.operation.GetLegendGraphic;
093    import org.deegree.ogcwebservices.wms.operation.GetMap;
094    import org.deegree.ogcwebservices.wms.operation.GetStyles;
095    import org.deegree.ogcwebservices.wms.operation.PutStyles;
096    import org.deegree.ogcwebservices.wms.operation.WMSGetCapabilities;
097    import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory;
098    import org.deegree.owscommon_new.DCP;
099    import org.deegree.owscommon_new.HTTP;
100    import org.deegree.owscommon_new.Operation;
101    import org.deegree.owscommon_new.OperationsMetadata;
102    import org.xml.sax.SAXException;
103    
104    import com.sun.media.jai.codec.MemoryCacheSeekableStream;
105    
106    /**
107     * An instance of the class acts as a wrapper to a remote WMS.
108     *
109     * @version $Revision: 18195 $
110     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
111     */
112    public class RemoteWMService implements OGCWebService {
113    
114        private static ILogger LOG = LoggerFactory.getLogger( RemoteWMService.class );
115    
116        private static final String GETCAPABILITIES_NAME = "GetCapabilities";
117    
118        private static final String CAPABILITIES_NAME = "Capabilities";
119    
120        private static final String GETMAP_NAME = "GetMap";
121    
122        private static final String MAP_NAME = "Map";
123    
124        private static final String GETFEATUREINFO_NAME = "GetFeatureInfo";
125    
126        private static final String FEATUREINFO_NAME = "FeatureInfo";
127    
128        private static final String DESCRIBELAYER_NAME = "DescribeLayer";
129    
130        private static final String GETLEGENDGRAPHIC_NAME = "GetLegendGraphic";
131    
132        private static final String GETSTYLES_NAME = "GetStyles";
133    
134        private static final String PUTSTYLES_NAME = "PutStyles";
135    
136        // private static final String UNKNOWN_NAME = "Unknown";
137    
138        protected HashMap<String, URL> addresses = null;
139    
140        protected WMSCapabilities capabilities = null;
141    
142        private static Properties properties;
143        static {
144            if ( properties == null ) {
145                try {
146                    properties = new Properties();
147                    InputStream is = RemoteWMService.class.getResourceAsStream( "remotewmservice.properties" );
148                    properties.load( is );
149                    is.close();
150                } catch ( Exception e ) {
151                    BootLogger.logError( e.getMessage(), e );
152                }
153            }
154        }
155    
156        /**
157         * Creates a new instance of RemoteWMService
158         *
159         * @param capabilities
160         */
161        public RemoteWMService( WMSCapabilities capabilities ) {
162            this.capabilities = capabilities;
163            addresses = new HashMap<String, URL>();
164    
165            // get GetCapabilities operation address
166            List<DCP> dcps = null;
167            HTTP http = null;
168    
169            OperationsMetadata om = capabilities.getOperationMetadata();
170    
171            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
172                dcps = om.getOperation( new QualifiedName( CAPABILITIES_NAME ) ).getDCP();
173                for ( DCP dcp : dcps )
174                    if ( dcp instanceof HTTP )
175                        http = (HTTP) dcp;
176                if ( http != null ) {
177                    addresses.put( CAPABILITIES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
178                }
179            } else {
180                dcps = om.getOperation( new QualifiedName( GETCAPABILITIES_NAME ) ).getDCP();
181                for ( DCP dcp : dcps )
182                    if ( dcp instanceof HTTP )
183                        http = (HTTP) dcp;
184                if ( http != null ) {
185                    addresses.put( GETCAPABILITIES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
186                }
187            }
188    
189            // get GetMap operation address
190            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
191                dcps = om.getOperation( new QualifiedName( MAP_NAME ) ).getDCP();
192                for ( DCP dcp : dcps )
193                    if ( dcp instanceof HTTP )
194                        http = (HTTP) dcp;
195                if ( http != null ) {
196                    addresses.put( MAP_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
197                }
198            } else {
199                dcps = om.getOperation( new QualifiedName( GETMAP_NAME ) ).getDCP();
200                for ( DCP dcp : dcps )
201                    if ( dcp instanceof HTTP )
202                        http = (HTTP) dcp;
203                if ( http != null ) {
204                    addresses.put( GETMAP_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
205                }
206            }
207    
208            // get GetFeatureInfo operation address
209            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
210                Operation operation = om.getOperation( new QualifiedName( FEATUREINFO_NAME ) );
211    
212                if ( operation != null ) {
213                    dcps = operation.getDCP();
214                    for ( DCP dcp : dcps )
215                        if ( dcp instanceof HTTP )
216                            http = (HTTP) dcp;
217                    if ( http != null ) {
218                        addresses.put( FEATUREINFO_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
219                    }
220                }
221            } else {
222                Operation operation = om.getOperation( new QualifiedName( GETFEATUREINFO_NAME ) );
223    
224                if ( operation != null ) {
225                    dcps = operation.getDCP();
226                    for ( DCP dcp : dcps )
227                        if ( dcp instanceof HTTP )
228                            http = (HTTP) dcp;
229                    if ( http != null ) {
230                        addresses.put( GETFEATUREINFO_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
231                    }
232                }
233            }
234    
235            // get GetLegendGraphic operation address
236            Operation operation = om.getOperation( new QualifiedName( GETLEGENDGRAPHIC_NAME ) );
237    
238            if ( operation != null ) {
239                dcps = operation.getDCP();
240                for ( DCP dcp : dcps )
241                    if ( dcp instanceof HTTP )
242                        http = (HTTP) dcp;
243                if ( http != null ) {
244                    addresses.put( GETLEGENDGRAPHIC_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
245                }
246            }
247    
248            // get GetStyles operation address
249            operation = om.getOperation( new QualifiedName( GETSTYLES_NAME ) );
250    
251            if ( operation != null ) {
252                dcps = operation.getDCP();
253                for ( DCP dcp : dcps )
254                    if ( dcp instanceof HTTP )
255                        http = (HTTP) dcp;
256                if ( http != null ) {
257                    addresses.put( GETSTYLES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
258                }
259            }
260    
261            // get PutStyles operation address
262            operation = om.getOperation( new QualifiedName( PUTSTYLES_NAME ) );
263    
264            if ( operation != null ) {
265                dcps = operation.getDCP();
266                for ( DCP dcp : dcps )
267                    if ( dcp instanceof HTTP )
268                        http = (HTTP) dcp;
269                if ( http != null ) {
270                    addresses.put( PUTSTYLES_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
271                }
272            }
273    
274            // get DescribeLayer operation address
275            operation = om.getOperation( new QualifiedName( DESCRIBELAYER_NAME ) );
276    
277            if ( operation != null ) {
278                dcps = operation.getDCP();
279                for ( DCP dcp : dcps )
280                    if ( dcp instanceof HTTP )
281                        http = (HTTP) dcp;
282                if ( http != null ) {
283                    addresses.put( DESCRIBELAYER_NAME, http.getLinks().get( 0 ).getLinkage().getHref() );
284                }
285            }
286    
287        }
288    
289        public OGCCapabilities getCapabilities() {
290            return capabilities;
291        }
292    
293        private HashSet<CoordinateSystem> getSupportedCoordinateSystems( GetMap getMap )
294                                throws UnknownCRSException {
295            HashSet<CoordinateSystem> crs = new HashSet<CoordinateSystem>();
296            List<Layer> layers = new LinkedList<Layer>();
297            for ( GetMap.Layer l : getMap.getLayers() ) {
298                if ( l == null ) {
299                    continue; // unclear when/why this can happen
300                }
301                Layer lay = capabilities.getLayer( l.getName() );
302                while ( lay.getParent() != null ) {
303                    layers.add( lay );
304                    lay = lay.getParent();
305                }
306            }
307            for ( Layer l : layers ) {
308                for ( LayerBoundingBox bbox : l.getBoundingBoxes() ) {
309                    if ( bbox.getCoordinateSystem() != null ) {
310                        crs.add( bbox.getCoordinateSystem() );
311                    }
312                }
313                for ( String srs : l.getSrs() ) {
314                    crs.add( CRSFactory.create( srs ) );
315                }
316            }
317            return crs;
318        }
319    
320        /**
321         * the method performs the handling of the passed OGCWebServiceEvent directly and returns the result to the calling
322         * class/method
323         *
324         * @param request
325         *            request (WMS, WCS, WFS, WCAS, WCTS, WTS, Gazetter) to perform
326         *
327         * @throws OGCWebServiceException
328         */
329        public Object doService( OGCWebServiceRequest request )
330                                throws OGCWebServiceException {
331            Object o = null;
332            if ( request instanceof GetMap ) {
333                o = handleGetMap( (GetMap) request );
334                o = WMSProtocolFactory.createGetMapResponse( request, null, o );
335            } else if ( request instanceof GetFeatureInfo ) {
336                o = handleFeatureInfo( (GetFeatureInfo) request );
337                o = WMSProtocolFactory.createGetFeatureInfoResponse( request, null, (String) o );
338            } else if ( request instanceof GetLegendGraphic ) {
339                o = handleGetLegendGraphic( (GetLegendGraphic) request );
340                o = WMSProtocolFactory.createGetLegendGraphicResponse( request, o );
341            }
342            /*
343             * else if ( request instanceof WMSGetCapabilities) { handleGetCapabilities( (WMSGetCapabilities)request, client
344             * ); } else if ( request instanceof GetStyles ) { handleGetStyles( (GetStyles)request, client ); } else if (
345             * request instanceof PutStyles ) { handlePutStyles( (PutStyles)request, client ); } else if ( request
346             * instanceof DescribeLayer ) { handleDescribeLayer( (DescribeLayer)request, client ); } else if ( request
347             * instanceof GetLegendGraphic ) { handleGetLegendGraphic( (GetLegendGraphic)request, client ); }
348             */
349    
350            return o;
351    
352        }
353    
354        // checks for excessive &
355        private static String constructRequestURL( String params, String url ) {
356            if ( url.endsWith( "?" ) && params.startsWith( "&" ) ) {
357                return url + params.substring( 1 );
358            }
359    
360            return url + params;
361        }
362    
363        /**
364         * performs a GetMap request against the remote service. The result contains the map decoded in the desired format
365         * as a byte array.
366         *
367         * @param request
368         *            GetMap request
369         * @return the requested map-image
370         * @throws OGCWebServiceException
371         *             if the url in the request is <code>null</code>
372         */
373        protected Object handleGetMap( GetMap request )
374                                throws OGCWebServiceException {
375    
376            URL url = null;
377    
378            if ( request.getVersion().equals( "1.0.0" ) ) {
379                url = addresses.get( MAP_NAME );
380            } else {
381                url = addresses.get( GETMAP_NAME );
382            }
383    
384            try {
385                Envelope requestBBOX = request.getBoundingBox();
386                HashSet<CoordinateSystem> crss = getSupportedCoordinateSystems( request );
387                CoordinateSystem requestCRS = CRSFactory.create( request.getSrs() );
388                requestBBOX = createEnvelope( requestBBOX.getMin(), requestBBOX.getMax(), requestCRS );
389                if ( !crss.contains( requestCRS ) ) {
390                    Iterator<CoordinateSystem> iterator = crss.iterator();
391                    CoordinateSystem dataCRS = iterator.hasNext() ? iterator.next() : null;
392                    if ( dataCRS != null ) {
393                        GeoTransformer transformer = new GeoTransformer( dataCRS );
394                        GeoTransformer transformBack = new GeoTransformer( requestCRS );
395                        Envelope dataBBOX = transformer.transform( requestBBOX, requestCRS, true );
396    
397                        int origWidth = request.getWidth();
398                        int origHeight = request.getHeight();
399    
400                        double scale = calcScale( origWidth, origHeight, requestBBOX, requestCRS, DEFAULT_PIXEL_SIZE );
401                        double newScale = calcScale( origWidth, origHeight, dataBBOX, dataCRS, DEFAULT_PIXEL_SIZE );
402                        double ratio = scale / newScale;
403    
404                        LOG.logDebug( "Requesting transformed bounding box " + dataBBOX + " in srs "
405                                      + dataCRS.getIdentifier() );
406                        request.setBoundingBox( dataBBOX );
407                        request.setSrs( dataCRS.getIdentifier() );
408                        request.setWidth( (int) ( origWidth * ratio ) );
409                        request.setHeight( (int) ( origHeight * ratio ) );
410                        Object o = handleGetMap( request );
411                        if ( o instanceof BufferedImage ) {
412                            return transformBack.transform( (BufferedImage) o, dataBBOX, requestBBOX, origWidth,
413                                                            origHeight, 16, 3, null );
414                        }
415    
416                        return o;
417                    }
418                }
419            } catch ( UnknownCRSException e ) {
420                LOG.logError( e.getLocalizedMessage(), e );
421            } catch ( CRSTransformationException e ) {
422                LOG.logError( "An error occurred while transforming bounding boxes (this should not happen)", e );
423            }
424    
425            String us = constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
426    
427            LOG.logDebug( "remote wms getmap", us );
428    
429            if ( capabilities.getVersion().compareTo( "1.0.0" ) <= 0 ) {
430                us = StringTools.replace( us, "TRANSPARENCY", "TRANSPARENT", false );
431                us = StringTools.replace( us, "GetMap", "map", false );
432                us = StringTools.replace( us, "image/", "", false );
433            }
434    
435            Object result = null;
436            try {
437                HttpClient client = new HttpClient();
438                enableProxyUsage( client, new URL( us ) );
439                int timeout = 25000;
440                if ( properties != null && properties.getProperty( "timeout" ) != null ) {
441                    timeout = Integer.parseInt( properties.getProperty( "timeout" ) );
442                }
443                LOG.logDebug( "timeout is:", timeout );
444                client.getHttpConnectionManager().getParams().setSoTimeout( timeout );
445                GetMethod get = new GetMethod( us );
446                client.executeMethod( get );
447                InputStream is = get.getResponseBodyAsStream();
448                Header header = get.getResponseHeader( "Content-type" );
449    
450                String contentType = header.getValue();
451                String[] tmp = StringTools.toArray( contentType, ";", true );
452                for ( int i = 0; i < tmp.length; i++ ) {
453                    if ( tmp[i].indexOf( "image" ) > -1 ) {
454                        contentType = tmp[i];
455                        break;
456                    }
457                    contentType = tmp[0];
458                }
459    
460                if ( MimeTypeMapper.isImageType( contentType ) && MimeTypeMapper.isKnownImageType( contentType ) ) {
461                    MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
462                    RenderedOp rop = JAI.create( "stream", mcss );
463                    result = rop.getAsBufferedImage();
464                    mcss.close();
465                } else {
466                    // extract remote (error) message if the response
467                    // contains a known mime type
468                    String res = "";
469                    if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
470                        res = "Remote-WMS message: " + getInputStreamContent( is );
471                    } else {
472                        res = Messages.getMessage( "REMOTEWMS_GETMAP_INVALID_RESULT", contentType, us );
473                    }
474                    throw new OGCWebServiceException( "RemoteWMS:handleGetMap", res );
475                }
476            } catch ( HttpException e ) {
477                LOG.logError( e.getMessage(), e );
478                String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR",
479                                                  capabilities.getServiceIdentification().getTitle(), us );
480                throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
481            } catch ( IOException e ) {
482                LOG.logError( e.getMessage(), e );
483                String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR",
484                                                  capabilities.getServiceIdentification().getTitle(), us );
485                throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
486            }
487            // catch ( Exception e ) {
488            // LOG.logError( e.getMessage(), e );
489            // String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR",
490            // capabilities.getServiceIdentification().getTitle(), us );
491            // throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
492            // }
493    
494            return result;
495        }
496    
497        /**
498         * reads feature infos from the remote WMS by performing a FeatureInfo request against it. As long the result of a
499         * FeatureInfo request is generic (for usual it is som HTML) it isn't easy to combine the result with that of other
500         * WMS's
501         *
502         * @param request
503         *            feature info request
504         * @return the response of the GetFeatureInfo request.
505         * @throws OGCWebServiceException
506         *             if the request could not be excuted correctly.
507         */
508        protected Object handleFeatureInfo( GetFeatureInfo request )
509                                throws OGCWebServiceException {
510    
511            URL url = null;
512    
513            if ( request.getVersion().equals( "1.0.0" ) ) {
514                url = addresses.get( FEATUREINFO_NAME );
515            } else {
516                url = addresses.get( GETFEATUREINFO_NAME );
517            }
518    
519            if ( url == null ) {
520                String msg = Messages.getMessage( "REMOTEWMS_GFI_NOT_SUPPORTED",
521                                                  capabilities.getServiceIdentification().getTitle() );
522                throw new OGCWebServiceException( msg );
523            }
524    
525            try {
526                GetMap gm = request.getGetMapRequestCopy();
527                Envelope requestBBOX = gm.getBoundingBox();
528                HashSet<CoordinateSystem> crss = getSupportedCoordinateSystems( gm );
529                CoordinateSystem requestCRS = CRSFactory.create( gm.getSrs() );
530                if ( !crss.contains( requestCRS ) ) {
531                    CoordinateSystem dataCRS = crss.iterator().next();
532                    if ( dataCRS != null ) {
533                        GeoTransformer transformer = new GeoTransformer( dataCRS );
534                        GeoTransformer transformBack = new GeoTransformer( requestCRS );
535                        Envelope dataBBOX = transformer.transform( requestBBOX, requestCRS, true );
536    
537                        int origWidth = gm.getWidth();
538                        int origHeight = gm.getHeight();
539    
540                        double scale = calcScale( origWidth, origHeight, requestBBOX, requestCRS, DEFAULT_PIXEL_SIZE );
541                        double newScale = calcScale( origWidth, origHeight, dataBBOX, dataCRS, DEFAULT_PIXEL_SIZE );
542                        double ratio = scale / newScale;
543    
544                        LOG.logDebug( "Requesting transformed bounding box " + dataBBOX + " in srs "
545                                      + dataCRS.getIdentifier() );
546                        gm.setBoundingBox( dataBBOX );
547                        gm.setSrs( dataCRS.getIdentifier() );
548                        gm.setWidth( (int) ( origWidth * ratio ) );
549                        gm.setHeight( (int) ( origHeight * ratio ) );
550    
551                        Object o = handleFeatureInfo( request );
552                        if ( o instanceof BufferedImage ) {
553                            return transformBack.transform( (BufferedImage) o, dataBBOX, requestBBOX, origWidth,
554                                                            origHeight, 16, 3, null );
555                        }
556    
557                        return o;
558                    }
559                }
560            } catch ( UnknownCRSException e ) {
561                LOG.logError( e.getLocalizedMessage(), e );
562            } catch ( CRSTransformationException e ) {
563                LOG.logError( "An error occurred while transforming bounding boxes (this should not happen)", e );
564            }
565    
566            String us = constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
567    
568            String result = null;
569            try {
570                LOG.logDebug( "GetFeatureInfo: ", us );
571                URL ur = new URL( us );
572                // get map from the remote service
573                NetWorker nw = new NetWorker( ur );
574                byte[] b = nw.getDataAsByteArr( 20000 );
575                String contentType = nw.getContentType();
576    
577                // extract content charset if available; otherwise use configured system charset
578                String charset = null;
579                LOG.logDebug( "content type: ", contentType );
580                if ( contentType != null ) {
581                    String[] tmp = StringTools.toArray( contentType, ";", false );
582                    if ( tmp.length == 2 ) {
583                        charset = tmp[1].substring( tmp[1].indexOf( '=' ) + 1, tmp[1].length() );
584                    } else {
585                        charset = CharsetUtils.getSystemCharset();
586                    }
587                } else {
588                    charset = CharsetUtils.getSystemCharset();
589                }
590    
591                // commented out checks, we're trying to fix broken GFI responses here, after all
592                // if ( contentType != null && contentType.toLowerCase().startsWith( "application/vnd.ogc.gml" ) ) {
593                result = new String( b, charset );
594                // } else {
595                // throw new OGCWebServiceException( "RemoteWMS:handleFeatureInfo" );
596                // }
597            } catch ( Exception e ) {
598                LOG.logError( e.getMessage(), e );
599                String msg = Messages.getMessage( "REMOTEWMS_GFI_GENERAL_ERROR",
600                                                  capabilities.getServiceIdentification().getTitle(), us );
601                throw new OGCWebServiceException( "RemoteWMS:handleFeatureInfo", msg );
602            }
603    
604            return result;
605        }
606    
607        /**
608         * reads the capabilities from the remote WMS by performing a GetCapabilities request against it.
609         *
610         * @param request
611         *            capabilities request
612         * @return remote capabilities
613         * @throws OGCWebServiceException
614         *             if the request could not be executed correctly.
615         */
616        protected WMSCapabilities handleGetCapabilities( WMSGetCapabilities request )
617                                throws OGCWebServiceException {
618    
619            URL url = null;
620    
621            if ( request.getVersion().equals( "1.0.0" ) ) {
622                url = addresses.get( CAPABILITIES_NAME );
623            } else {
624                url = addresses.get( GETCAPABILITIES_NAME );
625            }
626    
627            String us = constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
628    
629            WMSCapabilities result = null;
630    
631            try {
632                URL ur = new URL( us );
633                // get map from the remote service
634                NetWorker nw = new NetWorker( ur );
635                byte[] b = nw.getDataAsByteArr( 20000 );
636                String contentType = nw.getContentType();
637    
638                if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
639                    // create a WMSCapabilitiesTEMP instance from the result
640                    StringReader reader = new StringReader( new String( b ) );
641                    WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
642                    doc.load( reader, XMLFragment.DEFAULT_URL );
643                    doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( doc.getRootElement() );
644                    result = (WMSCapabilities) doc.parseCapabilities();
645                } else {
646                    String msg = Messages.getMessage( "REMOTEWMS_GETCAPS_INVALID_CONTENTTYPE", contentType, us );
647                    throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
648                }
649            } catch ( Exception e ) {
650                LOG.logError( e.getMessage(), e );
651                String msg = Messages.getMessage( "REMOTEWMS_GETCAPS_GENERAL_ERROR",
652                                                  capabilities.getServiceIdentification().getTitle(), us );
653                throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
654            }
655    
656            return result;
657        }
658    
659        /**
660         *
661         *
662         * @param request
663         *            get styles request (WMS 1.1.1 - SLD)
664         * @return <code>null</code>
665         * @throws OGCWebServiceException
666         *             if the url in the request is <code>null</code>
667         */
668        protected Object handleGetStyles( GetStyles request )
669                                throws OGCWebServiceException {
670    
671            URL url = addresses.get( GETSTYLES_NAME );
672    
673            if ( url == null ) {
674                throw new OGCWebServiceException( "GetStyles is not supported by the RemoteWMS: "
675                                                  + capabilities.getServiceIdentification().getTitle() );
676            }
677    
678            constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
679    
680            // FIXME
681            // TODO
682            return null;
683        }
684    
685        /**
686         *
687         *
688         * @param request
689         *            put styles request (WMS 1.1.1 - SLD)
690         * @return <code>null</code>
691         * @throws OGCWebServiceException
692         *             if the url in the request is <code>null</code>
693         */
694        protected Object handlePutStyles( PutStyles request )
695                                throws OGCWebServiceException {
696    
697            URL url = addresses.get( PUTSTYLES_NAME );
698    
699            if ( url == null ) {
700                throw new OGCWebServiceException( "PUTSTYLES is not supported by the RemoteWMS: "
701                                                  + capabilities.getServiceIdentification().getTitle() );
702            }
703    
704            constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
705    
706            // FIXME
707            // TODO
708    
709            return null;
710        }
711    
712        /**
713         *
714         *
715         * @param request
716         *            describe layer request (WMS 1.1.1 - SLD)
717         * @return <code>null</code>
718         * @throws OGCWebServiceException
719         *             if the url in the request is <code>null</code>
720         */
721        protected Object handleDescribeLayer( DescribeLayer request )
722                                throws OGCWebServiceException {
723    
724            URL url = addresses.get( DESCRIBELAYER_NAME );
725    
726            if ( url == null ) {
727                throw new OGCWebServiceException( "DESCRIBELAYER is not supported by the RemoteWMS: "
728                                                  + capabilities.getServiceIdentification().getTitle() );
729            }
730    
731            constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
732    
733            // FIXME
734            // TODO
735    
736            return null;
737        }
738    
739        /**
740         *
741         *
742         * @param request
743         *            describe layer request (WMS 1.1.1 - SLD)
744         * @return <code>null</code>
745         * @throws OGCWebServiceException
746         *             if the url in the request is <code>null</code>
747         */
748        protected Object handleGetLegendGraphic( GetLegendGraphic request )
749                                throws OGCWebServiceException {
750    
751            URL url = addresses.get( GETLEGENDGRAPHIC_NAME );
752    
753            if ( url == null ) {
754                throw new OGCWebServiceException( "GETLEGENDGRAPHIC is not supported by the RemoteWMS: "
755                                                  + capabilities.getServiceIdentification().getTitle() );
756            }
757    
758            String address = constructRequestURL( request.getRequestParameter(),
759                                                  validateHTTPGetBaseURL( url.toExternalForm() ) );
760    
761            try {
762                URL theURL = new URL( address );
763                LOG.logDebug( "Getting legend from remote WMS, URL: ", theURL );
764                BufferedImage img = ImageIO.read( theURL );
765                if ( img == null ) {
766                    XMLFragment doc = new XMLFragment( theURL );
767                    LOG.logDebug( "Got error message: ", doc.getAsPrettyString() );
768                    return new IOException( "Service exception recieved" );
769                }
770                return img;
771            } catch ( MalformedURLException e ) {
772                return e;
773            } catch ( IOException e ) {
774                return e;
775            } catch ( SAXException e ) {
776                return e;
777            }
778        }
779    
780        /**
781         *
782         *
783         * @param is
784         *
785         * @return thr content as String
786         *
787         * @throws IOException
788         */
789        protected String getInputStreamContent( InputStream is )
790                                throws IOException {
791            StringBuffer sb = new StringBuffer( 1000 );
792            int c = 0;
793    
794            while ( ( c = is.read() ) >= 0 ) {
795                sb.append( (char) c );
796            }
797    
798            is.close();
799            return sb.toString();
800        }
801    
802    }