001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/datastore/wfs/CascadingWFSDatastore.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2007 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     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.io.datastore.wfs;
044    
045    import java.io.IOException;
046    import java.io.InputStream;
047    import java.net.MalformedURLException;
048    import java.net.URL;
049    import java.util.HashMap;
050    import java.util.Map;
051    
052    import org.apache.commons.httpclient.HttpClient;
053    import org.apache.commons.httpclient.methods.PostMethod;
054    import org.apache.commons.httpclient.methods.StringRequestEntity;
055    import org.deegree.enterprise.WebUtils;
056    import org.deegree.framework.log.ILogger;
057    import org.deegree.framework.log.LoggerFactory;
058    import org.deegree.framework.util.CharsetUtils;
059    import org.deegree.framework.xml.XMLFragment;
060    import org.deegree.framework.xml.XMLParsingException;
061    import org.deegree.i18n.Messages;
062    import org.deegree.io.datastore.Datastore;
063    import org.deegree.io.datastore.DatastoreException;
064    import org.deegree.io.datastore.DatastoreTransaction;
065    import org.deegree.io.datastore.schema.MappedFeatureType;
066    import org.deegree.model.crs.UnknownCRSException;
067    import org.deegree.model.feature.FeatureCollection;
068    import org.deegree.model.feature.GMLFeatureCollectionDocument;
069    import org.deegree.ogcwebservices.OWSUtils;
070    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
071    import org.deegree.ogcwebservices.wfs.XMLFactory;
072    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
073    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument;
074    import org.deegree.ogcwebservices.wfs.operation.GetFeature;
075    import org.deegree.ogcwebservices.wfs.operation.Query;
076    import org.deegree.ogcwebservices.wfs.operation.GetFeature.RESULT_TYPE;
077    import org.xml.sax.SAXException;
078    
079    /**
080     * 
081     * 
082     * 
083     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
084     * @author last edited by: $Author: mschneider $
085     * 
086     * @version $Revision: 7468 $, $Date: 2007-06-05 16:33:13 +0200 (Di, 05 Jun 2007) $
087     */
088    public class CascadingWFSDatastore extends Datastore {
089    
090        private ILogger LOG = LoggerFactory.getLogger( CascadingWFSDatastore.class );
091    
092        private static Map<URL, WFSCapabilities> wfsCapabilities;
093        static {
094            if ( wfsCapabilities == null ) {
095                wfsCapabilities = new HashMap<URL, WFSCapabilities>();
096            }
097        }
098    
099        @Override
100        public CascadingWFSAnnotationDocument getAnnotationParser() {
101            return new CascadingWFSAnnotationDocument ();
102        }    
103        
104        @Override
105        public void close()
106                                throws DatastoreException {
107        }
108    
109        @Override
110        public FeatureCollection performQuery( Query query, MappedFeatureType[] rootFts, DatastoreTransaction context )
111                                throws DatastoreException, UnknownCRSException {
112            return performQuery( query, rootFts );
113        }
114    
115        @Override
116        public FeatureCollection performQuery( Query query, MappedFeatureType[] rootFts )
117                                throws DatastoreException, UnknownCRSException {
118    
119            GetFeature getFeature = GetFeature.create( "1.1.0", "ID", RESULT_TYPE.RESULTS, "text/xml; subtype=gml/3.1.1",
120                                                       "", query.getMaxFeatures(), query.getStartPosition(), -1, -1,
121                                                       new Query[] { query } );
122            XMLFragment gfXML = null;
123            try {
124                gfXML = XMLFactory.export( getFeature );
125            } catch ( IOException e ) {
126                LOG.logError( e.getMessage(), e );
127                throw new DatastoreException( e.getMessage() );
128            } catch ( XMLParsingException e ) {
129                LOG.logError( e.getMessage(), e );
130                throw new DatastoreException( e.getMessage() );
131            }
132    
133            FeatureCollection allFc = null;
134    
135            // get URL that is target of a GetFeature request
136            CascadingWFSDatastoreConfiguration config = (CascadingWFSDatastoreConfiguration) this.getConfiguration();
137            URL[] urls = config.getWfsURL();
138            for ( int i = 0; i < urls.length; i++ ) {
139    
140                URL url = getTargetURL( GetFeature.class, urls[i] );
141    
142                InputStream is = null;
143                try {
144                    // perform GetFeature request against cascaded WFS
145                    HttpClient client = new HttpClient();
146                    client = WebUtils.enableProxyUsage( client, url );
147                    PostMethod post = new PostMethod( url.toExternalForm() );
148                    StringRequestEntity se = new StringRequestEntity( gfXML.getAsString(), "text/xml",
149                                                                      CharsetUtils.getSystemCharset() );
150                    post.setRequestEntity( se );
151                    client.executeMethod( post );
152                    is = post.getResponseBodyAsStream();
153                } catch ( Exception e ) {
154                    throw new DatastoreException( Messages.getMessage( "DATASTORE_WFS_ACCESS", url ) );
155                }
156    
157                // read result as GMLFeatureColllection
158                GMLFeatureCollectionDocument fcd = new GMLFeatureCollectionDocument();
159                try {
160                    fcd.load( is, url.toExternalForm() );
161                } catch ( Exception e ) {
162                    LOG.logError( e.getMessage(), e );
163                    throw new DatastoreException( e.getMessage() );
164                } finally {
165                    try {
166                        is.close();
167                    } catch ( IOException shouldNeverHappen ) {
168                    }
169                }
170    
171                FeatureCollection fc = null;
172                try {
173                    fc = fcd.parse();
174                } catch ( XMLParsingException e ) {
175                    LOG.logError( e.getMessage(), e );
176                    throw new DatastoreException( e.getMessage() );
177                }
178                if ( allFc == null ) {
179                    allFc = fc;
180                } else {
181                    allFc.addAll( fc );
182                }
183    
184            }
185    
186            return allFc;
187        }
188    
189        private URL getTargetURL( Class clss, URL url )
190                                throws DatastoreException {
191    
192            String href = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() );
193            href = href + "request=GetCapabilities&version=1.1.0&service=WFS";
194    
195            LOG.logDebug( "requested capabilities: ", href );
196    
197            try {
198                url = new URL( href );
199            } catch ( MalformedURLException e1 ) {
200                e1.printStackTrace();
201            }
202    
203            WFSCapabilities caps = wfsCapabilities.get( url );
204            if ( caps == null ) {
205                // access capabilities if not already has been loaded
206                WFSCapabilitiesDocument cd = new WFSCapabilitiesDocument();
207                try {
208                    cd.load( url );
209                } catch ( IOException e ) {
210                    LOG.logError( e.getMessage(), e );
211                    throw new DatastoreException( e.getMessage() );
212                } catch ( SAXException e ) {
213                    LOG.logError( e.getMessage(), e );
214                    throw new DatastoreException( e.getMessage() );
215                }
216                try {
217                    caps = (WFSCapabilities) cd.parseCapabilities();
218                } catch ( InvalidCapabilitiesException e ) {
219                    LOG.logError( e.getMessage(), e );
220                    throw new DatastoreException( e.getMessage() );
221                }
222                wfsCapabilities.put( url, caps );
223            }
224    
225            // get GetFeature target URL from capabilities
226            return OWSUtils.getHTTPPostOperationURL( caps, clss );
227        }
228    }