    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_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    }