001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wfs/RemoteWFService.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.wfs;
037    
038    import java.io.InputStreamReader;
039    import java.io.StringReader;
040    import java.io.StringWriter;
041    import java.net.URL;
042    import java.util.HashMap;
043    import java.util.Map;
044    
045    import org.deegree.framework.log.ILogger;
046    import org.deegree.framework.log.LoggerFactory;
047    import org.deegree.framework.util.CharsetUtils;
048    import org.deegree.framework.util.MimeTypeMapper;
049    import org.deegree.framework.util.NetWorker;
050    import org.deegree.framework.util.StringTools;
051    import org.deegree.framework.xml.XMLFragment;
052    import org.deegree.model.feature.FeatureCollection;
053    import org.deegree.model.feature.GMLFeatureCollectionDocument;
054    import org.deegree.ogcwebservices.OGCWebService;
055    import org.deegree.ogcwebservices.OGCWebServiceException;
056    import org.deegree.ogcwebservices.OGCWebServiceRequest;
057    import org.deegree.ogcwebservices.OWSUtils;
058    import org.deegree.ogcwebservices.getcapabilities.DCPType;
059    import org.deegree.ogcwebservices.getcapabilities.HTTP;
060    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
061    import org.deegree.ogcwebservices.getcapabilities.Operation;
062    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
063    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument_1_0_0;
064    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument_1_1_0;
065    import org.deegree.ogcwebservices.wfs.capabilities.WFSOperationsMetadata;
066    import org.deegree.ogcwebservices.wfs.operation.DescribeFeatureType;
067    import org.deegree.ogcwebservices.wfs.operation.FeatureResult;
068    import org.deegree.ogcwebservices.wfs.operation.FeatureTypeDescription;
069    import org.deegree.ogcwebservices.wfs.operation.GetFeature;
070    import org.deegree.ogcwebservices.wfs.operation.LockFeature;
071    import org.deegree.ogcwebservices.wfs.operation.WFSGetCapabilities;
072    import org.deegree.ogcwebservices.wfs.operation.transaction.Transaction;
073    
074    /**
075     * An instance of the class acts as a wrapper to a remote WFS.
076     *
077     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
078     * @author last edited by: $Author: mschneider $
079     *
080     * @version $Revision: 18195 $
081     */
082    public class RemoteWFService implements OGCWebService {
083    
084        private static final ILogger LOG = LoggerFactory.getLogger( RemoteWFService.class );
085    
086        protected static final String GETCAPABILITIES = "GETCAPABILITIES";
087    
088        protected static final String GETFEATURE = "GETFEATURE";
089    
090        protected static final String GETFEATUREWITHLOCK = "GETFEATUREWITHLOCK";
091    
092        protected static final String DESCRIBEFEATURETYPE = "DESCRIBEFEATURETYPE";
093    
094        protected static final String TRANSACTION = "TRANSACTION";
095    
096        protected static final String LOCKFEATURE = "LOCKFEATURE";
097    
098        protected WFSCapabilities capabilities = null;
099    
100        protected Map<String, URL> addresses = new HashMap<String, URL>();
101    
102        /**
103         * Creates a new instance of RemoteWFService
104         *
105         * @param capabilities
106         * @throws OGCWebServiceException
107         */
108        public RemoteWFService( WFSCapabilities capabilities ) throws OGCWebServiceException {
109    
110            this.capabilities = capabilities;
111    
112            WFSOperationsMetadata om = (WFSOperationsMetadata) capabilities.getOperationsMetadata();
113            Operation op = om.getGetCapabilitiesOperation();
114    
115            // get GetCapabilities address
116            DCPType[] dcp = op.getDCPs();
117            URL[] get = ( (HTTP) dcp[0].getProtocol() ).getGetOnlineResources();
118            addresses.put( GETCAPABILITIES, get[0] );
119    
120            // get GetFeature address
121            op = om.getGetFeature();
122            dcp = op.getDCPs();
123            boolean po = false;
124            for ( int i = 0; i < dcp.length; i++ ) {
125                get = ( (HTTP) dcp[i].getProtocol() ).getPostOnlineResources();
126                if ( get != null && get.length > 0 ) {
127                    addresses.put( GETFEATURE, get[0] );
128                    po = true;
129                }
130            }
131            if ( !po ) {
132                String s = "WFS: " + capabilities.getServiceIdentification().getTitle() + " doesn't "
133                           + "support HTTP POST for GetFeature requests";
134                LOG.logDebug( s );
135                throw new OGCWebServiceException( s );
136            }
137    
138            // get DescribeFeatureType address
139            op = om.getDescribeFeatureType();
140            dcp = op.getDCPs();
141            get = ( (HTTP) dcp[0].getProtocol() ).getGetOnlineResources();
142            addresses.put( DESCRIBEFEATURETYPE, get[0] );
143    
144            op = om.getGetFeatureWithLock();
145            if ( op != null ) {
146                // get GetFeatureWithLock address
147                dcp = op.getDCPs();
148                po = false;
149                for ( int i = 0; i < dcp.length; i++ ) {
150                    get = ( (HTTP) dcp[i].getProtocol() ).getPostOnlineResources();
151                    if ( get != null && get.length > 0 ) {
152                        addresses.put( GETFEATUREWITHLOCK, get[0] );
153                        po = true;
154                    }
155                }
156                if ( !po ) {
157                    String s = "WFS: " + capabilities.getServiceIdentification().getTitle()
158                               + " doesn't support HTTP POST for GetFeatureWithLock requests";
159                    LOG.logDebug( s );
160                    throw new OGCWebServiceException( s );
161                }
162            }
163    
164            op = om.getTransaction();
165            if ( op != null ) {
166                // get Transaction address
167                dcp = op.getDCPs();
168                po = false;
169                for ( int i = 0; i < dcp.length; i++ ) {
170                    get = ( (HTTP) dcp[i].getProtocol() ).getPostOnlineResources();
171                    if ( get != null && get.length > 0 ) {
172                        addresses.put( TRANSACTION, get[0] );
173                        po = true;
174                    }
175                }
176                if ( !po ) {
177                    String s = "WFS: " + capabilities.getServiceIdentification().getTitle()
178                               + " doesn't support HTTP POST for Transaction requests";
179                    LOG.logDebug( s );
180                    throw new OGCWebServiceException( s );
181                }
182            }
183    
184            op = om.getLockFeature();
185            if ( op != null ) {
186                // get LockFeature address
187                dcp = op.getDCPs();
188                get = ( (HTTP) dcp[0].getProtocol() ).getGetOnlineResources();
189                if ( get != null && get.length > 0 ) {
190                    addresses.put( LOCKFEATURE, get[0] );
191                }
192            }
193    
194        }
195    
196        /**
197         *
198         * @return capabilities
199         */
200        public WFSCapabilities getWFSCapabilities() {
201            return capabilities;
202        }
203    
204        /*
205         * (non-Javadoc)
206         *
207         * @see org.deegree.ogcwebservices.OGCWebService#doService(org.deegree.ogcwebservices.OGCWebServiceRequest)
208         */
209        public Object doService( OGCWebServiceRequest request )
210                                throws OGCWebServiceException {
211            Object response = null;
212            if ( request instanceof GetFeature ) {
213                response = handleGetFeature( (GetFeature) request );
214            } else if ( request instanceof DescribeFeatureType ) {
215                response = handleDescribeFeatureType( (DescribeFeatureType) request );
216            } else if ( request instanceof WFSGetCapabilities ) {
217                response = handleGetCapabilities( (WFSGetCapabilities) request );
218            } else if ( request instanceof LockFeature ) {
219                response = handleLockFeature( (LockFeature) request );
220            } else if ( request instanceof Transaction ) {
221                response = handleTransaction( (Transaction) request );
222            }
223            return response;
224        }
225    
226        /**
227         * performs a GetFeature request against the remote service. The method uses http-POST to call the remote WFS
228         *
229         * @param request
230         *            get feature request
231         */
232        private FeatureResult handleGetFeature( GetFeature request )
233                                throws OGCWebServiceException {
234    
235            URL url = addresses.get( GETFEATURE );
236            StringWriter writer = new StringWriter( 1000 );
237            try {
238                if ( "1.0.0".equals( capabilities.getVersion() ) ) {
239                    XMLFactory_1_0_0.export( request ).write( writer );
240                } else {
241                    XMLFactory.export( request ).write( writer );
242                }
243            } catch ( Exception e ) {
244                LOG.logError( e.getMessage(), e );
245                throw new OGCWebServiceException( "could not transform GetFeature requst to its string representation" );
246            }
247            String param = writer.getBuffer().toString();
248    
249            FeatureCollection result = null;
250            try {
251                // get map from the remote service
252                NetWorker nw = new NetWorker( CharsetUtils.getSystemCharset(), url, param );
253                String contentType = nw.getContentType();
254                if ( contentType == null || MimeTypeMapper.isKnownMimeType( contentType ) ) {
255                    try {
256                        InputStreamReader isr = new InputStreamReader( nw.getInputStream(), CharsetUtils.getSystemCharset() );
257                        GMLFeatureCollectionDocument doc = new GMLFeatureCollectionDocument();
258                        doc.load( isr, url.toString() );
259                        result = doc.parse();
260                    } catch ( Exception e ) {
261                        throw new OGCWebServiceException( e.toString() );
262                    }
263                } else {
264                    String msg = StringTools.concat( 500, "Response of the remote WFS contains unknown content type: ",
265                                                     contentType, ";request: ", param );
266                    throw new OGCWebServiceException( "RemoteWFS:handleGetFeature", msg );
267                }
268            } catch ( Exception e ) {
269                LOG.logError( e.getMessage(), e );
270                String msg = StringTools.concat( 500, "Could not get feature from RemoteWFS: ",
271                                                 capabilities.getServiceIdentification().getTitle(), "; request: ", param,
272                                                 ';' );
273                throw new OGCWebServiceException( "RemoteWFS:handleGetFeature", msg );
274    
275            }
276    
277            FeatureResult fr = new FeatureResult( request, result );
278            return fr;
279    
280        }
281    
282        /**
283         * Performs a describe feature type request against a remote WFS. The method uses http-GET to call the remote WFS
284         *
285         * @param request
286         *            describe feature type request
287         */
288        private FeatureTypeDescription handleDescribeFeatureType( DescribeFeatureType request )
289                                throws OGCWebServiceException {
290    
291            URL url = addresses.get( DESCRIBEFEATURETYPE );
292    
293            String param = request.getRequestParameter();
294    
295            String result = null;
296            try {
297                String us = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) + param;
298                URL ur = new URL( us );
299                // get map from the remote service
300                NetWorker nw = new NetWorker( CharsetUtils.getSystemCharset(), ur );
301                byte[] b = nw.getDataAsByteArr( 20000 );
302                String contentType = nw.getContentType();
303                if ( MimeTypeMapper.isKnownMimeType( contentType ) ) {
304                    // create a WFSCapabilities instance from the result
305                    result = new String( b );
306                } else {
307                    String msg = StringTools.concat( 500, "Response of the remote WFS contains unknown content type: ",
308                                                     contentType, ";request: ", param );
309                    throw new OGCWebServiceException( "RemoteWFS:handleDescribeFeatureType", msg );
310                }
311            } catch ( Exception e ) {
312                LOG.logError( e.getMessage(), e );
313                String msg = StringTools.concat( 500, "Could not get map from RemoteWFS: ",
314                                                 capabilities.getServiceIdentification().getTitle(), "; request: ", param,
315                                                 ';' );
316                throw new OGCWebServiceException( "RemoteWFS:handleDescribeFeatureType", msg );
317    
318            }
319    
320            FeatureTypeDescription ftd = null;
321            try {
322                XMLFragment frag = new XMLFragment( new StringReader( result ), XMLFragment.DEFAULT_URL );
323                ftd = new FeatureTypeDescription( frag );
324            } catch ( Exception e1 ) {
325                LOG.logError( e1.getMessage(), e1 );
326                throw new OGCWebServiceException( this.getClass().getName() + "Could not create response",
327                                                  StringTools.stackTraceToString( e1 ) );
328            }
329    
330            return ftd;
331        }
332    
333        private String toKVPRequest() {
334            return null;
335        }
336    
337        /**
338         * reads the capabilities from the remote WFS by performing a GetCapabilities request against it. The method uses
339         * http-GET to call the remote WFS
340         *
341         * @param request
342         *            capabilities request
343         */
344        private WFSCapabilities handleGetCapabilities( WFSGetCapabilities request )
345                                throws OGCWebServiceException {
346    
347            URL url = addresses.get( GETCAPABILITIES );
348            String param = request.getRequestParameter();
349    
350            WFSCapabilities response = null;
351            try {
352                String remoteAddress = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() );
353                URL ur = new URL( remoteAddress + param );
354                XMLFragment responseDoc = new XMLFragment( ur );
355                String version = responseDoc.getRootElement().getAttribute( "version" );
356                if ( version == null ) {
357                    String msg = "Cannot determine remote WFS version. No 'version' attribute.";
358                    throw new OGCWebServiceException( "RemoteWFS:handleGetCapabilities", msg );
359                }
360                if ( "1.0.0".equals( version ) ) {
361                    WFSCapabilitiesDocument_1_0_0 capabilitiesDoc = new WFSCapabilitiesDocument_1_0_0();
362                    capabilitiesDoc.setRootElement( responseDoc.getRootElement() );
363                    response = (WFSCapabilities) capabilitiesDoc.parseCapabilities();
364                } else if ( "1.1.0".equals( version ) ) {
365                    WFSCapabilitiesDocument_1_1_0 capabilitiesDoc = new WFSCapabilitiesDocument_1_1_0();
366                    capabilitiesDoc.setRootElement( responseDoc.getRootElement() );
367                    response = (WFSCapabilities) capabilitiesDoc.parseCapabilities();
368                } else {
369                    String msg = "Cannot communicate with remote WFS. Protocol version '" + version
370                                 + "' is not supported by RemoteWFService class.";
371                    throw new OGCWebServiceException( "RemoteWFS:handleGetCapabilities", msg );
372                }
373    
374            } catch ( Exception e ) {
375                LOG.logError( e.getMessage(), e );
376                String msg = StringTools.concat( 500, "Could not get map from RemoteWFS: ",
377                                                 capabilities.getServiceIdentification().getTitle(), "; request: ", param,
378                                                 ';' );
379                throw new OGCWebServiceException( "RemoteWFS:handleGetCapabilities", msg );
380    
381            }
382            return response;
383    
384        }
385    
386        /**
387         * @param request
388         */
389        private Object handleLockFeature( LockFeature request ) {
390            // FIXME
391            // TODO
392            return null;
393        }
394    
395        /**
396         * @param request
397         */
398        private Object handleTransaction( Transaction request ) {
399            // FIXME
400            // TODO
401            return null;
402        }
403    
404        /*
405         * (non-Javadoc)
406         *
407         * @see org.deegree.ogcwebservices.OGCWebService#getCapabilities()
408         */
409        public OGCCapabilities getCapabilities() {
410            return capabilities;
411        }
412    
413    }