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