001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wmps/RemoteWMService.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.ogcwebservices.wmps;
045    
046    import java.io.IOException;
047    import java.io.InputStream;
048    import java.io.StringReader;
049    import java.net.URL;
050    import java.util.HashMap;
051    import java.util.List;
052    
053    import javax.media.jai.JAI;
054    import javax.media.jai.RenderedOp;
055    
056    import org.deegree.datatypes.QualifiedName;
057    import org.deegree.framework.log.ILogger;
058    import org.deegree.framework.log.LoggerFactory;
059    import org.deegree.framework.util.MimeTypeMapper;
060    import org.deegree.framework.util.NetWorker;
061    import org.deegree.framework.util.StringTools;
062    import org.deegree.framework.xml.XMLFragment;
063    import org.deegree.ogcwebservices.OGCWebService;
064    import org.deegree.ogcwebservices.OGCWebServiceException;
065    import org.deegree.ogcwebservices.OGCWebServiceRequest;
066    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
067    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
068    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
069    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
070    import org.deegree.ogcwebservices.wms.operation.GetMap;
071    import org.deegree.ogcwebservices.wms.operation.WMSGetCapabilities;
072    import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory;
073    import org.deegree.owscommon_new.DCP;
074    import org.deegree.owscommon_new.HTTP;
075    import org.deegree.owscommon_new.OperationsMetadata;
076    
077    import com.sun.media.jai.codec.MemoryCacheSeekableStream;
078    
079    /**
080     * An instance of the class acts as a wrapper to a remote WMS.
081     * 
082     * @version $Revision: 9345 $
083     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
084     */
085    public class RemoteWMService implements OGCWebService {
086    
087        private static ILogger LOG = LoggerFactory.getLogger( RemoteWMService.class );
088    
089        protected HashMap<String, URL> addresses = null;
090    
091        protected WMSCapabilities capabilities = null;
092    
093        /**
094         * Creates a new instance of RemoteWMService
095         * 
096         * @param capabilities
097         */
098        public RemoteWMService( WMSCapabilities capabilities ) {
099            this.capabilities = capabilities;
100            this.addresses = new HashMap<String, URL>();
101    
102            // get GetCapabilities operation address
103            List<DCP> dcps = null;
104            HTTP http = null;
105    
106            OperationsMetadata om = capabilities.getOperationMetadata();
107    
108            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
109                dcps = om.getOperation( new QualifiedName( "Capabilities" ) ).getDCP();
110                for ( DCP dcp : dcps )
111                    if ( dcp instanceof HTTP )
112                        http = (HTTP) dcp;
113                this.addresses.put( "Capabilities", http.getLinks().get( 0 ).getLinkage().getHref() );
114            } else {
115                dcps = om.getOperation( new QualifiedName( "GetCapabilities" ) ).getDCP();
116                for ( DCP dcp : dcps )
117                    if ( dcp instanceof HTTP )
118                        http = (HTTP) dcp;
119                this.addresses.put( "GetCapabilities", http.getLinks().get( 0 ).getLinkage().getHref() );
120            }
121    
122            // get GetMap operation address
123            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
124                // hui, is this the right name? Though it is all lowercase or 'Map'?
125                dcps = om.getOperation( new QualifiedName( "MAP" ) ).getDCP();
126                for ( DCP dcp : dcps )
127                    if ( dcp instanceof HTTP )
128                        http = (HTTP) dcp;
129                this.addresses.put( "MAP", http.getLinks().get( 0 ).getLinkage().getHref() );
130            } else {
131                dcps = om.getOperation( new QualifiedName( "GetMap" ) ).getDCP();
132                for ( DCP dcp : dcps )
133                    if ( dcp instanceof HTTP )
134                        http = (HTTP) dcp;
135                this.addresses.put( "GetMap", http.getLinks().get( 0 ).getLinkage().getHref() );
136            }
137    
138        }
139    
140        /**
141         * Returns the OGCCapabilities
142         * 
143         * @return OGCCapabilities
144         */
145        public OGCCapabilities getCapabilities() {
146            return this.capabilities;
147        }
148    
149        /**
150         * the method performs the handling of the passed OGCWebServiceEvent directly and returns the
151         * result to the calling class/method
152         * 
153         * @param request
154         *            request (WMS, WCS, WFS, WCAS, WCTS, WTS, Gazetter) to perform
155         * @return Object
156         * @throws OGCWebServiceException
157         */
158        public Object doService( OGCWebServiceRequest request )
159                                throws OGCWebServiceException {
160    
161            Object object = null;
162            if ( request instanceof GetMap ) {
163                object = handleGetMap( (GetMap) request );
164                object = WMSProtocolFactory.createGetMapResponse( request, null, object );
165            }
166            return object;
167    
168        }
169    
170        /**
171         * performs a GetMap request against the remote service. The result contains the map decoded in
172         * the desired format as a byte array.
173         * 
174         * @param request
175         *            GetMap request
176         * @return Object
177         * @throws OGCWebServiceException
178         */
179        protected Object handleGetMap( GetMap request )
180                                throws OGCWebServiceException {
181    
182            URL url = null;
183            if ( request.getVersion().equals( "1.0.0" ) ) {
184                url = this.addresses.get( "MAP" );
185            } else {
186                url = this.addresses.get( "GetMap" );
187            }
188    
189            String param = request.getRequestParameter();
190            String us = url.toExternalForm();
191            if ( !us.endsWith( "?" ) ) {
192                us = us + '?';
193            }
194            us = us + param;
195            LOG.logDebug( "remote wms getmap", us );
196    
197            if ( this.capabilities.getVersion().compareTo( "1.0.0" ) <= 0 ) {
198                us = StringTools.replace( us, "TRANSPARENCY", "TRANSPARENT", false );
199                us = StringTools.replace( us, "GetMap", "map", false );
200                us = StringTools.replace( us, "image/", "", false );
201            }
202    
203            Object result = null;
204            try {
205                URL ur = new URL( us );
206                // get map from the remote service
207                NetWorker nw = new NetWorker( ur );
208                InputStream is = nw.getInputStream();
209    
210                String contentType = nw.getContentType();
211                String[] tmp = StringTools.toArray( contentType, ";", true );
212                for ( int i = 0; i < tmp.length; i++ ) {
213                    if ( tmp[i].indexOf( "image" ) > -1 ) {
214                        contentType = tmp[i];
215                        break;
216                    }
217                    contentType = tmp[0];
218                }
219    
220                if ( MimeTypeMapper.isImageType( contentType ) && MimeTypeMapper.isKnownImageType( contentType ) ) {
221                    MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream( is );
222                    RenderedOp rop = JAI.create( "stream", mcss );
223                    result = rop.getAsBufferedImage();
224                    mcss.close();
225                } else {
226                    // extract remote (error) message if the response
227                    // contains a known mime type
228                    String res = "";
229                    if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
230                        res = "; remote message: ";
231                        res += getInputStreamContent( is );
232                    }
233                    String msg = StringTools.concat( 500, "Response of the remote WMS contains wrong content type: ",
234                                                     contentType, ";request: ", param, ' ', res );
235                    throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
236                }
237            } catch ( Exception e ) {
238                LOG.logError( e.getMessage(), e );
239                String msg = StringTools.concat( 500, "Could not get map from RemoteWMS: ",
240                                                 this.capabilities.getServiceIdentification().getTitle(), "; ",
241                                                 "request: ", param, " ", e.toString() );
242                throw new OGCWebServiceException( "RemoteWMS:handleGetMap", msg );
243            }
244    
245            return result;
246        }
247    
248        /**
249         * reads the capabilities from the remote WMS by performing a GetCapabilities request against
250         * it.
251         * 
252         * @param request
253         *            capabilities request
254         * @return WMSCapabilities
255         * @throws OGCWebServiceException
256         */
257        protected WMSCapabilities handleGetCapabilities( WMSGetCapabilities request )
258                                throws OGCWebServiceException {
259    
260            URL url = null;
261    
262            if ( request.getVersion().equals( "1.0.0" ) ) {
263                url = this.addresses.get( "capabilites" );
264            } else {
265                url = this.addresses.get( "GetCapabilities" );
266            }
267    
268            String param = request.getRequestParameter();
269            String us = url.toExternalForm();
270            if ( !us.endsWith( "?" ) ) {
271                us = us + '?';
272            }
273            us = us + param;
274    
275            WMSCapabilities result = null;
276    
277            try {
278                URL ur = new URL( us );
279                // get map from the remote service
280                NetWorker nw = new NetWorker( ur );
281                byte[] b = nw.getDataAsByteArr( 20000 );
282                String contentType = nw.getContentType();
283    
284                if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
285                    // create a WMSCapabilitiesTEMP instance from the result
286                    StringReader reader = new StringReader( new String( b ) );
287                    WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
288                    doc.load( reader, XMLFragment.DEFAULT_URL );
289                    doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( doc.getRootElement() );
290                    result = (WMSCapabilities) doc.parseCapabilities();
291                } else {
292                    String msg = StringTools.concat( 500, "Response of the remote WMS contains unknown content type: ",
293                                                     contentType, ";request: ", param );
294                    throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
295                }
296            } catch ( Exception e ) {
297                LOG.logError( e.getMessage(), e );
298                String msg = StringTools.concat( 500, "Could not get map from RemoteWMS: ",
299                                                 this.capabilities.getServiceIdentification().getTitle(), "; request: ",
300                                                 param + "; ", e.toString() );
301                throw new OGCWebServiceException( "RemoteWMS:handleGetCapabilities", msg );
302            }
303    
304            return result;
305        }
306    
307        // /**
308        // * Returns the legend graphics
309        // *
310        // * @param request
311        // * describe layer request (WMS 1.1.1 - SLD)
312        // * @return Object
313        // * @throws OGCWebServiceException
314        // */
315        // protected Object handleGetLegendGraphic( GetLegendGraphic request )
316        // throws OGCWebServiceException {
317        //
318        // URL url = addresses.get( WMPSConstants.GETLEGENDGRAPHIC );
319        //
320        // if ( url == null ) {
321        // throw new OGCWebServiceException( "GETLEGENDGRAPHIC is not supported by "
322        // + "the RemoteWMS: "
323        // + capabilities.getServiceIdentification().getTitle() );
324        // }
325        //
326        // String param = request.getRequestParameter();
327        // String us = url.toExternalForm();
328        // if ( !us.endsWith( "?" ) ) {
329        // us = us + '?';
330        // }
331        // us = us + param;
332        // // FIXME
333        // return null;
334        // }
335    
336        /**
337         * 
338         * 
339         * @param is
340         * 
341         * @return String
342         * 
343         * @throws IOException
344         */
345        protected String getInputStreamContent( InputStream is )
346                                throws IOException {
347            StringBuffer sb = new StringBuffer( 1000 );
348            int c = 0;
349    
350            while ( ( c = is.read() ) >= 0 ) {
351                sb.append( (char) c );
352            }
353    
354            is.close();
355            return sb.toString();
356        }
357    
358    }