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