PluginSystem.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2013, Institute for Artificial Intelligence,
00005  *  Universität Bremen.
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Institute for Artificial Intelligence,
00019  *     Universität Bremen, nor the names of its contributors may be
00020  *     used to endorse or promote products derived from this software
00021  *     without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *********************************************************************/
00036 
00040 #include <PluginSystem.h>
00041 
00042 
00043 namespace beliefstate {
00044   PluginSystem::PluginSystem(int argc, char** argv) {
00045     m_argc = argc;
00046     m_argv = argv;
00047     
00048     this->setMessagePrefixLabel("plugins");
00049   }
00050   
00051   PluginSystem::~PluginSystem() {
00052     m_lstLoadedPlugins.reverse();
00053     
00054     // Trigger kill signals
00055     for(PluginInstance* icCurrent : m_lstLoadedPlugins) {
00056       icCurrent->setRunning(false);
00057     }
00058     
00059     // Join all threads
00060     for(PluginInstance* icCurrent : m_lstLoadedPlugins) {
00061       icCurrent->waitForJoin();
00062     }
00063     
00064     // Delete all structures
00065     for(PluginInstance* icCurrent : m_lstLoadedPlugins) {
00066       icCurrent->unload();
00067       delete icCurrent;
00068     }
00069     
00070     m_lstLoadedPlugins.clear();
00071   }
00072   
00073   string PluginSystem::pluginNameFromPath(string strPath) {
00074     // Remove path
00075     const size_t last_slash_idx = strPath.find_last_of("\\/");
00076     if(std::string::npos != last_slash_idx) {
00077       strPath.erase(0, last_slash_idx + 1);
00078     }
00079     
00080     // Remove extension
00081     const size_t period_idx = strPath.rfind('.');
00082     if(std::string::npos != period_idx) {
00083       strPath.erase(period_idx);
00084     }
00085     
00086     // Remove plugin prefix
00087     std::string strPrefix = "libbs_plugin_";
00088     
00089     if(strPath.substr(0, strPrefix.size()) == strPrefix) {
00090       strPath = strPath.substr(strPrefix.size());
00091     }
00092     
00093     return strPath;
00094   }
00095   
00096   bool PluginSystem::pluginLoaded(std::string strPluginName) {
00097     for(PluginInstance* icCurrent : m_lstLoadedPlugins) {
00098       if(icCurrent->name() == strPluginName) {
00099         return true;
00100       }
00101     }
00102     
00103     return false;
00104   }
00105   
00106   void PluginSystem::setLoadDevelopmentPlugins(bool bLoadDevelopmentPlugins) {
00107     m_bLoadDevelopmentPlugins = bLoadDevelopmentPlugins;
00108   }
00109   
00110   bool PluginSystem::loadDevelopmentPlugins() {
00111     return m_bLoadDevelopmentPlugins;
00112   }
00113   
00114   bool PluginSystem::pluginFailedToLoadBefore(std::string strName) {
00115     for(std::string strPluginName : m_lstLoadFailedPlugins) {
00116       if(strPluginName == strName) {
00117         return true;
00118       }
00119     }
00120     
00121     return false;
00122   }
00123   
00124   Result PluginSystem::loadPluginLibrary(std::string strFilepath, bool bIsNameOnly) {
00125     PluginInstance* icLoad = NULL;
00126     std::string strPrefix = "libbs_plugin_";
00127     std::string strSuffix = ".so";
00128     
00129     if(bIsNameOnly) {
00130       strFilepath = strPrefix + strFilepath + strSuffix;
00131     }
00132     
00133     std::list<std::string> lstSearchPaths = m_lstPluginSearchPaths;
00134     lstSearchPaths.push_front("./"); // Add local path as search path
00135     
00136     Result resLoad = defaultResult();
00137     resLoad.bSuccess = false;
00138     
00139     if(this->pluginLoaded(this->pluginNameFromPath(strFilepath))) {
00140       this->info("Plugin '" + this->pluginNameFromPath(strFilepath) + "' already loaded.");
00141       resLoad.bSuccess = true;
00142     } else {
00143       if(!this->pluginFailedToLoadBefore(strFilepath)) {
00144         for(string strSP : lstSearchPaths) {
00145           string strSearchFilepath = strSP + (strSP[strSP.size() - 1] != '/' && strFilepath[0] != '/' && strSP.size() > 0 ? "/" : "") + strFilepath;
00146           
00147           icLoad = new PluginInstance();
00148           resLoad = icLoad->loadPluginLibrary(strSearchFilepath);
00149           resLoad.piPlugin = icLoad;
00150           
00151           if(resLoad.bSuccess) {
00152             // Check if this is a development plugin and if we're supposed to load it.
00153             if((icLoad->developmentPlugin() && m_bLoadDevelopmentPlugins) || !icLoad->developmentPlugin()) {
00154               if(icLoad->developmentPlugin()) {
00155                 this->info("This is a development plugin: '" + strFilepath + "'");
00156               }
00157               
00158               // Check and meet dependencies
00159               std::list<std::string> lstDeps = icLoad->dependencies();
00160               for(string strDep : lstDeps) {
00161                 if(this->pluginLoaded(strDep) == false) {
00162                   Result resLoadDep = this->loadPluginLibrary(strPrefix + strDep + strSuffix);
00163                   
00164                   if(resLoadDep.bSuccess == false) {
00165                     this->fail("Unable to meet dependency of '" + strSearchFilepath + "': '" + strDep + "'");
00166                     
00167                     resLoad.bSuccess = false;
00168                     resLoad.riResultIdentifier = RI_PLUGIN_DEPENDENCY_NOT_MET;
00169                     resLoad.strErrorMessage = strDep;
00170                     
00171                     break;
00172                   }
00173                 }
00174               }
00175             } else {
00176               this->info("Not loading development plugin: '" + strFilepath + "'");
00177               
00178               resLoad.bSuccess = false;
00179               resLoad.riResultIdentifier = RI_PLUGIN_DEVELOPMENT_NOT_LOADING;
00180             }
00181             
00182             if(resLoad.bSuccess) {
00183               // Initialize the plugin
00184               Result rsResult = icLoad->init(m_argc, m_argv);
00185               
00186               if(rsResult.bSuccess) {
00187                 m_lstLoadedPlugins.push_back(icLoad);
00188               } else {
00189                 resLoad.bSuccess = false;
00190                 resLoad.riResultIdentifier = RI_PLUGIN_LOADING_FAILED;
00191               }
00192               
00193               break;
00194             }
00195           } else {
00196             resLoad.bSuccess = false;
00197             resLoad.riResultIdentifier = RI_PLUGIN_LOADING_FAILED;
00198           }
00199           
00200           if(resLoad.bSuccess == false) {
00201             icLoad->unload();
00202             m_lstLoadFailedPlugins.push_back(strFilepath);
00203             
00204             delete icLoad;
00205           } else {
00206             break;
00207           }
00208         }
00209       } else {
00210         this->warn("This plugin failed to load before. Skipping it.");
00211       }
00212     }
00213     
00214     if(resLoad.bSuccess == false) {
00215       this->fail("Failed to load plugin '" + strFilepath + "'");
00216     } else {
00217       resLoad.piPlugin = icLoad;
00218     }
00219     
00220     return resLoad;
00221   }
00222   
00223   void PluginSystem::queueUnloadPluginInstance(PluginInstance* icUnload) {
00224     m_lstUnloadPlugins.push_back(icUnload);
00225   }
00226   
00227   int PluginSystem::spreadEvent(Event evEvent) {
00228     int nReceivers = 0;
00229     
00230     for(PluginInstance* piPlugin : m_lstLoadedPlugins) {
00231       if(piPlugin->subscribedToEvent(evEvent.strEventName)) {
00232         piPlugin->consumeEvent(evEvent);
00233         nReceivers++;
00234       }
00235     }
00236     
00237     return nReceivers;
00238   }
00239   
00240   int PluginSystem::spreadServiceEvent(ServiceEvent seServiceEvent) {
00241     list<Event> lstResultEvents;
00242     int nReceivers = 0;
00243     
00244     for(PluginInstance* piPlugin : m_lstLoadedPlugins) {
00245       if(piPlugin->offersService(seServiceEvent.strServiceName) ||
00246          seServiceEvent.siServiceIdentifier == SI_RESPONSE) {
00247         Event evResult = piPlugin->consumeServiceEvent(seServiceEvent);
00248         nReceivers++;
00249         
00250         if(seServiceEvent.smResultModifier != SM_IGNORE_RESULTS) {
00251           evResult.nOriginID = piPlugin->pluginID();
00252           lstResultEvents.push_back(evResult);
00253           
00254           if(seServiceEvent.smResultModifier == SM_FIRST_RESULT) {
00255             break;
00256           } else {
00257             // Aggregate results
00258           }
00259         }
00260       }
00261     }
00262     
00263     PluginInstance* piRequester = this->pluginInstanceByID(seServiceEvent.nRequesterID);
00264     if(piRequester && seServiceEvent.smResultModifier != SM_IGNORE_RESULTS) {
00265       ServiceEvent seResponses = seServiceEvent;
00266       seResponses.lstResultEvents = lstResultEvents;
00267       seResponses.siServiceIdentifier = SI_RESPONSE;
00268       
00269       piRequester->consumeServiceEvent(seResponses);
00270     }
00271     
00272     return nReceivers;
00273   }
00274   
00275   Result PluginSystem::cycle() {
00276     Result resCycle = defaultResult();
00277     
00278     for(PluginInstance* icCurrent : m_lstLoadedPlugins) {
00279       Result resCurrent = icCurrent->cycle();
00280       
00281       for(StatusMessage smCurrent : resCurrent.lstStatusMessages) {
00282         resCycle.lstStatusMessages.push_back(smCurrent);
00283       }
00284       
00285       if(resCurrent.bSuccess == false) {
00286         // NOTE(winkler): This might also be a good place to implement
00287         // a recovery mechanism in case a plugin actually fails during
00288         // its cycle. Reload plugins and notify all "depending"
00289         // plugins (in order of dependency) to "recover".
00290         this->queueUnloadPluginInstance(icCurrent);
00291       } else {
00292         for(Event evtCurrent : resCurrent.lstEvents) {
00293           resCycle.lstEvents.push_back(evtCurrent);
00294         }
00295         
00296         for(ServiceEvent seCurrent : resCurrent.lstServiceEvents) {
00297           resCycle.lstServiceEvents.push_back(seCurrent);
00298         }
00299       }
00300     }
00301     
00302     for(PluginInstance* icCurrent : m_lstUnloadPlugins) {
00303       icCurrent->unload();
00304       m_lstLoadedPlugins.remove(icCurrent);
00305       delete icCurrent;
00306     }
00307     
00308     return resCycle;
00309   }
00310   
00311   void PluginSystem::addPluginSearchPath(std::string strPath) {
00312     // Make sure it is in there only once.
00313     m_lstPluginSearchPaths.remove(strPath);
00314     m_lstPluginSearchPaths.push_back(strPath);
00315   }
00316   
00317   PluginInstance* PluginSystem::pluginInstanceByID(int nID) {
00318     for(PluginInstance* icCurrent : m_lstLoadedPlugins) {
00319       if(icCurrent->pluginID() == nID) {
00320         return icCurrent;
00321       }
00322     }
00323     
00324     return NULL;
00325   }
00326 }


beliefstate
Author(s): Jan Winkler
autogenerated on Sun Oct 5 2014 22:30:15