001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wmps/RemoteWMService.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 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.operation.GetMap;
070    import org.deegree.ogcwebservices.wms.operation.WMSGetCapabilities;
071    import org.deegree.ogcwebservices.wms.operation.WMSProtocolFactory;
072    import org.deegree.owscommon_new.DCP;
073    import org.deegree.owscommon_new.HTTP;
074    import org.deegree.owscommon_new.OperationsMetadata;
075    
076    import com.sun.media.jai.codec.MemoryCacheSeekableStream;
077    
078    /**
079     * An instance of the class acts as a wrapper to a remote WMS.
080     * 
081     * @version $Revision: 6259 $
082     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
083     */
084    public class RemoteWMService implements OGCWebService {
085        
086        private static ILogger LOG = LoggerFactory.getLogger( RemoteWMService.class ); 
087    
088        protected HashMap<String, URL> addresses = null;
089    
090        protected WMSCapabilities capabilities = null;
091    
092        /**
093         * Creates a new instance of RemoteWMService
094         * 
095         * @param capabilities
096         */
097        public RemoteWMService( WMSCapabilities capabilities ) {
098            this.capabilities = capabilities;
099            this.addresses = new HashMap<String, URL>();
100    
101            // get GetCapabilities operation address
102            List<DCP> dcps = null;
103            HTTP http = null;
104    
105            OperationsMetadata om = capabilities.getOperationMetadata();
106    
107            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
108                dcps = om.getOperation( new QualifiedName( "Capabilities" ) ).getDCP();
109                for( DCP dcp : dcps ) if( dcp instanceof HTTP ) http = (HTTP) dcp;
110                this.addresses.put( "Capabilities", http.getLinks().get( 0 ).getLinkage().getHref() );
111            } else {
112                dcps = om.getOperation( new QualifiedName( "GetCapabilities" ) ).getDCP();
113                for( DCP dcp : dcps ) if( dcp instanceof HTTP ) http = (HTTP) dcp;
114                this.addresses.put( "GetCapabilities", http.getLinks().get( 0 ).getLinkage().getHref() );
115            }
116    
117            // get GetMap operation address
118            if ( capabilities.getVersion().equals( "1.0.0" ) ) {
119                // hui, is this the right name? Though it is all lowercase or 'Map'?
120                dcps = om.getOperation( new QualifiedName( "MAP" ) ).getDCP();
121                for( DCP dcp : dcps ) if( dcp instanceof HTTP ) http = (HTTP) dcp;
122                this.addresses.put( "MAP", http.getLinks().get( 0 ).getLinkage().getHref() );
123            } else {
124                dcps = om.getOperation( new QualifiedName( "GetMap" ) ).getDCP();
125                for( DCP dcp : dcps ) if( dcp instanceof HTTP ) http = (HTTP) dcp;
126                this.addresses.put("GetMap", http.getLinks().get( 0 ).getLinkage().getHref() );
127            }
128    
129        }
130    
131        /**
132         * Returns the OGCCapabilities
133         * 
134         * @return OGCCapabilities
135         */
136        public OGCCapabilities getCapabilities() {
137            return this.capabilities;
138        }
139    
140        /**
141         * the method performs the handling of the passed OGCWebServiceEvent directly and returns the
142         * result to the calling class/method
143         * 
144         * @param request
145         *            request (WMS, WCS, WFS, WCAS, WCTS, WTS, Gazetter) to perform
146         * @return Object
147         * @throws OGCWebServiceException
148         */
149        public Object doService( OGCWebServiceRequest request )
150                                throws OGCWebServiceException {
151            
152            Object object = null;
153            if ( request instanceof GetMap ) {
154                object = handleGetMap( (GetMap) request );
155                object = WMSProtocolFactory.createGetMapResponse( request, null, object );
156            }
157            return object;
158    
159        }
160    
161        /**
162         * performs a GetMap request against the remote service. The result contains the map decoded in
163         * the desired format as a byte array.
164         * 
165         * @param request
166         *            GetMap request
167         * @return Object
168         * @throws OGCWebServiceException
169         */
170        protected Object handleGetMap( GetMap request )
171                                throws OGCWebServiceException {
172            
173            URL url = null;
174            if ( request.getVersion().equals( "1.0.0" ) ) {
175                url = this.addresses.get( "MAP" );
176            } else {
177                url = this.addresses.get( "GetMap" );
178            }
179    
180            String param = request.getRequestParameter();
181            String us = url.toExternalForm();
182            if ( !us.endsWith( "?" ) ) {
183                us = us + '?';
184            }
185            us = us + param;
186            LOG.logDebug( "remote wms getmap", us );
187    
188            if ( this.capabilities.getVersion().compareTo( "1.0.0" ) <= 0 ) {
189                us = StringTools.replace( us, "TRANSPARENCY", "TRANSPARENT", false );
190                us = StringTools.replace( us, "GetMap", "map", false );
191                us = StringTools.replace( us, "image/", "", false );
192            }
193    
194            Object result = null;
195            try {
196                URL ur = new URL( us );
197                // get map from the remote service
198                NetWorker nw = new NetWorker( ur );
199                InputStream is = nw.getInputStream();
200    
201                String contentType = nw.getContentType();
202                String[] tmp = StringTools.toArray( contentType, ";", true );
203                for ( int i = 0; i < tmp.length; i++ ) {
204                    if ( tmp[i].indexOf( "image" ) > -1 ) {
205                        contentType = tmp[i];
206                        break;
207                    }
208                    contentType = tmp[0];
209                }
210    
211                if ( MimeTypeMapper.isImageType( contentType )
212                     && 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    
226                    throw new OGCWebServiceException( "RemoteWMS:handleGetMap",
227                                                      "Response of the remote " + "WMS " + "contains "
228                                                                              + "wrong content type: "
229                                                                              + contentType
230                                                                              + ";request: " + param
231                                                                              + res );
232                }
233            } catch ( Exception e ) {
234                throw new OGCWebServiceException(
235                                                  "RemoteWMS:handleGetMap",
236                                                  "Could not get map from RemoteWMS: "
237                                                                          + this.capabilities.getServiceIdentification().getTitle()
238                                                                          + "; " + "request: " + param
239                                                                          + " " + e.toString() );
240            }
241    
242            return result;
243        }
244    
245         /**
246             * reads the capabilities from the remote WMS by performing a GetCapabilities request
247             * against it.
248             * 
249             * @param request
250             *            capabilities request
251             * @return WMSCapabilities
252             * @throws OGCWebServiceException
253             */
254        protected WMSCapabilities handleGetCapabilities( WMSGetCapabilities request )
255                                throws OGCWebServiceException {
256            
257            URL url = null;
258    
259            if ( request.getVersion().equals( "1.0.0" ) ) {
260                url = this.addresses.get( "capabilites" );
261            } else {
262                url = this.addresses.get( "GetCapabilities" );
263            }
264    
265            String param = request.getRequestParameter();
266            String us = url.toExternalForm();
267            if ( !us.endsWith( "?" ) ) {
268                us = us + '?';
269            }
270            us = us + param;
271    
272            WMSCapabilities result = null;
273    
274            try {
275                URL ur = new URL( us );
276                // get map from the remote service
277                NetWorker nw = new NetWorker( ur );
278                byte[] b = nw.getDataAsByteArr( 20000 );
279                String contentType = nw.getContentType();
280    
281                if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
282                    // create a WMSCapabilitiesTEMP instance from the result
283                    StringReader reader = new StringReader( new String( b ) );
284                    WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
285                    doc.load( reader, XMLFragment.DEFAULT_URL );
286                    result = (WMSCapabilities) doc.parseCapabilities();
287                } else {
288                    throw new OGCWebServiceException(
289                                                      "RemoteWMS:handleGetCapabilities",
290                                                      "Response of the "
291                                                                              + "remote WMS "
292                                                                              + "contains "
293                                                                              + "unknown content type: "
294                                                                              + contentType
295                                                                              + ";request: " + param );
296                }
297            } catch ( Exception e ) {
298                throw new OGCWebServiceException(
299                                                  "RemoteWMS:handleGetCapabilities",
300                                                  "Could not get map from RemoteWMS: "
301                                                                          + this.capabilities.getServiceIdentification().getTitle()
302                                                                          + "; request: " + param
303                                                                          + "; " + e.toString() );
304            }
305    
306            return result;
307        }
308    
309        // /**
310        // * Returns the legend graphics
311        // *
312        // * @param request
313        // * describe layer request (WMS 1.1.1 - SLD)
314        // * @return Object
315        // * @throws OGCWebServiceException
316        // */
317        // protected Object handleGetLegendGraphic( GetLegendGraphic request )
318        // throws OGCWebServiceException {
319        //
320        // URL url = addresses.get( WMPSConstants.GETLEGENDGRAPHIC );
321        //
322        // if ( url == null ) {
323        // throw new OGCWebServiceException( "GETLEGENDGRAPHIC is not supported by "
324        // + "the RemoteWMS: "
325        // + capabilities.getServiceIdentification().getTitle() );
326        // }
327        //
328        // String param = request.getRequestParameter();
329        // String us = url.toExternalForm();
330        // if ( !us.endsWith( "?" ) ) {
331        // us = us + '?';
332        // }
333        // us = us + param;
334        //        // FIXME
335        //        return null;
336        //    }
337    
338        /**
339         * 
340         * 
341         * @param is
342         * 
343         * @return String
344         * 
345         * @throws IOException
346         */
347        protected String getInputStreamContent( InputStream is )
348                                throws IOException {
349            StringBuffer sb = new StringBuffer( 1000 );
350            int c = 0;
351    
352            while ( ( c = is.read() ) >= 0 ) {
353                sb.append( (char) c );
354            }
355    
356            is.close();
357            return sb.toString();
358        }
359    
360    }
361    /***************************************************************************************************
362     * Changes to this class. What the people have been up to: $Log$
363     * Changes to this class. What the people have been up to: Revision 1.17  2006/11/27 09:07:52  poth
364     * Changes to this class. What the people have been up to: JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code.
365     * Changes to this class. What the people have been up to:
366     * Changes to this class. What the people have been up to: Revision 1.16  2006/10/22 20:36:05  poth
367     * Changes to this class. What the people have been up to: operations not supported by WMPS removed
368     * Changes to this class. What the people have been up to:
369     * Changes to this class. What the people have been up to: Revision 1.15  2006/08/23 07:10:22  schmitz
370     * Changes to this class. What the people have been up to: Renamed the owscommon_neu package to owscommon_new.
371     * Changes to this class. What the people have been up to:
372     * Changes to this class. What the people have been up to: Revision 1.14  2006/08/22 10:25:01  schmitz
373     * Changes to this class. What the people have been up to: Updated the WMS to use the new OWS common package.
374     * Changes to this class. What the people have been up to: Updated the rest of deegree to use the new data classes returned
375     * Changes to this class. What the people have been up to: by the updated WMS methods/capabilities.
376     * Changes to this class. What the people have been up to:
377     * Changes to this class. What the people have been up to: Revision 1.13  2006/08/10 07:11:35  deshmukh
378     * Changes to this class. What the people have been up to: WMPS has been modified to support the new configuration changes and the excess code not needed has been replaced.
379     * Changes to this class. What the people have been up to: Changes to
380     * this class. What the people have been up to: Revision 1.12 2006/08/01 13:41:48 deshmukh Changes
381     * to this class. What the people have been up to: The wmps configuration has been modified and
382     * extended. Also fixed the javadoc. Changes to this class. What the people have been up to:
383     * Revision 1.11 2006/07/12 14:46:16 poth comment footer added
384     * 
385     **************************************************************************************************/