001    //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/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: 32293 $
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                    try {
315                        crs.add( CRSFactory.create( srs ) );
316                    } catch ( Exception e ) {
317                        LOG.logWarning( "CRS: " + crs + " is not known and will be ignored" );
318                    }
319                }
320            }
321            return crs;
322        }
323    
324        /**
325         * the method performs the handling of the passed OGCWebServiceEvent directly and returns the result to the calling
326         * class/method
327         * 
328         * @param request
329         *            request (WMS, WCS, WFS, WCAS, WCTS, WTS, Gazetter) to perform
330         * 
331         * @throws OGCWebServiceException
332         */
333        public Object doService( OGCWebServiceRequest request )
334                                throws OGCWebServiceException {
335            Object o = null;
336            if ( request instanceof GetMap ) {
337                o = handleGetMap( (GetMap) request );
338                o = WMSProtocolFactory.createGetMapResponse( request, null, o );
339            } else if ( request instanceof GetFeatureInfo ) {
340                o = handleFeatureInfo( (GetFeatureInfo) request );
341                o = WMSProtocolFactory.createGetFeatureInfoResponse( request, null, (String) o );
342            } else if ( request instanceof GetLegendGraphic ) {
343                o = handleGetLegendGraphic( (GetLegendGraphic) request );
344                o = WMSProtocolFactory.createGetLegendGraphicResponse( request, o );
345            }
346            /*
347             * else if ( request instanceof WMSGetCapabilities) { handleGetCapabilities( (WMSGetCapabilities)request, client
348             * ); } else if ( request instanceof GetStyles ) { handleGetStyles( (GetStyles)request, client ); } else if (
349             * request instanceof PutStyles ) { handlePutStyles( (PutStyles)request, client ); } else if ( request
350             * instanceof DescribeLayer ) { handleDescribeLayer( (DescribeLayer)request, client ); } else if ( request
351             * instanceof GetLegendGraphic ) { handleGetLegendGraphic( (GetLegendGraphic)request, client ); }
352             */
353    
354            return o;
355    
356        }
357    
358        // checks for excessive &
359        private static String constructRequestURL( String params, String url ) {
360            if ( url.endsWith( "?" ) && params.startsWith( "&" ) ) {
361                return url + params.substring( 1 );
362            }
363    
364            return url + params;
365        }
366    
367        /**
368         * performs a GetMap request against the remote service. The result contains the map decoded in the desired format
369         * as a byte array.
370         * 
371         * @param request
372         *            GetMap request
373         * @return the requested map-image
374         * @throws OGCWebServiceException
375         *             if the url in the request is <code>null</code>
376         */
377        protected Object handleGetMap( GetMap request )
378                                throws OGCWebServiceException {
379    
380            URL url = null;
381    
382            if ( request.getVersion().equals( "1.0.0" ) ) {
383                url = addresses.get( MAP_NAME );
384            } else {
385                url = addresses.get( GETMAP_NAME );
386            }
387    
388            try {
389                Envelope requestBBOX = request.getBoundingBox();
390                HashSet<CoordinateSystem> crss = getSupportedCoordinateSystems( request );
391                CoordinateSystem requestCRS = CRSFactory.create( request.getSrs() );
392                requestBBOX = createEnvelope( requestBBOX.getMin(), requestBBOX.getMax(), requestCRS );
393                if ( !crss.contains( requestCRS ) ) {
394                    Iterator<CoordinateSystem> iterator = crss.iterator();
395                    CoordinateSystem dataCRS = iterator.hasNext() ? iterator.next() : null;
396                    if ( dataCRS != null ) {
397                        GeoTransformer transformer = new GeoTransformer( dataCRS );
398                        GeoTransformer transformBack = new GeoTransformer( requestCRS );
399                        Envelope dataBBOX = transformer.transform( requestBBOX, requestCRS, true );
400    
401                        int origWidth = request.getWidth();
402                        int origHeight = request.getHeight();
403    
404                        double scale = calcScale( origWidth, origHeight, requestBBOX, requestCRS, DEFAULT_PIXEL_SIZE );
405                        double newScale = calcScale( origWidth, origHeight, dataBBOX, dataCRS, DEFAULT_PIXEL_SIZE );
406                        double ratio = scale / newScale;
407                        if ( ratio < 1 ) {
408                            ratio = newScale / scale;
409                        }
410    
411                        LOG.logDebug( "Requesting transformed bounding box " + dataBBOX + " in srs "
412                                      + dataCRS.getIdentifier() );
413                        request.setBoundingBox( dataBBOX );
414                        request.setSrs( dataCRS.getIdentifier() );
415                        request.setWidth( (int) ( origWidth * ratio ) );
416                        request.setHeight( (int) ( origHeight * ratio ) );
417                        Object o = handleGetMap( request );
418                        if ( o instanceof BufferedImage ) {
419                            return transformBack.transform( (BufferedImage) o, dataBBOX, requestBBOX, origWidth,
420                                                            origHeight, 16, 3, null );
421                        }
422    
423                        return o;
424                    }
425                }
426            } catch ( UnknownCRSException e ) {
427                LOG.logError( e.getLocalizedMessage(), e );
428            } catch ( CRSTransformationException e ) {
429                LOG.logError( "An error occurred while transforming bounding boxes (this should not happen)", e );
430            }
431    
432            String us = constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
433    
434            LOG.logDebug( "remote wms getmap", us );
435    
436            if ( capabilities.getVersion().compareTo( "1.0.0" ) <= 0 ) {
437                us = StringTools.replace( us, "TRANSPARENCY", "TRANSPARENT", false );
438                us = StringTools.replace( us, "GetMap", "map", false );
439                us = StringTools.replace( us, "image/", "", false );
440            }
441    
442            Object result = null;
443            try {
444                HttpClient client = new HttpClient();
445                enableProxyUsage( client, new URL( us ) );
446                int timeout = 25000;
447                if ( properties != null && properties.getProperty( "timeout" ) != null ) {
448                    timeout = Integer.parseInt( properties.getProperty( "timeout" ) );
449                }
450                LOG.logDebug( "timeout is:", timeout );
451                client.getHttpConnectionManager().getParams().setSoTimeout( timeout );
452                GetMethod get = new GetMethod( us );
453                client.executeMethod( get );
454                InputStream is = get.getResponseBodyAsStream();
455                Header header = get.getResponseHeader( "Content-type" );
456    
457                String contentType = header.getValue();
458                String[] tmp = StringTools.toArray( contentType, ";", true );
459                for ( int i = 0; i < tmp.length; i++ ) {
460                    if ( tmp[i].indexOf( "image" ) > -1 ) {
461                        contentType = tmp[i];
462                        break;
463                    }
464                    contentType = tmp[0];
465                }
466    
467                if ( MimeTypeMapper.isImageType( contentType ) && MimeTypeMapper.isKnownImageType( contentType ) ) {
468                    MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
469                    RenderedOp rop = JAI.create( "stream", mcss );
470                    result = rop.getAsBufferedImage();
471                    mcss.close();
472                } else {
473                    // extract remote (error) message if the response
474                    // contains a known mime type
475                    String res = "";
476                    if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
477                        res = "Remote-WMS message: " + getInputStreamContent( is );
478                    } else {
479                        res = Messages.getMessage( "REMOTEWMS_GETMAP_INVALID_RESULT", contentType, us );
480                    }
481                    throw new OGCWebServiceException( "RemoteWMS:handleGetMap", res );
482                }
483            } catch ( HttpException e ) {
484                LOG.logError( e.getMessage(), e );
485                String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR",
486                                                  capabilities.getServiceIdentification().getTitle(), us );
487                throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
488            } catch ( IOException e ) {
489                LOG.logError( e.getMessage(), e );
490                String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR",
491                                                  capabilities.getServiceIdentification().getTitle(), us );
492                throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
493            }
494            // catch ( Exception e ) {
495            // LOG.logError( e.getMessage(), e );
496            // String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR",
497            // capabilities.getServiceIdentification().getTitle(), us );
498            // throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
499            // }
500    
501            return result;
502        }
503    
504        /**
505         * reads feature infos from the remote WMS by performing a FeatureInfo request against it. As long the result of a
506         * FeatureInfo request is generic (for usual it is som HTML) it isn't easy to combine the result with that of other
507         * WMS's
508         * 
509         * @param request
510         *            feature info request
511         * @return the response of the GetFeatureInfo request.
512         * @throws OGCWebServiceException
513         *             if the request could not be excuted correctly.
514         */
515        protected Object handleFeatureInfo( GetFeatureInfo request )
516                                throws OGCWebServiceException {
517    
518            URL url = null;
519    
520            if ( request.getVersion().equals( "1.0.0" ) ) {
521                url = addresses.get( FEATUREINFO_NAME );
522            } else {
523                url = addresses.get( GETFEATUREINFO_NAME );
524            }
525    
526            if ( url == null ) {
527                String msg = Messages.getMessage( "REMOTEWMS_GFI_NOT_SUPPORTED",
528                                                  capabilities.getServiceIdentification().getTitle() );
529                throw new OGCWebServiceException( msg );
530            }
531    
532            try {
533                GetMap gm = request.getGetMapRequestCopy();
534                Envelope requestBBOX = gm.getBoundingBox();
535                HashSet<CoordinateSystem> crss = getSupportedCoordinateSystems( gm );
536                CoordinateSystem requestCRS = CRSFactory.create( gm.getSrs() );
537                if ( !crss.contains( requestCRS ) ) {
538                    CoordinateSystem dataCRS = crss.iterator().next();
539                    if ( dataCRS != null ) {
540                        GeoTransformer transformer = new GeoTransformer( dataCRS );
541                        GeoTransformer transformBack = new GeoTransformer( requestCRS );
542                        Envelope dataBBOX = transformer.transform( requestBBOX, requestCRS, true );
543    
544                        int origWidth = gm.getWidth();
545                        int origHeight = gm.getHeight();
546    
547                        double scale = calcScale( origWidth, origHeight, requestBBOX, requestCRS, DEFAULT_PIXEL_SIZE );
548                        double newScale = calcScale( origWidth, origHeight, dataBBOX, dataCRS, DEFAULT_PIXEL_SIZE );
549                        double ratio = scale / newScale;
550    
551                        LOG.logDebug( "Requesting transformed bounding box " + dataBBOX + " in srs "
552                                      + dataCRS.getIdentifier() );
553                        gm.setBoundingBox( dataBBOX );
554                        gm.setSrs( dataCRS.getIdentifier() );
555                        gm.setWidth( (int) ( origWidth * ratio ) );
556                        gm.setHeight( (int) ( origHeight * ratio ) );
557    
558                        Object o = handleFeatureInfo( request );
559                        if ( o instanceof BufferedImage ) {
560                            return transformBack.transform( (BufferedImage) o, dataBBOX, requestBBOX, origWidth,
561                                                            origHeight, 16, 3, null );
562                        }
563    
564                        return o;
565                    }
566                }
567            } catch ( UnknownCRSException e ) {
568                LOG.logError( e.getLocalizedMessage(), e );
569            } catch ( CRSTransformationException e ) {
570                LOG.logError( "An error occurred while transforming bounding boxes (this should not happen)", e );
571            }
572    
573            String us = constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
574    
575            String result = null;
576            try {
577                LOG.logDebug( "GetFeatureInfo: ", us );
578                URL ur = new URL( us );
579                // get map from the remote service
580                NetWorker nw = new NetWorker( ur );
581                byte[] b = nw.getDataAsByteArr( 20000 );
582                String contentType = nw.getContentType();
583    
584                // extract content charset if available; otherwise use configured system charset
585                String charset = null;
586                LOG.logDebug( "content type: ", contentType );
587                if ( contentType != null ) {
588                    String[] tmp = StringTools.toArray( contentType, ";", false );
589                    if ( tmp.length == 2 ) {
590                        charset = tmp[1].substring( tmp[1].indexOf( '=' ) + 1, tmp[1].length() );
591                    } else {
592                        charset = CharsetUtils.getSystemCharset();
593                    }
594                } else {
595                    charset = CharsetUtils.getSystemCharset();
596                }
597    
598                // commented out checks, we're trying to fix broken GFI responses here, after all
599                // if ( contentType != null && contentType.toLowerCase().startsWith( "application/vnd.ogc.gml" ) ) {
600                result = new String( b, charset );
601                // } else {
602                // throw new OGCWebServiceException( "RemoteWMS:handleFeatureInfo" );
603                // }
604            } catch ( Exception e ) {
605                LOG.logError( e.getMessage(), e );
606                String msg = Messages.getMessage( "REMOTEWMS_GFI_GENERAL_ERROR",
607                                                  capabilities.getServiceIdentification().getTitle(), us );
608                throw new OGCWebServiceException( "RemoteWMS:handleFeatureInfo", msg );
609            }
610    
611            return result;
612        }
613    
614        /**
615         * reads the capabilities from the remote WMS by performing a GetCapabilities request against it.
616         * 
617         * @param request
618         *            capabilities request
619         * @return remote capabilities
620         * @throws OGCWebServiceException
621         *             if the request could not be executed correctly.
622         */
623        protected WMSCapabilities handleGetCapabilities( WMSGetCapabilities request )
624                                throws OGCWebServiceException {
625    
626            URL url = null;
627    
628            if ( request.getVersion().equals( "1.0.0" ) ) {
629                url = addresses.get( CAPABILITIES_NAME );
630            } else {
631                url = addresses.get( GETCAPABILITIES_NAME );
632            }
633    
634            String us = constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
635    
636            WMSCapabilities result = null;
637    
638            try {
639                URL ur = new URL( us );
640                // get map from the remote service
641                NetWorker nw = new NetWorker( ur );
642                byte[] b = nw.getDataAsByteArr( 20000 );
643                String contentType = nw.getContentType();
644    
645                if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
646                    // create a WMSCapabilitiesTEMP instance from the result
647                    StringReader reader = new StringReader( new String( b ) );
648                    WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
649                    doc.load( reader, XMLFragment.DEFAULT_URL );
650                    doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( doc.getRootElement() );
651                    result = (WMSCapabilities) doc.parseCapabilities();
652                } else {
653                    String msg = Messages.getMessage( "REMOTEWMS_GETCAPS_INVALID_CONTENTTYPE", contentType, us );
654                    throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
655                }
656            } catch ( Exception e ) {
657                LOG.logError( e.getMessage(), e );
658                String msg = Messages.getMessage( "REMOTEWMS_GETCAPS_GENERAL_ERROR",
659                                                  capabilities.getServiceIdentification().getTitle(), us );
660                throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
661            }
662    
663            return result;
664        }
665    
666        /**
667         * 
668         * 
669         * @param request
670         *            get styles request (WMS 1.1.1 - SLD)
671         * @return <code>null</code>
672         * @throws OGCWebServiceException
673         *             if the url in the request is <code>null</code>
674         */
675        protected Object handleGetStyles( GetStyles request )
676                                throws OGCWebServiceException {
677    
678            URL url = addresses.get( GETSTYLES_NAME );
679    
680            if ( url == null ) {
681                throw new OGCWebServiceException( "GetStyles is not supported by the RemoteWMS: "
682                                                  + capabilities.getServiceIdentification().getTitle() );
683            }
684    
685            constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
686    
687            // FIXME
688            // TODO
689            return null;
690        }
691    
692        /**
693         * 
694         * 
695         * @param request
696         *            put styles request (WMS 1.1.1 - SLD)
697         * @return <code>null</code>
698         * @throws OGCWebServiceException
699         *             if the url in the request is <code>null</code>
700         */
701        protected Object handlePutStyles( PutStyles request )
702                                throws OGCWebServiceException {
703    
704            URL url = addresses.get( PUTSTYLES_NAME );
705    
706            if ( url == null ) {
707                throw new OGCWebServiceException( "PUTSTYLES is not supported by the RemoteWMS: "
708                                                  + capabilities.getServiceIdentification().getTitle() );
709            }
710    
711            constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
712    
713            // FIXME
714            // TODO
715    
716            return null;
717        }
718    
719        /**
720         * 
721         * 
722         * @param request
723         *            describe layer request (WMS 1.1.1 - SLD)
724         * @return <code>null</code>
725         * @throws OGCWebServiceException
726         *             if the url in the request is <code>null</code>
727         */
728        protected Object handleDescribeLayer( DescribeLayer request )
729                                throws OGCWebServiceException {
730    
731            URL url = addresses.get( DESCRIBELAYER_NAME );
732    
733            if ( url == null ) {
734                throw new OGCWebServiceException( "DESCRIBELAYER is not supported by the RemoteWMS: "
735                                                  + capabilities.getServiceIdentification().getTitle() );
736            }
737    
738            constructRequestURL( request.getRequestParameter(), validateHTTPGetBaseURL( url.toExternalForm() ) );
739    
740            // FIXME
741            // TODO
742    
743            return null;
744        }
745    
746        /**
747         * 
748         * 
749         * @param request
750         *            describe layer request (WMS 1.1.1 - SLD)
751         * @return <code>null</code>
752         * @throws OGCWebServiceException
753         *             if the url in the request is <code>null</code>
754         */
755        protected Object handleGetLegendGraphic( GetLegendGraphic request )
756                                throws OGCWebServiceException {
757    
758            URL url = addresses.get( GETLEGENDGRAPHIC_NAME );
759    
760            if ( url == null ) {
761                throw new OGCWebServiceException( "GETLEGENDGRAPHIC is not supported by the RemoteWMS: "
762                                                  + capabilities.getServiceIdentification().getTitle() );
763            }
764    
765            String address = constructRequestURL( request.getRequestParameter(),
766                                                  validateHTTPGetBaseURL( url.toExternalForm() ) );
767    
768            try {
769                URL theURL = new URL( address );
770                LOG.logDebug( "Getting legend from remote WMS, URL: ", theURL );
771                BufferedImage img = ImageIO.read( theURL );
772                if ( img == null ) {
773                    XMLFragment doc = new XMLFragment( theURL );
774                    LOG.logDebug( "Got error message: ", doc.getAsPrettyString() );
775                    return new IOException( "Service exception recieved" );
776                }
777                return img;
778            } catch ( MalformedURLException e ) {
779                return e;
780            } catch ( IOException e ) {
781                return e;
782            } catch ( SAXException e ) {
783                return e;
784            }
785        }
786    
787        /**
788         * 
789         * 
790         * @param is
791         * 
792         * @return thr content as String
793         * 
794         * @throws IOException
795         */
796        protected String getInputStreamContent( InputStream is )
797                                throws IOException {
798            StringBuffer sb = new StringBuffer( 1000 );
799            int c = 0;
800    
801            while ( ( c = is.read() ) >= 0 ) {
802                sb.append( (char) c );
803            }
804    
805            is.close();
806            return sb.toString();
807        }
808    
809    }