001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wmps/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.wmps;
037    
038    import java.io.IOException;
039    import java.io.InputStream;
040    import java.io.StringReader;
041    import java.net.URL;
042    import java.util.HashMap;
043    import java.util.List;
044    
045    import javax.media.jai.JAI;
046    import javax.media.jai.RenderedOp;
047    
048    import org.deegree.datatypes.QualifiedName;
049    import org.deegree.framework.log.ILogger;
050    import org.deegree.framework.log.LoggerFactory;
051    import org.deegree.framework.util.MimeTypeMapper;
052    import org.deegree.framework.util.NetWorker;
053    import org.deegree.framework.util.StringTools;
054    import org.deegree.framework.xml.XMLFragment;
055    import org.deegree.ogcwebservices.OGCWebService;
056    import org.deegree.ogcwebservices.OGCWebServiceException;
057    import org.deegree.ogcwebservices.OGCWebServiceRequest;
058    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
059    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
060    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
061    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
062    import org.deegree.ogcwebservices.wms.operation.GetMap;
063    import org.deegree.ogcwebservices.wms.operation.WMSGetCapabilities;
064    import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory;
065    import org.deegree.owscommon_new.DCP;
066    import org.deegree.owscommon_new.HTTP;
067    import org.deegree.owscommon_new.OperationsMetadata;
068    
069    import com.sun.media.jai.codec.MemoryCacheSeekableStream;
070    
071    /**
072     * An instance of the class acts as a wrapper to a remote WMS.
073     *
074     * @version $Revision: 18195 $
075     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
076     */
077    public class RemoteWMService implements OGCWebService {
078    
079        private static ILogger LOG = LoggerFactory.getLogger( RemoteWMService.class );
080    
081        protected HashMap<String, URL> addresses = null;
082    
083        protected WMSCapabilities capabilities = null;
084    
085        /**
086         * Creates a new instance of RemoteWMService
087         *
088         * @param capabilities
089         */
090        public RemoteWMService( WMSCapabilities capabilities ) {
091            this.capabilities = capabilities;
092            this.addresses = new HashMap<String, URL>();
093    
094            // get GetCapabilities operation address
095            List<DCP> dcps = null;
096            HTTP http = null;
097    
098            OperationsMetadata om = capabilities.getOperationMetadata();
099    
100            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
101                dcps = om.getOperation( new QualifiedName( "Capabilities" ) ).getDCP();
102                for ( DCP dcp : dcps )
103                    if ( dcp instanceof HTTP )
104                        http = (HTTP) dcp;
105                this.addresses.put( "Capabilities", http.getLinks().get( 0 ).getLinkage().getHref() );
106            } else {
107                dcps = om.getOperation( new QualifiedName( "GetCapabilities" ) ).getDCP();
108                for ( DCP dcp : dcps )
109                    if ( dcp instanceof HTTP )
110                        http = (HTTP) dcp;
111                this.addresses.put( "GetCapabilities", http.getLinks().get( 0 ).getLinkage().getHref() );
112            }
113    
114            // get GetMap operation address
115            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
116                // hui, is this the right name? Though it is all lowercase or 'Map'?
117                dcps = om.getOperation( new QualifiedName( "MAP" ) ).getDCP();
118                for ( DCP dcp : dcps )
119                    if ( dcp instanceof HTTP )
120                        http = (HTTP) dcp;
121                this.addresses.put( "MAP", http.getLinks().get( 0 ).getLinkage().getHref() );
122            } else {
123                dcps = om.getOperation( new QualifiedName( "GetMap" ) ).getDCP();
124                for ( DCP dcp : dcps )
125                    if ( dcp instanceof HTTP )
126                        http = (HTTP) dcp;
127                this.addresses.put( "GetMap", http.getLinks().get( 0 ).getLinkage().getHref() );
128            }
129    
130        }
131    
132        /**
133         * Returns the OGCCapabilities
134         *
135         * @return OGCCapabilities
136         */
137        public OGCCapabilities getCapabilities() {
138            return this.capabilities;
139        }
140    
141        /**
142         * the method performs the handling of the passed OGCWebServiceEvent directly and returns the
143         * result to the calling class/method
144         *
145         * @param request
146         *            request (WMS, WCS, WFS, WCAS, WCTS, WTS, Gazetter) to perform
147         * @return Object
148         * @throws OGCWebServiceException
149         */
150        public Object doService( OGCWebServiceRequest request )
151                                throws OGCWebServiceException {
152    
153            Object object = null;
154            if ( request instanceof GetMap ) {
155                object = handleGetMap( (GetMap) request );
156                object = WMSProtocolFactory.createGetMapResponse( request, null, object );
157            }
158            return object;
159    
160        }
161    
162        /**
163         * performs a GetMap request against the remote service. The result contains the map decoded in
164         * the desired format as a byte array.
165         *
166         * @param request
167         *            GetMap request
168         * @return Object
169         * @throws OGCWebServiceException
170         */
171        protected Object handleGetMap( GetMap request )
172                                throws OGCWebServiceException {
173    
174            URL url = null;
175            if ( request.getVersion().equals( "1.0.0" ) ) {
176                url = this.addresses.get( "MAP" );
177            } else {
178                url = this.addresses.get( "GetMap" );
179            }
180    
181            String param = request.getRequestParameter();
182            String us = url.toExternalForm();
183            if ( !us.endsWith( "?" ) ) {
184                us = us + '?';
185            }
186            us = us + param;
187            LOG.logDebug( "remote wms getmap", us );
188    
189            if ( this.capabilities.getVersion().compareTo( "1.0.0" ) <= 0 ) {
190                us = StringTools.replace( us, "TRANSPARENCY", "TRANSPARENT", false );
191                us = StringTools.replace( us, "GetMap", "map", false );
192                us = StringTools.replace( us, "image/", "", false );
193            }
194    
195            Object result = null;
196            try {
197                URL ur = new URL( us );
198                // get map from the remote service
199                NetWorker nw = new NetWorker( ur );
200                InputStream is = nw.getInputStream();
201    
202                String contentType = nw.getContentType();
203                String[] tmp = StringTools.toArray( contentType, ";", true );
204                for ( int i = 0; i < tmp.length; i++ ) {
205                    if ( tmp[i].indexOf( "image" ) > -1 ) {
206                        contentType = tmp[i];
207                        break;
208                    }
209                    contentType = tmp[0];
210                }
211    
212                if ( MimeTypeMapper.isImageType( contentType ) && MimeTypeMapper.isKnownImageType( contentType ) ) {
213                    MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
214                    RenderedOp rop = JAI.create( "stream", mcss );
215                    result = rop.getAsBufferedImage();
216                    mcss.close();
217                } else {
218                    // extract remote (error) message if the response
219                    // contains a known mime type
220                    String res = "";
221                    if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
222                        res = "; remote message: ";
223                        res += getInputStreamContent( is );
224                    }
225                    String msg = StringTools.concat( 500, "Response of the remote WMS contains wrong content type: ",
226                                                     contentType, ";request: ", param, ' ', res );
227                    throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
228                }
229            } catch ( Exception e ) {
230                LOG.logError( e.getMessage(), e );
231                String msg = StringTools.concat( 500, "Could not get map from RemoteWMS: ",
232                                                 this.capabilities.getServiceIdentification().getTitle(), "; ",
233                                                 "request: ", param, " ", e.toString() );
234                throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
235            }
236    
237            return result;
238        }
239    
240        /**
241         * reads the capabilities from the remote WMS by performing a GetCapabilities request against
242         * it.
243         *
244         * @param request
245         *            capabilities request
246         * @return WMSCapabilities
247         * @throws OGCWebServiceException
248         */
249        protected WMSCapabilities handleGetCapabilities( WMSGetCapabilities request )
250                                throws OGCWebServiceException {
251    
252            URL url = null;
253    
254            if ( request.getVersion().equals( "1.0.0" ) ) {
255                url = this.addresses.get( "capabilites" );
256            } else {
257                url = this.addresses.get( "GetCapabilities" );
258            }
259    
260            String param = request.getRequestParameter();
261            String us = url.toExternalForm();
262            if ( !us.endsWith( "?" ) ) {
263                us = us + '?';
264            }
265            us = us + param;
266    
267            WMSCapabilities result = null;
268    
269            try {
270                URL ur = new URL( us );
271                // get map from the remote service
272                NetWorker nw = new NetWorker( ur );
273                byte[] b = nw.getDataAsByteArr( 20000 );
274                String contentType = nw.getContentType();
275    
276                if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
277                    // create a WMSCapabilitiesTEMP instance from the result
278                    StringReader reader = new StringReader( new String( b ) );
279                    WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
280                    doc.load( reader, XMLFragment.DEFAULT_URL );
281                    doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( doc.getRootElement() );
282                    result = (WMSCapabilities) doc.parseCapabilities();
283                } else {
284                    String msg = StringTools.concat( 500, "Response of the remote WMS contains unknown content type: ",
285                                                     contentType, ";request: ", param );
286                    throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
287                }
288            } catch ( Exception e ) {
289                LOG.logError( e.getMessage(), e );
290                String msg = StringTools.concat( 500, "Could not get map from RemoteWMS: ",
291                                                 this.capabilities.getServiceIdentification().getTitle(), "; request: ",
292                                                 param + "; ", e.toString() );
293                throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
294            }
295    
296            return result;
297        }
298    
299        // /**
300        // * Returns the legend graphics
301        // *
302        // * @param request
303        // * describe layer request (WMS 1.1.1 - SLD)
304        // * @return Object
305        // * @throws OGCWebServiceException
306        // */
307        // protected Object handleGetLegendGraphic( GetLegendGraphic request )
308        // throws OGCWebServiceException {
309        //
310        // URL url = addresses.get( WMPSConstants.GETLEGENDGRAPHIC );
311        //
312        // if ( url == null ) {
313        // throw new OGCWebServiceException( "GETLEGENDGRAPHIC is not supported by "
314        // + "the RemoteWMS: "
315        // + capabilities.getServiceIdentification().getTitle() );
316        // }
317        //
318        // String param = request.getRequestParameter();
319        // String us = url.toExternalForm();
320        // if ( !us.endsWith( "?" ) ) {
321        // us = us + '?';
322        // }
323        // us = us + param;
324        // // FIXME
325        // return null;
326        // }
327    
328        /**
329         *
330         *
331         * @param is
332         *
333         * @return String
334         *
335         * @throws IOException
336         */
337        protected String getInputStreamContent( InputStream is )
338                                throws IOException {
339            StringBuffer sb = new StringBuffer( 1000 );
340            int c = 0;
341    
342            while ( ( c = is.read() ) >= 0 ) {
343                sb.append( (char) c );
344            }
345    
346            is.close();
347            return sb.toString();
348        }
349    
350    }