    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_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    }