TuttleOFX  1
OfxhPluginCache.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License :
00003  *
00004  * Copyright (c) 2007-2009, The Open Effects Association Ltd.  All Rights Reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  * Redistributions of source code must retain the above copyright notice,
00010  *    this list of conditions and the following disclaimer.
00011  * Redistributions in binary form must reproduce the above copyright notice,
00012  *    this list of conditions and the following disclaimer in the documentation
00013  *    and/or other materials provided with the distribution.
00014  * Neither the name The Open Effects Association Ltd, nor the names of its
00015  *    contributors may be used to endorse or promote products derived from this
00016  *    software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00020  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00022  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00024  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00025  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00027  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 #ifndef _TUTTLE_HOST_OFX_PLUGINCACHE_HPP_
00030 #define _TUTTLE_HOST_OFX_PLUGINCACHE_HPP_
00031 
00032 #include "property/OfxhSet.hpp"
00033 #include "OfxhPluginAPICache.hpp"
00034 #include "OfxhPluginBinary.hpp"
00035 
00036 #include <ofxCore.h>
00037 
00038 #include <boost/serialization/string.hpp>
00039 #include <boost/serialization/set.hpp>
00040 #include <boost/serialization/list.hpp>
00041 #include <boost/ptr_container/serialize_ptr_list.hpp>
00042 
00043 #include <string>
00044 #include <set>
00045 #include <algorithm>
00046 #include <iostream>
00047 
00048 namespace tuttle {
00049 namespace host {
00050 namespace ofx {
00051 
00052 /**
00053  * for later
00054  */
00055 struct PluginCacheSupportedApi
00056 {
00057         APICache::OfxhPluginAPICacheI* _handler;
00058 
00059         PluginCacheSupportedApi( APICache::OfxhPluginAPICacheI* handler )
00060                 : _handler( handler ) {}
00061 
00062         bool matches( std::string api, int version ) const
00063         {
00064                 if( api == _handler->_apiName && version >= _handler->_apiVersionMin && version <= _handler->_apiVersionMax )
00065                 {
00066                         return true;
00067                 }
00068                 return false;
00069         }
00070 
00071 };
00072 
00073 /**
00074  * Where we keep our plugins.
00075  */
00076 class OfxhPluginCache
00077 {
00078 public:
00079         typedef OfxhPluginCache This;
00080         typedef boost::ptr_list<OfxhPluginBinary> OfxhPluginBinaryList;
00081 
00082 protected:
00083         tuttle::host::ofx::property::OfxhPropSpec* _hostSpec;
00084 
00085         std::list<std::string> _pluginPath; ///< list of directories to look in
00086         std::set<std::string> _nonrecursePath; ///< list of directories to look in (non-recursively)
00087         std::list<std::string> _pluginDirs; ///< list of directories we found
00088         OfxhPluginBinaryList _binaries; ///< all the binaries we know about, we own these
00089         std::list<OfxhPlugin*> _plugins; ///< all the plugins inside the binaries, we don't own these, populated from _binaries
00090         std::map<std::string, OfxhPlugin*> _pluginsByID;
00091         std::map<OfxhPluginIdent, bool> _loadedMap; ///< Used to check if a plugin is loaded twice
00092         std::set<std::string> _knownBinFiles;
00093 
00094         std::list<PluginCacheSupportedApi> _apiHandlers;
00095 
00096         // internal state
00097         bool _ignoreCache;
00098         std::string _cacheVersion;
00099         bool _dirty;
00100         bool _enablePluginSeek; ///< Turn off to make all seekPluginFile() calls return an empty string
00101 
00102 public:
00103         /// ctor, which inits _pluginPath to default locations and not much else
00104         OfxhPluginCache();
00105 
00106         /// dtor
00107         ~OfxhPluginCache();
00108 
00109 protected:
00110         void scanDirectory( std::set<std::string>& foundBinFiles, const std::string& dir, bool recurse );
00111 
00112         void addPlugin( OfxhPlugin* plugin )
00113         {
00114                 // Check if the same plugin has already been loaded
00115                 if( _loadedMap.find( plugin->getIdentity() ) == _loadedMap.end() )
00116                 {
00117                         _loadedMap[plugin->getIdentity()] = true;
00118                 }
00119                 else
00120                 {
00121                         TUTTLE_LOG_WARNING( "Plugin: " << plugin->getRawIdentifier() << " loaded twice! (" << plugin->getBinary().getFilePath() << ")" );
00122                 }
00123                 _plugins.push_back( plugin );
00124 
00125                 if( _pluginsByID.find( plugin->getIdentifier() ) != _pluginsByID.end() )
00126                 {
00127                         OfxhPlugin& otherPlugin = *_pluginsByID[plugin->getIdentifier()];
00128                         if( plugin->trumps( otherPlugin ) )
00129                         {
00130                                 _pluginsByID[plugin->getIdentifier()] = plugin;
00131                         }
00132                 }
00133                 else
00134                 {
00135                         _pluginsByID[plugin->getIdentifier()] = plugin;
00136                 }
00137         }
00138 
00139 public:
00140         friend std::ostream& operator<<( std::ostream& os, const This& g );
00141 
00142 public:
00143         /// get the plugin by id.  vermaj and vermin can be specified.  if they are not it will
00144         /// pick the highest found version.
00145         OfxhPlugin*       getPluginById( const std::string& id, int vermaj = -1, int vermin = -1 );
00146         const OfxhPlugin* getPluginById( const std::string& id, int vermaj = -1, int vermin = -1 ) const { return const_cast<This&>( *this ).getPluginById( id, vermaj, vermin ); }
00147 
00148         /// get the list in which plugins are sought
00149         const std::list<std::string>& getPluginPath()
00150         {
00151                 return _pluginPath;
00152         }
00153 
00154         /// was the cache outdated?
00155         bool isDirty() const
00156         {
00157                 return _dirty;
00158         }
00159 
00160         void setDirty()
00161         {
00162                 //TUTTLE_TLOG( TUTTLE_INFO, "OfxhPluginCache::setDirty()" );
00163                 _dirty = true;
00164         }
00165 
00166         /// add a directory to the plugin path
00167         void addDirectoryToPath( const std::string& f, bool recurse = true )
00168         {
00169                 _pluginPath.push_back( f );
00170                 if( !recurse )
00171                 {
00172                         _nonrecursePath.insert( f );
00173                 }
00174         }
00175 
00176         /// specify which subdirectory of /usr/OFX or equivilant
00177         /// (as well as 'Plugins') to look in for plugins.
00178         void setPluginHostPath( const std::string& hostId );
00179 
00180         /// set the version string to write to the cache,
00181         /// and also that we expect on cachess read in
00182         void setCacheVersion( const std::string& cacheVersion )
00183         {
00184                 _cacheVersion = cacheVersion;
00185         }
00186 
00187         // populate the cache.  must call scanPluginFiles() after to check for changes.
00188         //void readCache( std::istream& is );
00189 
00190         // seek a particular file on the OFX plugin path
00191         std::string seekPluginFile( const std::string& baseName ) const;
00192 
00193         /// Sets behaviour of seekPluginFile().
00194         /// Enable (the default): normal operation; disable: returns an empty string instead
00195         void setPluginSeekEnabled( bool enabled )
00196         {
00197                 _enablePluginSeek = enabled;
00198         }
00199 
00200         /// scan for plugins
00201         void scanPluginFiles();
00202 
00203         /// register an API cache handler
00204         void registerAPICache( APICache::OfxhPluginAPICacheI& apiCache )
00205         {
00206                 _apiHandlers.push_back( PluginCacheSupportedApi( &apiCache ) );
00207         }
00208 
00209         /// find the API cache handler for the given api/apiverson
00210         APICache::OfxhPluginAPICacheI* findApiHandler( const std::string& api, int apiver );
00211 
00212         /// obtain a list of plugins to walk through
00213         const std::list<OfxhPlugin*>& getPlugins() const
00214         {
00215                 return _plugins;
00216         }
00217 
00218         OfxhPluginBinaryList& getBinaries()
00219         {
00220                 return _binaries;
00221         }
00222 
00223 private:
00224         friend class boost::serialization::access;
00225         template<class Archive>
00226         void serialize( Archive& ar, const unsigned int version )
00227         {
00228                 //              ar & BOOST_SERIALIZATION_NVP(_pluginPath);
00229                 //              ar & BOOST_SERIALIZATION_NVP(_nonrecursePath);
00230                 //              ar & BOOST_SERIALIZATION_NVP(_pluginDirs);
00231                 ar& BOOST_SERIALIZATION_NVP( _binaries );
00232                 //              ar & BOOST_SERIALIZATION_NVP(_plugins); // just a link, don't save this
00233                 ar& BOOST_SERIALIZATION_NVP( _knownBinFiles );
00234 
00235                 if( typename Archive::is_loading() )
00236                 {
00237                         for( ofx::OfxhPluginCache::OfxhPluginBinaryList::iterator it = getBinaries().begin(), itEnd = getBinaries().end();
00238                              it != itEnd;
00239                              ++it )
00240                         {
00241                                 for( ofx::OfxhPluginBinary::PluginVector::iterator i = it->getPlugins().begin(), iEnd = it->getPlugins().end();
00242                                      i != iEnd;
00243                                      ++i )
00244                                 {
00245                                         APICache::OfxhPluginAPICacheI* apiCache = findApiHandler( i->getPluginApi(), i->getApiVersion() );
00246                                         i->setApiHandler( *apiCache );
00247                                         _plugins.push_back( &( *i ) );
00248                                 }
00249                         }
00250                 }
00251         }
00252 
00253 };
00254 
00255 }
00256 }
00257 }
00258 
00259 #endif