osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/feature_wfs/FeatureSourceWFS.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 
00020 #include <osgEarth/Registry>
00021 #include <osgEarth/FileUtils>
00022 #include <osgEarthFeatures/FeatureSource>
00023 #include <osgEarthFeatures/Filter>
00024 #include <osgEarthFeatures/BufferFilter>
00025 #include <osgEarthFeatures/ScaleFilter>
00026 #include <osgEarthUtil/WFS>
00027 #include "WFSFeatureOptions"
00028 #include <osgEarthFeatures/OgrUtils>
00029 #include <osg/Notify>
00030 #include <osgDB/FileNameUtils>
00031 #include <osgDB/FileUtils>
00032 #include <list>
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 
00036 #include <ogr_api.h>
00037 
00038 #ifdef WIN32
00039 #include <windows.h>
00040 #endif
00041 
00042 #define LC "[WFS FeatureSource] "
00043 
00044 using namespace osgEarth;
00045 using namespace osgEarth::Util;
00046 using namespace osgEarth::Features;
00047 using namespace osgEarth::Drivers;
00048 
00049 #define OGR_SCOPED_LOCK GDAL_SCOPED_LOCK
00050 
00051 std::string getTempPath()
00052 {
00053 #if defined(WIN32)  && !defined(__CYGWIN__)
00054     BOOL fSuccess  = FALSE;
00055 
00056     TCHAR lpTempPathBuffer[MAX_PATH];    
00057 
00058     //  Gets the temp path env string (no guarantee it's a valid path).
00059     DWORD dwRetVal = ::GetTempPath(MAX_PATH,          // length of the buffer
00060                                    lpTempPathBuffer); // buffer for path     
00061 
00062     if (dwRetVal > MAX_PATH || (dwRetVal == 0))
00063     {
00064         OE_NOTICE << "GetTempPath failed" << std::endl;
00065         return ".";
00066     }
00067 
00068     return std::string(lpTempPathBuffer);
00069 #else
00070     return "/tmp/";
00071 #endif
00072 }
00073 
00074 std::string getTempName(const std::string& prefix="", const std::string& suffix="")
00075 {
00076     //tmpname is kind of busted on Windows, it always returns a file of the form \blah which gets put in your root directory but
00077     //oftentimes can't get opened by some drivers b/c it doesn't have a drive letter in front of it.
00078     bool valid = false;
00079     while (!valid)
00080     {
00081         std::stringstream ss;
00082         ss << prefix << "~" << rand() << suffix;
00083         if (!osgDB::fileExists(ss.str())) return ss.str();
00084     }
00085     return "";
00086 }
00087 
00093 class WFSFeatureSource : public FeatureSource
00094 {
00095 public:
00096     WFSFeatureSource( const WFSFeatureOptions& options ) : FeatureSource( options ),      
00097       _options( options )
00098     {        
00099     }
00100 
00102     virtual ~WFSFeatureSource()
00103     {               
00104     }
00105 
00106     //override
00107     void initialize( const std::string& referenceURI )
00108     {
00109         char sep = _options.url()->full().find_first_of('?') == std::string::npos? '?' : '&';
00110 
00111         std::string capUrl;
00112         if ( capUrl.empty() )
00113         {
00114             capUrl = 
00115                 _options.url()->full() +
00116                 sep + 
00117                 "SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities";
00118         }
00119 
00120         _capabilities = WFSCapabilitiesReader::read( capUrl, 0L );
00121         if ( !_capabilities.valid() )
00122         {
00123             OE_WARN << "[osgEarth::WFS] Unable to read WFS GetCapabilities." << std::endl;
00124             //return;
00125         }
00126         else
00127         {
00128             OE_NOTICE << "[osgEarth::WFS] Got capabilities from " << capUrl << std::endl;
00129         }
00130     }
00131 
00134     const FeatureProfile* createFeatureProfile()
00135     {
00136         FeatureProfile* result = NULL;
00137         if (_capabilities.valid())
00138         {
00139             //Find the feature type by name
00140             osg::ref_ptr< WFSFeatureType > featureType = _capabilities->getFeatureTypeByName( _options.typeName().get() );
00141             if (featureType.valid())
00142             {
00143                 if (featureType->getExtent().isValid())
00144                 {
00145                     result = new FeatureProfile(featureType->getExtent());
00146 
00147                     if (featureType->getTiled())
00148                     {                        
00149                         result->setTiled( true );
00150                         result->setFirstLevel( featureType->getFirstLevel() );
00151                         result->setMaxLevel( featureType->getMaxLevel() );
00152                         result->setProfile( osgEarth::Profile::create(osgEarth::SpatialReference::create("epsg:4326"), featureType->getExtent().xMin(), featureType->getExtent().yMin(), featureType->getExtent().xMax(), featureType->getExtent().yMax(), 0, 1, 1) );
00153                     }
00154                 }
00155             }
00156         }
00157 
00158         if (!result)
00159         {
00160             result = new FeatureProfile(GeoExtent(SpatialReference::create( "epsg:4326" ), -180, -90, 180, 90));
00161         }
00162         return result;        
00163     }
00164 
00165     void saveResponse(HTTPResponse& response, const std::string& filename)
00166     {
00167         std::ofstream fout;
00168         fout.open(filename.c_str(), std::ios::out | std::ios::binary);
00169 
00170         std::istream& input_stream = response.getPartStream(0);
00171         input_stream.seekg (0, std::ios::end);
00172         int length = input_stream.tellg();
00173         input_stream.seekg (0, std::ios::beg);
00174 
00175         char *buffer = new char[length];
00176         input_stream.read(buffer, length);
00177         fout.write(buffer, length);
00178         delete[] buffer;
00179         fout.close();
00180     }
00181     
00182     std::string getExtensionForMimeType(const std::string& mime)
00183     {
00184         //OGR is particular sometimes about the extension of files when it's reading them so it's good to have
00185         //the temp file have an appropriate extension
00186         if ((mime.compare("text/xml") == 0) ||
00187             (mime.compare("text/xml; subtype=gml/2.1.2") == 0) ||
00188             (mime.compare("text/xml; subtype=gml/3.1.1") == 0)
00189             )
00190         {
00191             return ".xml";
00192         }        
00193         else if ((mime.compare("application/json") == 0) ||
00194                  (mime.compare("json") == 0) ||            
00195 
00196                  (mime.compare("application/x-javascript") == 0) ||
00197                  (mime.compare("text/javascript") == 0) ||
00198                  (mime.compare("text/x-javascript") == 0) ||
00199                  (mime.compare("text/x-json") == 0)                 
00200                 )
00201         {
00202             return ".json";
00203         }        
00204         return "";
00205     }
00206 
00207     void getFeatures(HTTPResponse &response, FeatureList& features)
00208     {        
00209         //OE_NOTICE << "mimetype=" << response.getMimeType() << std::endl;
00210         //TODO:  Handle more than just geojson...
00211         std::string ext = getExtensionForMimeType(response.getMimeType());
00212         //Save the response to a temp file            
00213         std::string tmpPath = getTempPath();        
00214         std::string name = getTempName(tmpPath, ext);
00215         saveResponse(response, name );
00216         //OE_NOTICE << "Saving to " << name << std::endl;        
00217 
00218         //OGRDataSourceH ds = OGROpen(name.c_str(), FALSE, &driver);            
00219         OGRDataSourceH ds = OGROpen(name.c_str(), FALSE, NULL);            
00220         if (!ds)
00221         {
00222             OE_NOTICE << "Error opening data with contents " << std::endl
00223                 << response.getPartAsString(0) << std::endl;
00224         }
00225 
00226         OGRLayerH layer = OGR_DS_GetLayer(ds, 0);
00227         //Read all the features
00228         if (layer)
00229         {
00230             OGR_L_ResetReading(layer);                                
00231             OGRFeatureH feat_handle;
00232             while ((feat_handle = OGR_L_GetNextFeature( layer )) != NULL)
00233             {
00234                 if ( feat_handle )
00235                 {
00236                     Feature* f = OgrUtils::createFeature( feat_handle );
00237                     if ( f ) 
00238                     {
00239                         features.push_back( f );
00240                     }
00241                     OGR_F_Destroy( feat_handle );
00242                 }
00243             }
00244         }
00245 
00246         //Destroy the datasource
00247         OGR_DS_Destroy( ds );
00248         //Remove the temporary file
00249         remove( name.c_str() );            
00250     }
00251 
00252     std::string createURL(const Symbology::Query& query)
00253     {
00254         std::stringstream buf;
00255         buf << _options.url()->full() << "?SERVICE=WFS&VERSION=1.0.0&REQUEST=getfeature";
00256         buf << "&TYPENAME=" << _options.typeName().get();
00257         
00258         std::string outputFormat = "geojson";
00259         if (_options.outputFormat().isSet()) outputFormat = _options.outputFormat().get();
00260         buf << "&OUTPUTFORMAT=" << outputFormat;
00261 
00262         if (_options.maxFeatures().isSet())
00263         {
00264             buf << "&MAXFEATURES=" << _options.maxFeatures().get();
00265         }
00266 
00267         if (query.tileKey().isSet())
00268         {
00269             buf << "&Z=" << query.tileKey().get().getLevelOfDetail() << 
00270                    "&X=" << query.tileKey().get().getTileX() <<
00271                    "&Y=" << query.tileKey().get().getTileY();
00272         }
00273         else if (query.bounds().isSet())
00274         {
00275             buf << "&BBOX=" << query.bounds().get().xMin() << "," << query.bounds().get().yMin() << ","
00276                             << query.bounds().get().xMax() << "," << query.bounds().get().yMax();
00277         }
00278         return buf.str();
00279     }
00280 
00281     //override
00282     FeatureCursor* createFeatureCursor( const Symbology::Query& query )
00283     {
00284         std::string url = createURL( query );
00285         OE_DEBUG << LC << "URL: " << url << std::endl;
00286         HTTPResponse response = HTTPClient::get(url);                
00287         FeatureList features;
00288         if (response.isOK())
00289         {
00290             getFeatures(response, features);            
00291             std::string data = response.getPartAsString(0);        
00292         }
00293         else
00294         {
00295             OE_INFO << "Error getting url " << url << std::endl;
00296         }
00297         return new FeatureListCursor( features );        
00298     }
00299 
00300     virtual bool deleteFeature(FeatureID fid)
00301     {
00302         return false;
00303     }
00304 
00305     virtual int getFeatureCount() const
00306     {
00307         return -1;
00308     }
00309 
00310     virtual bool insertFeature(Feature* feature)
00311     {
00312         return false;
00313     }
00314 
00320     virtual Feature* getFeature( FeatureID fid )
00321     {
00322         return 0;
00323     }
00324 
00325     virtual bool isWritable() const
00326     {
00327         return false;
00328     }
00329 
00330     virtual const FeatureSchema& getSchema() const
00331     {
00332         //TODO:  Populate the schema from the DescribeFeatureType call
00333         return _schema;
00334     }
00335 
00336     virtual osgEarth::Symbology::Geometry::Type getGeometryType() const
00337     {
00338         return Geometry::TYPE_UNKNOWN;
00339     }
00340 
00341 
00342 
00343 private:
00344     const WFSFeatureOptions _options;  
00345     osg::ref_ptr< WFSCapabilities > _capabilities;
00346     FeatureSchema _schema;
00347 };
00348 
00349 
00350 class WFSFeatureSourceFactory : public FeatureSourceDriver
00351 {
00352 public:
00353     WFSFeatureSourceFactory()
00354     {
00355         supportsExtension( "osgearth_feature_wfs", "WFS feature driver for osgEarth" );
00356     }
00357 
00358     virtual const char* className()
00359     {
00360         return "WFS Feature Reader";
00361     }
00362 
00363     virtual ReadResult readObject(const std::string& file_name, const Options* options) const
00364     {
00365         if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name )))
00366             return ReadResult::FILE_NOT_HANDLED;
00367 
00368         return ReadResult( new WFSFeatureSource( getFeatureSourceOptions(options) ) );
00369     }
00370 };
00371 
00372 REGISTER_OSGPLUGIN(osgearth_feature_wfs, WFSFeatureSourceFactory)
00373 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines