001    //$HeadURL: svn+ssh://developername@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/ogcwebservices/wcs/RemoteWCService.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.wcs;
037    
038    import java.awt.image.BufferedImage;
039    import java.io.IOException;
040    import java.io.InputStream;
041    import java.io.StringReader;
042    import java.net.URL;
043    import java.util.HashMap;
044    import java.util.Properties;
045    import java.util.UUID;
046    
047    import javax.media.jai.JAI;
048    import javax.media.jai.RenderedOp;
049    
050    import org.apache.commons.httpclient.Header;
051    import org.apache.commons.httpclient.HttpClient;
052    import org.apache.commons.httpclient.HttpException;
053    import org.apache.commons.httpclient.methods.GetMethod;
054    import org.deegree.enterprise.WebUtils;
055    import org.deegree.framework.log.ILogger;
056    import org.deegree.framework.log.LoggerFactory;
057    import org.deegree.framework.util.BootLogger;
058    import org.deegree.framework.util.MimeTypeMapper;
059    import org.deegree.framework.util.NetWorker;
060    import org.deegree.framework.util.StringTools;
061    import org.deegree.framework.xml.XMLFragment;
062    import org.deegree.i18n.Messages;
063    import org.deegree.model.coverage.grid.ImageGridCoverage;
064    import org.deegree.ogcwebservices.OGCWebService;
065    import org.deegree.ogcwebservices.OGCWebServiceException;
066    import org.deegree.ogcwebservices.OGCWebServiceRequest;
067    import org.deegree.ogcwebservices.OWSUtils;
068    import org.deegree.ogcwebservices.getcapabilities.DCPType;
069    import org.deegree.ogcwebservices.getcapabilities.HTTP;
070    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
071    import org.deegree.ogcwebservices.getcapabilities.Operation;
072    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
073    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageDescription;
074    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageDescriptionDocument;
075    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering;
076    import org.deegree.ogcwebservices.wcs.describecoverage.DescribeCoverage;
077    import org.deegree.ogcwebservices.wcs.getcapabilities.WCSCapabilities;
078    import org.deegree.ogcwebservices.wcs.getcapabilities.WCSCapabilitiesDocument;
079    import org.deegree.ogcwebservices.wcs.getcapabilities.WCSGetCapabilities;
080    import org.deegree.ogcwebservices.wcs.getcoverage.GetCoverage;
081    import org.deegree.ogcwebservices.wcs.getcoverage.ResultCoverage;
082    
083    import com.sun.media.jai.codec.MemoryCacheSeekableStream;
084    
085    /**
086     * An instance of the class acts as a wrapper to a remote WMS.
087     *
088     * @version $Revision: 11921 $
089     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
090     */
091    public class RemoteWCService implements OGCWebService {
092    
093        private static ILogger LOG = LoggerFactory.getLogger( RemoteWCService.class );
094    
095        private static final String GETCAPABILITIES_NAME = "GetCapabilities";
096    
097        private static final String GETCOVERAGE_NAME = "GetCoverage";
098    
099        private static final String DESCRIBECOVERAGE_NAME = "DescribeCoverage";
100    
101        protected HashMap<String, URL> addresses = null;
102    
103        protected WCSCapabilities capabilities = null;
104    
105        private static Properties properties;
106        static {
107            if ( properties == null ) {
108                try {
109                    properties = new Properties();
110                    InputStream is = RemoteWCService.class.getResourceAsStream( "remotewcservice.properties" );
111                    properties.load( is );
112                    is.close();
113                } catch ( Exception e ) {
114                    BootLogger.logError( e.getMessage(), e );
115                }
116            }
117        }
118    
119        /**
120         * Creates a new instance of RemoteWMService
121         *
122         * @param capabilities
123         */
124        public RemoteWCService( WCSCapabilities capabilities ) {
125            this.capabilities = capabilities;
126            addresses = new HashMap<String, URL>();
127    
128            // get GetCapabilities operation address
129            DCPType[] dcps = null;
130            HTTP http = null;
131    
132            OperationsMetadata om = capabilities.getCapabilitiy().getOperations();
133    
134            Operation[] ops = om.getOperations();
135            for ( Operation operation : ops ) {
136                if ( operation.getName().equals( GETCAPABILITIES_NAME ) ) {
137                    dcps = operation.getDCPs();
138                    for ( DCPType dcp : dcps ) {
139                        if ( dcp.getProtocol() instanceof HTTP ) {
140                            http = (HTTP) dcp.getProtocol();
141                        }
142                    }
143                }
144            }
145            addresses.put( GETCAPABILITIES_NAME, http.getGetOnlineResources()[0] );
146    
147            // get GetCoverage operation address
148            for ( Operation operation : ops ) {
149                if ( operation.getName().equals( GETCOVERAGE_NAME ) ) {
150                    dcps = operation.getDCPs();
151                    for ( DCPType dcp : dcps ) {
152                        if ( dcp.getProtocol() instanceof HTTP ) {
153                            http = (HTTP) dcp.getProtocol();
154                        }
155                    }
156                }
157            }
158            addresses.put( GETCOVERAGE_NAME, http.getGetOnlineResources()[0] );
159    
160            // get DescribeCoverage operation address
161            for ( Operation operation : ops ) {
162                if ( operation.getName().equals( DESCRIBECOVERAGE_NAME ) ) {
163                    dcps = operation.getDCPs();
164                    for ( DCPType dcp : dcps ) {
165                        if ( dcp.getProtocol() instanceof HTTP ) {
166                            http = (HTTP) dcp.getProtocol();
167                        }
168                    }
169                }
170            }
171            addresses.put( DESCRIBECOVERAGE_NAME, http.getGetOnlineResources()[0] );
172    
173        }
174    
175        public OGCCapabilities getCapabilities() {
176            return capabilities;
177        }
178    
179        /**
180         * the method performs the handling of the passed OGCWebServiceEvent directly and returns the
181         * result to the calling class/method
182         *
183         * @param request
184         *            request to perform
185         *
186         * @throws OGCWebServiceException
187         */
188        public Object doService( OGCWebServiceRequest request )
189                                throws OGCWebServiceException {
190            Object o = null;
191            if ( request instanceof GetCoverage ) {
192                o = handleGetCoverage( (GetCoverage) request );
193            } else if ( request instanceof DescribeCoverage ) {
194                o = handleDescribeCoverage( (DescribeCoverage) request );
195            }
196    
197            return o;
198    
199        }
200    
201        // checks for excessive &
202        private static String constructRequestURL( String params, String url ) {
203            if ( url.endsWith( "?" ) && params.startsWith( "&" ) ) {
204                return url + params.substring( 1 );
205            }
206    
207            return url + params;
208        }
209    
210        /**
211         * performs a GetCoverage request against a remote service. The result contains the Coverage
212         * decoded in the desired format as a byte array.
213         *
214         * @param request
215         *            GetCoverage request
216         * @return the requested coverage
217         * @throws OGCWebServiceException
218         *             if the url in the request is <code>null</code>
219         */
220        protected Object handleGetCoverage( GetCoverage request )
221                                throws OGCWebServiceException {
222    
223            URL url = addresses.get( GETCOVERAGE_NAME );
224    
225            String us = constructRequestURL( request.getRequestParameter(), OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) );
226    
227            LOG.logDebug( "remote wcs GetCoverage", us );
228    
229            Object result = null;
230            try {
231                HttpClient client = new HttpClient();
232                WebUtils.enableProxyUsage( client, new URL( us ) );
233                int timeout = 25000;
234                if ( properties != null && properties.getProperty( "timeout" ) != null ) {
235                    timeout = Integer.parseInt( properties.getProperty( "timeout" ) );
236                }
237                LOG.logDebug( "timeout is:", timeout );
238                client.getHttpConnectionManager().getParams().setSoTimeout( timeout );
239                GetMethod get = new GetMethod( us );
240                client.executeMethod( get );
241                InputStream is = get.getResponseBodyAsStream();
242                Header header = get.getResponseHeader( "Content-type" );
243    
244                String contentType = header.getValue();
245                String[] tmp = StringTools.toArray( contentType, ";", true );
246                contentType = tmp[0];
247    
248                if ( "application/vnd.ogc.se_xml".equals( contentType ) ) {
249                    String res = "Remote-WCS message: " + getInputStreamContent( is );
250                    throw new OGCWebServiceException( "RemoteWCS:handleGetCoverage", res );
251                } else if ( MimeTypeMapper.isImageType( contentType ) && MimeTypeMapper.isKnownImageType( contentType ) ) {
252                    MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
253                    RenderedOp rop = JAI.create( "stream", mcss );
254                    BufferedImage bi = rop.getAsBufferedImage();
255                    mcss.close();
256                    DescribeCoverage dscC = new DescribeCoverage( UUID.randomUUID().toString(), capabilities.getVersion(),
257                                                                  new String[] { request.getSourceCoverage() } );
258                    CoverageDescription cd = handleDescribeCoverage( dscC );
259                    CoverageOffering co = cd.getCoverageOfferings()[0];
260                    result = new ImageGridCoverage( co, request.getDomainSubset().getSpatialSubset().getEnvelope(), bi );
261                } else {
262                    // must be something else; e.g. GML or XYZ-text
263                    result = getInputStreamContent( is );
264                }
265            } catch ( HttpException e ) {
266                LOG.logError( e.getMessage(), e );
267                String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR", capabilities.getService().getLabel(),
268                                                  us );
269                throw new OGCWebServiceException( "RemoteWCS:handleGetCoverage", msg );
270            } catch ( IOException e ) {
271                LOG.logError( e.getMessage(), e );
272                String msg = Messages.getMessage( "REMOTEWMS_GETMAP_GENERAL_ERROR", capabilities.getService().getLabel(),
273                                                  us );
274                throw new OGCWebServiceException( "RemoteWCS:handleGetCoverage", msg );
275            }
276    
277            return new ResultCoverage( result, result.getClass(), request.getOutput().getFormat(), request );
278    
279        }
280    
281        /**
282         *
283         * @param request
284         *            DescribeCoverage to perform
285         * @return the response of the DescribeCoverage request.
286         * @throws OGCWebServiceException
287         *             if the request could not be excuted correctly.
288         */
289        protected CoverageDescription handleDescribeCoverage( DescribeCoverage request )
290                                throws OGCWebServiceException {
291    
292            URL url = addresses.get( DESCRIBECOVERAGE_NAME );
293    
294            if ( url == null ) {
295                String msg = Messages.getMessage( "REMOTEWMS_GFI_NOT_SUPPORTED", capabilities.getService().getLabel() );
296                throw new OGCWebServiceException( msg );
297            }
298    
299            String us = constructRequestURL( request.getRequestParameter(), OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) );
300    
301            CoverageDescription result = null;
302            try {
303                LOG.logDebug( "DescribeCoverage: ", us );
304                // get map from the remote service
305                HttpClient client = new HttpClient();
306                WebUtils.enableProxyUsage( client, new URL( us ) );
307                int timeout = 25000;
308                if ( properties != null && properties.getProperty( "timeout" ) != null ) {
309                    timeout = Integer.parseInt( properties.getProperty( "timeout" ) );
310                }
311                LOG.logDebug( "timeout is:", timeout );
312                client.getHttpConnectionManager().getParams().setSoTimeout( timeout );
313                GetMethod get = new GetMethod( us );
314                client.executeMethod( get );
315                InputStream is = get.getResponseBodyAsStream();
316                Header header = get.getResponseHeader( "Content-type" );
317    
318                String contentType = header.getValue();
319                String[] tmp = StringTools.toArray( contentType, ";", true );
320                contentType = tmp[0];
321    
322                if ( "application/vnd.ogc.se_xml".equals( contentType ) ) {
323                    String res = "Remote-WCS message: " + getInputStreamContent( is );
324                    throw new OGCWebServiceException( "RemoteWCS:handleGetCoverage", res );
325                } else {
326                    CoverageDescriptionDocument doc = new CoverageDescriptionDocument();
327                    doc.load( is, us );
328                    result = new CoverageDescription( doc );
329                }
330            } catch ( Exception e ) {
331                LOG.logError( e.getMessage(), e );
332                String msg = Messages.getMessage( "REMOTEWCS_GFI_GENERAL_ERROR", capabilities.getService().getLabel(), us );
333                throw new OGCWebServiceException( "RemoteWCS:handleFeatureInfo", msg );
334            }
335    
336            return result;
337        }
338    
339        /**
340         * reads the capabilities from the remote WMS by performing a GetCapabilities request against
341         * it.
342         *
343         * @param request
344         *            capabilities request
345         * @return remote capabilities
346         * @throws OGCWebServiceException
347         *             if the request could not be executed correctly.
348         */
349        protected WCSCapabilities handleGetCapabilities( WCSGetCapabilities request )
350                                throws OGCWebServiceException {
351    
352            URL url = addresses.get( GETCAPABILITIES_NAME );
353    
354            String us = constructRequestURL( request.getRequestParameter(), OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) );
355    
356            WCSCapabilities result = null;
357    
358            try {
359                URL ur = new URL( us );
360                // get map from the remote service
361                NetWorker nw = new NetWorker( ur );
362                byte[] b = nw.getDataAsByteArr( 20000 );
363                String contentType = nw.getContentType();
364    
365                if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
366                    // create a WMSCapabilitiesTEMP instance from the result
367                    StringReader reader = new StringReader( new String( b ) );
368                    WCSCapabilitiesDocument doc = new WCSCapabilitiesDocument();
369                    doc.load( reader, XMLFragment.DEFAULT_URL );
370                    result = (WCSCapabilities) doc.parseCapabilities();
371                } else {
372                    String msg = Messages.getMessage( "REMOTEWMS_GETCAPS_INVALID_CONTENTTYPE", contentType, us );
373                    throw new OGCWebServiceException( "RemoteWCS:handleGetCapabilities", msg );
374                }
375            } catch ( Exception e ) {
376                LOG.logError( e.getMessage(), e );
377                String msg = Messages.getMessage( "REMOTEWCS_GETCAPS_GENERAL_ERROR", capabilities.getService().getLabel(),
378                                                  us );
379                throw new OGCWebServiceException( "RemoteWCS:handleGetCapabilities", msg );
380            }
381    
382            return result;
383        }
384    
385        /**
386         *
387         *
388         * @param is
389         *
390         * @return thr content as String
391         *
392         * @throws IOException
393         */
394        protected String getInputStreamContent( InputStream is )
395                                throws IOException {
396            StringBuffer sb = new StringBuffer( 1000 );
397            int c = 0;
398    
399            while ( ( c = is.read() ) >= 0 ) {
400                sb.append( (char) c );
401            }
402    
403            is.close();
404            return sb.toString();
405        }
406    
407    }