platform/include/pion/platform/PluginConfig.hpp

00001 // ------------------------------------------------------------------------
00002 // Pion is a development platform for building Reactors that process Events
00003 // ------------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Pion is free software: you can redistribute it and/or modify it under the
00007 // terms of the GNU Affero General Public License as published by the Free
00008 // Software Foundation, either version 3 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Pion is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Affero General Public License
00017 // along with Pion.  If not, see <http://www.gnu.org/licenses/>.
00018 //
00019 
00020 #ifndef __PION_PLUGINCONFIG_HEADER__
00021 #define __PION_PLUGINCONFIG_HEADER__
00022 
00023 #include <libxml/tree.h>
00024 #include <boost/bind.hpp>
00025 #include <boost/signal.hpp>
00026 #include <boost/thread/mutex.hpp>
00027 #include <pion/PionConfig.hpp>
00028 #include <pion/PionException.hpp>
00029 #include <pion/PluginManager.hpp>
00030 #include <pion/platform/Vocabulary.hpp>
00031 #include <pion/platform/VocabularyManager.hpp>
00032 #include <pion/platform/ConfigManager.hpp>
00033 
00034 
00035 namespace pion {        // begin namespace pion
00036 namespace platform {    // begin namespace platform (Pion Platform Library)
00037 
00041 template <typename PluginType>
00042 class PluginConfig :
00043     public ConfigManager
00044 {
00045 public:
00046 
00048     class PluginException : public PionException {
00049     public:
00050         PluginException(const std::string& error_msg)
00051             : PionException(error_msg)
00052         {}
00053     };
00054     
00055 
00057     virtual ~PluginConfig() {}
00058     
00060     virtual void createConfigFile(void) {
00061         boost::mutex::scoped_lock plugins_lock(m_mutex);
00062         // just return if it's already open
00063         if (ConfigManager::configIsOpen())
00064             return;
00065         // create the file with "config" root element
00066         ConfigManager::createConfigFile();
00067         PION_LOG_INFO(m_logger, "Initializing new " << m_plugin_element
00068                       << " configuration file: " << ConfigManager::getConfigFile());
00069     }       
00070     
00072     virtual void openConfigFile(void) {
00073         boost::mutex::scoped_lock plugins_lock(m_mutex);
00074         // just return if it's already open
00075         if (ConfigManager::configIsOpen())
00076             return;
00077         // open the plug-in config file and load plug-ins
00078         ConfigManager::openPluginConfig(m_plugin_element);
00079         PION_LOG_INFO(m_logger, "Loaded " << m_plugin_element
00080                       << " configuration file: " << ConfigManager::getConfigFile());
00081     }
00082         
00088     virtual void writeConfigXML(std::ostream& out) const {
00089         boost::mutex::scoped_lock plugins_lock(m_mutex);
00090         ConfigManager::writeConfigXMLHeader(out);
00091         ConfigManager::writeConfigXML(out, m_config_node_ptr, true);
00092     }
00093     
00100     inline bool writeConfigXML(std::ostream& out, const std::string& plugin_id) const;
00101     
00112     inline xmlNodePtr getPluginConfig(const std::string& plugin_id);
00113     
00119     inline bool hasPlugin(const std::string& plugin_id) const {
00120         return (m_plugins.get(plugin_id) != NULL);
00121     }
00122     
00129     template <typename PluginUpdateFunction>
00130     inline boost::signals::connection registerForUpdates(PluginUpdateFunction f) const {
00131         boost::mutex::scoped_lock signal_lock(m_signal_mutex);
00132         return m_signal_plugins_updated.connect(f);
00133     }
00134 
00136     inline void updateVocabulary(void) {
00137         VocabularyPtr vocab_ptr(m_vocab_mgr.getVocabulary());
00138         m_plugins.run(boost::bind(&PluginType::updateVocabulary, _1,
00139                                   boost::cref(*vocab_ptr)));
00140     }
00141 
00143     inline VocabularyPtr getVocabulary(void) const { return m_vocab_mgr.getVocabulary(); }
00144 
00146     inline const VocabularyManager& getVocabularyManager(void) const { return m_vocab_mgr; }
00147     
00148     
00149 protected:
00150 
00152     inline void releasePlugins(void) { m_plugins.clear(); }
00153 
00161     PluginConfig(const VocabularyManager& vocab_mgr,
00162                  const std::string& config_file,
00163                  const std::string& plugin_element)
00164         : ConfigManager(config_file),
00165         m_vocab_mgr(vocab_mgr),
00166         m_plugin_element(plugin_element)
00167     {
00168         m_vocab_connection = vocab_mgr.registerForUpdates(boost::bind(&PluginConfig::updateVocabulary, this));
00169         setLogger(PION_GET_LOGGER("pion.platform.PluginConfig"));
00170     }
00171 
00179     inline void setPluginConfig(const std::string& plugin_id,
00180                                 const xmlNodePtr config_ptr);
00181 
00190     inline std::string addPlugin(const xmlNodePtr config_ptr);
00191     
00197     inline void removePlugin(const std::string& plugin_id);
00198     
00210     virtual void addPluginNoLock(const std::string& plugin_id,
00211                                  const std::string& plugin_name,
00212                                  const xmlNodePtr config_ptr) = 0;
00213     
00214     
00216     const VocabularyManager&        m_vocab_mgr;
00217 
00219     const std::string               m_plugin_element;
00220     
00222     PluginManager<PluginType>       m_plugins;
00223 
00225     boost::signals::scoped_connection   m_vocab_connection;
00226     
00228     mutable boost::signal0<void>    m_signal_plugins_updated;
00229 
00231     mutable boost::mutex            m_signal_mutex; 
00232 
00234     mutable boost::mutex            m_mutex;    
00235 };
00236 
00237     
00238 // inline member functions for PluginConfig
00239 
00240 template <typename PluginType>
00241 inline bool PluginConfig<PluginType>::writeConfigXML(std::ostream& out,
00242                                                      const std::string& plugin_id) const
00243 {
00244     // find the plug-in element in the XML config document
00245     boost::mutex::scoped_lock plugins_lock(m_mutex);
00246     xmlNodePtr plugin_node = findConfigNodeByAttr(m_plugin_element,
00247                                                   ID_ATTRIBUTE_NAME,
00248                                                   plugin_id,
00249                                                   m_config_node_ptr->children);
00250     if (plugin_node == NULL)
00251         return false;
00252     
00253     // found it
00254     ConfigManager::writeBeginPionConfigXML(out);
00255     ConfigManager::writeConfigXML(out, plugin_node, false);
00256     ConfigManager::writeEndPionConfigXML(out);
00257 
00258     return true;
00259 }
00260 
00261 template <typename PluginType>
00262 inline xmlNodePtr PluginConfig<PluginType>::getPluginConfig(const std::string& plugin_id)
00263 {
00264     // find the plug-in element in the XML config document
00265     boost::mutex::scoped_lock plugins_lock(m_mutex);
00266     xmlNodePtr plugin_node = findConfigNodeByAttr(m_plugin_element,
00267                                                   ID_ATTRIBUTE_NAME,
00268                                                   plugin_id,
00269                                                   m_config_node_ptr->children);
00270     if (plugin_node == NULL)
00271         throw typename PluginManager<PluginType>::PluginNotFoundException(plugin_id);
00272     
00273     // copy the plugin configuration
00274     return xmlCopyNodeList(plugin_node);
00275 }
00276     
00277 template <typename PluginType>
00278 inline void PluginConfig<PluginType>::setPluginConfig(const std::string& plugin_id,
00279                                                       const xmlNodePtr config_ptr)
00280 {
00281     // make sure that the plug-in configuration file is open
00282     if (! configIsOpen())
00283         throw ConfigNotOpenException(getConfigFile());
00284     
00285     VocabularyPtr vocab_ptr(m_vocab_mgr.getVocabulary());
00286 
00287     // update it within memory and the configuration file
00288     boost::mutex::scoped_lock plugins_lock(m_mutex);
00289     m_plugins.run(plugin_id, boost::bind(&PluginType::setConfig, _1,
00290                                          boost::cref(*vocab_ptr), config_ptr));
00291     ConfigManager::setPluginConfig(m_plugin_element, plugin_id, config_ptr);
00292     
00293     // unlock class mutex to prevent deadlock
00294     plugins_lock.unlock();
00295 
00296     // send notifications
00297     PION_LOG_DEBUG(m_logger, "Updated " << m_plugin_element << " configuration (" << plugin_id << ')');
00298     boost::mutex::scoped_lock signal_lock(m_signal_mutex);
00299     m_signal_plugins_updated();
00300 }
00301 
00302 template <typename PluginType>
00303 inline std::string PluginConfig<PluginType>::addPlugin(const xmlNodePtr config_ptr)
00304 {
00305     // make sure that the plug-in configuration file is open
00306     if (! configIsOpen())
00307         throw ConfigNotOpenException(getConfigFile());
00308 
00309     // find the plug-in type within the XML configuration
00310     std::string plugin_type;
00311     const std::string plugin_id(ConfigManager::createUUID());
00312     if (config_ptr == NULL || ! getConfigOption(PLUGIN_ELEMENT_NAME, plugin_type, config_ptr))
00313         throw EmptyPluginElementException(plugin_id);
00314     
00315     // create the new plug-in and add it to the config file
00316     boost::mutex::scoped_lock plugins_lock(m_mutex);
00317     addPluginNoLock(plugin_id, plugin_type, config_ptr);
00318     addPluginConfig(m_plugin_element, plugin_id, plugin_type, config_ptr);
00319     
00320     // unlock class mutex to prevent deadlock
00321     plugins_lock.unlock();
00322 
00323     // send notifications
00324     PION_LOG_DEBUG(m_logger, "Loaded " << m_plugin_element << " (" << plugin_type << "): " << plugin_id);
00325     boost::mutex::scoped_lock signal_lock(m_signal_mutex);
00326     m_signal_plugins_updated();
00327     signal_lock.unlock();
00328     
00329     // return the plug-in's (new) identifier
00330     return plugin_id;
00331 }
00332 
00333 template <typename PluginType>
00334 inline void PluginConfig<PluginType>::removePlugin(const std::string& plugin_id)
00335 {
00336     // make sure that the plug-in configuration file is open
00337     if (! configIsOpen())
00338         throw ConfigNotOpenException(getConfigFile());
00339 
00340     // first store a smart pointer to the shared library code
00341     // this guarantees it will not be released until after the updated signal
00342     // has been called, and all users of these types of plugins have released them
00343     boost::mutex::scoped_lock plugins_lock(m_mutex);
00344     PionPluginPtr<PluginType> plugin_lib_ptr(m_plugins.getLibPtr(plugin_id));
00345 
00346     // remove it from memory and the configuration file
00347     m_plugins.remove(plugin_id);
00348     removePluginConfig(m_plugin_element, plugin_id);
00349     
00350     // unlock class mutex to prevent deadlock
00351     plugins_lock.unlock();
00352 
00353     // send notifications
00354     PION_LOG_DEBUG(m_logger, "Removed " << m_plugin_element << ": " << plugin_id);
00355     boost::mutex::scoped_lock signal_lock(m_signal_mutex);
00356     m_signal_plugins_updated();
00357 }
00358 
00359 
00360 }   // end namespace platform
00361 }   // end namespace pion
00362 
00363 #endif

Generated on Wed Apr 13 16:38:34 2011 for pion-platform by  doxygen 1.4.7