Beliefstate.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 <Beliefstate.h>
00041 
00042 
00043 namespace beliefstate {
00044   Beliefstate::Beliefstate(int argc, char** argv) {
00045     m_psPlugins = NULL;
00046     m_bRun = true;
00047     m_argc = argc;
00048     m_argv = argv;
00049     m_strWorkspaceDirectory = "";
00050     m_bTerminalWindowResize = false;
00051     m_bCommandLineOutput = true;
00052     m_strVersion = "0.7 iai";
00053     
00054     this->setRedirectOutput(false);
00055     
00056     this->setMessagePrefixLabel("core");
00057     
00058     m_lstConfigFileLocations.push_back(""); // Current directory
00059     m_lstConfigFileLocations.push_back(this->resolveDirectoryTokens("${HOME}/.beliefstate/")); // Home directory
00060   }
00061   
00062   Beliefstate::~Beliefstate() {
00063   }
00064   
00065   std::string Beliefstate::version() {
00066     return m_strVersion;
00067   }
00068   
00069   Result Beliefstate::init(std::string strConfigFile) {
00070     Result resInit = defaultResult();
00071     
00072     // Do the actual init here.
00073     m_psPlugins = new PluginSystem(m_argc, m_argv);
00074     
00075     std::list<std::string> lstConfigFiles;
00076     for(std::string strLocation : m_lstConfigFileLocations) {
00077       std::string strLocationCleaned = strLocation;
00078       if(strLocationCleaned[strLocationCleaned.length() - 1] != '/') {
00079         strLocationCleaned += "/";
00080       }
00081       
00082       strLocationCleaned += "config.cfg";
00083       lstConfigFiles.push_back(strLocationCleaned);
00084     }
00085     
00086     if(strConfigFile != "") {
00087       lstConfigFiles.push_front(strConfigFile);
00088     }
00089     
00090     bool bConfigLoaded = false;
00091     for(std::string strConfigFileCurrent : lstConfigFiles) {
00092       if(this->loadConfigFile(strConfigFileCurrent)) {
00093         this->info("Loaded config file '" + strConfigFileCurrent + "'.");
00094         bConfigLoaded = true;
00095         
00096         break;
00097       }
00098     }
00099     
00100     if(bConfigLoaded) {
00101       // Messages are distributed through the event system from now
00102       // on.
00103       this->setRedirectOutput(true);
00104       
00105       // Set the global PluginSystem settings.
00106       ConfigSettings cfgsetCurrent = configSettings();
00107       m_psPlugins->setLoadDevelopmentPlugins(cfgsetCurrent.bLoadDevelopmentPlugins);
00108       
00109       // Set the settings concerning MongoDB, and experiment name mask
00110       // for each plugin here (through PluginSystem).
00111       for(string strPluginName : m_lstPluginsToLoad) {
00112         Result rsResult = m_psPlugins->loadPluginLibrary(strPluginName, true);
00113         
00114         if(!rsResult.bSuccess) {
00115           if(cfgsetCurrent.bFailedPluginsInvalidateStartup) {
00116             this->fail("Failed plugin load invalidates startup. Cancelling.");
00117             resInit.bSuccess = false;
00118             break;
00119           }
00120         } else {
00121           if(rsResult.piPlugin) {
00122             rsResult.piPlugin->setOnlyDisplayImportant(m_bOnlyDisplayImportant);
00123           }
00124         }
00125       }
00126     } else {
00127       this->fail("Failed to load a valid config file.");
00128       resInit.bSuccess = false;
00129     }
00130     
00131     // Additional checks to make the user aware of potential problems
00132     if(this->workspaceDirectory() == "") {
00133       this->warn("The workspace directory could not be resolved. This might cause problems, especially when trying to load plugins. Please ensure that your environment is set up properly. If everything seems alright, consider to override the workspace-dependent paths in a custom file (i.e. ~/.beliefstate/config.cfg).");
00134     }
00135     
00136     if(resInit.bSuccess) {
00137       m_lstGlobalEvents.push_back(defaultEvent("startup-complete"));
00138     }
00139     
00140     return resInit;
00141   }
00142   
00143   Result Beliefstate::deinit() {
00144     Result resInit = defaultResult();
00145     
00146     if(m_psPlugins) {
00147       delete m_psPlugins;
00148     }
00149     
00150     return resInit;
00151   }
00152   
00153   bool Beliefstate::loadConfigFile(std::string strConfigFile) {
00154     if(this->fileExists(strConfigFile)) {
00155       libconfig::Config cfgConfig;
00156       
00157       try {
00158         cfgConfig.readFile(strConfigFile.c_str());
00159         
00160         // Section: Miscellaneous -- IMPORTANT: Check first. This
00161         // section sets the 'workspace-directory' variable if
00162         // available. This affects all directory resolutions
00163         // afterwards that might use the ${WORKSPACE} token.
00164         bool bDisplayUnhandledEvents = true;
00165         bool bDisplayUnhandledServiceEvents = true;
00166         m_bOnlyDisplayImportant = false;
00167         
00168         if(cfgConfig.exists("miscellaneous")) {
00169           libconfig::Setting &sMiscellaneous = cfgConfig.lookup("miscellaneous");
00170           sMiscellaneous.lookupValue("display-unhandled-events", bDisplayUnhandledEvents);
00171           sMiscellaneous.lookupValue("display-unhandled-service-events", bDisplayUnhandledServiceEvents);
00172           sMiscellaneous.lookupValue("workspace-directory", m_strWorkspaceDirectory);
00173           sMiscellaneous.lookupValue("command-line-output", m_bCommandLineOutput);
00174           sMiscellaneous.lookupValue("only-display-important-messages", m_bOnlyDisplayImportant);
00175           
00176           if(!m_bCommandLineOutput) {
00177             this->setRedirectOutput(true);
00178           }
00179         }
00180         
00181         // Section: Persistent data storage
00182         std::string strBaseDataDirectory = "";
00183         std::string strMongoDBHost = "";
00184         std::string strMongoDBDatabase = "";
00185         int nMongoDBPort = 27017;
00186         bool bUseMongoDB = false;
00187         
00188         if(cfgConfig.exists("persistent-data-storage")) {
00189           libconfig::Setting &sPersistentDataStorage = cfgConfig.lookup("persistent-data-storage");
00190           sPersistentDataStorage.lookupValue("base-data-directory", strBaseDataDirectory);
00191           strBaseDataDirectory = this->resolveDirectoryTokens(strBaseDataDirectory);
00192           
00193           sPersistentDataStorage.lookupValue("use-mongodb", bUseMongoDB);
00194           
00195           if(bUseMongoDB) {
00196             if(cfgConfig.exists("persistent-data-storage.mongodb")) {
00197               libconfig::Setting &sMongoDB = cfgConfig.lookup("persistent-data-storage.mongodb");
00198               sMongoDB.lookupValue("host", strMongoDBHost);
00199               sMongoDB.lookupValue("port", nMongoDBPort);
00200               sMongoDB.lookupValue("database", strMongoDBDatabase);
00201             }
00202           }
00203         }
00204         
00205         // Section: Experiment data
00206         std::string strExperimentNameMask = "";
00207         std::string strSymlinkName = "";
00208         
00209         if(cfgConfig.exists("experiment-data")) {
00210           libconfig::Setting &sExperimentData = cfgConfig.lookup("experiment-data");
00211           sExperimentData.lookupValue("experiment-name-mask", strExperimentNameMask);
00212           sExperimentData.lookupValue("symlink-name", strSymlinkName);
00213         }
00214         
00215         // Check to see if the data given so far is valid. If it is
00216         // not, abort loading and notify the user.
00217         bool bSettingsOK = true;
00218         
00219         if((bUseMongoDB == true && (strMongoDBHost == "" ||
00220                                     strMongoDBDatabase == "" ||
00221                                     nMongoDBPort == 0))) {
00222           this->fail("Error while loading MongoDB settings:");
00223           if(strMongoDBHost == "") {
00224             this->fail(" - MongoDB Host is empty");
00225           }
00226           
00227           if(strMongoDBHost == "") {
00228             this->fail(" - MongoDB Database is empty");
00229           }
00230           
00231           if(nMongoDBPort == 0) {
00232             this->fail(" - MongoDB Port is not set or '0' (which is invalid)");
00233           }
00234           
00235           bSettingsOK = false;
00236         }
00237         
00238         if(bSettingsOK == false) {
00239           return false;
00240         }
00241         
00242         if(strSymlinkName == "" || strExperimentNameMask == "" || (strExperimentNameMask.find("%d") == string::npos && strExperimentNameMask.find("%s") == string::npos) || strBaseDataDirectory == "") {
00243           if(strBaseDataDirectory == "") {
00244             this->warn("The base data directory path is empty.");
00245             strBaseDataDirectory = this->resolveDirectoryTokens("${HOME}/bs_experimental_data");
00246             this->warn("Defaulting to: '" + strBaseDataDirectory + "'");
00247           }
00248           
00249           if(strSymlinkName == "") {
00250             this->warn("The symlink name for experiments is empty.");
00251             strSymlinkName = "current-experiment";
00252             this->warn("Defaulting to: '" + strSymlinkName + "'");
00253           }
00254           
00255           if(strExperimentNameMask == "") {
00256             this->warn("The experiment name mask is empty.");
00257             strExperimentNameMask = "exp-%d";
00258             this->warn("Defaulting to: '" + strExperimentNameMask + "'");
00259           } else if(strExperimentNameMask.find("%d") == string::npos && strExperimentNameMask.find("%s") == string::npos) {
00260             this->warn("The experiment name mask does not include the '\%d' or '\%s' escape sequence.");
00261             this->warn("It is currently: '" + strExperimentNameMask + "'");
00262             this->warn("This will cause your experiments to be overwritten. Be careful.");
00263           }
00264         }
00265         
00266         // Section: Plugins
00267         bool bLoadDevelopmentPlugins = false;
00268         bool bFailedPluginsInvalidateStartup = true;
00269         std::vector<std::string> vecPluginOutputColors;
00270         bool bSearchPathsSet = false;
00271         
00272         if(cfgConfig.exists("plugins")) {
00273           libconfig::Setting &sPlugins = cfgConfig.lookup("plugins");
00274           sPlugins.lookupValue("load-development-plugins", bLoadDevelopmentPlugins);
00275           sPlugins.lookupValue("failed-plugins-invalidate-startup", bFailedPluginsInvalidateStartup);
00276           
00277           if(cfgConfig.exists("plugins.load")) {
00278             libconfig::Setting &sPluginsLoad = cfgConfig.lookup("plugins.load");
00279             m_lstPluginsToLoad.clear();
00280             
00281             for(int nI = 0; nI < sPluginsLoad.getLength(); nI++) {
00282               std::string strLoad = sPluginsLoad[nI];
00283               
00284               m_lstPluginsToLoad.remove(strLoad);
00285               m_lstPluginsToLoad.push_back(strLoad);
00286             }
00287           }
00288           
00289           if(cfgConfig.exists("plugins.search-paths")) {
00290             libconfig::Setting &sPluginsPaths = cfgConfig.lookup("plugins.search-paths");
00291             
00292             for(int nI = 0; nI < sPluginsPaths.getLength(); nI++) {
00293               std::string strPath = sPluginsPaths[nI];
00294               
00295               strPath = this->resolveDirectoryTokens(strPath);
00296               m_psPlugins->addPluginSearchPath(strPath);
00297               
00298               bSearchPathsSet = true;
00299             }
00300           }
00301           
00302           if(cfgConfig.exists("plugins.colors")) {
00303             libconfig::Setting &sPluginsColors = cfgConfig.lookup("plugins.colors");
00304             
00305             for(int nI = 0; nI < sPluginsColors.getLength(); nI++) {
00306               std::string strColor = sPluginsColors[nI];
00307               vecPluginOutputColors.push_back(strColor);
00308             }
00309           }
00310           
00311           if(cfgConfig.exists("plugins.individual-configurations")) {
00312             libconfig::Setting &sPluginsIndividualConfigurations = cfgConfig.lookup("plugins.individual-configurations");
00313             
00314             for(int nI = 0; nI < sPluginsIndividualConfigurations.getLength(); nI++) {
00315               std::string strPluginName;
00316               
00317               if(sPluginsIndividualConfigurations[nI].lookupValue("plugin", strPluginName)) {
00318                 this->info("Loading per-plugin configuration for plugin '" + strPluginName + "'");
00319                 CDesignator* cdConfig = getPluginConfig(strPluginName);
00320                 
00321                 if(this->loadIndividualPluginConfigurationBranch(sPluginsIndividualConfigurations[nI], cdConfig, "", true) == false) {
00322                   this->warn("Failed to load configuration for plugin '" + strPluginName + "'.");
00323                 }
00324               } else {
00325                 this->warn("No 'plugin'-field specified for individual plugin configuration.");
00326               }
00327             }
00328           }
00329         }
00330         
00331         // Check if any search paths were set
00332         if(bSearchPathsSet == false) {
00333           this->warn("You didn't specify any search paths. This will prevent the system");
00334           this->warn("from finding any plugins. A default will be assumed.");
00335           std::string strSP = this->resolveDirectoryTokens("$WORKSPACE/lib/");
00336           this->warn("Defaulting to: '" + strSP + "'");
00337           
00338           m_psPlugins->addPluginSearchPath(strSP);
00339         }
00340         
00341         if(vecPluginOutputColors.size() == 0) {
00342           this->warn("The plugin output colors are empty. This might cause display issues.");
00343           
00344           vecPluginOutputColors.push_back("31");
00345           vecPluginOutputColors.push_back("32");
00346           vecPluginOutputColors.push_back("33");
00347           vecPluginOutputColors.push_back("34");
00348           vecPluginOutputColors.push_back("35");
00349           vecPluginOutputColors.push_back("36");
00350           vecPluginOutputColors.push_back("37");
00351           
00352           std::string strColors = "";
00353           for(string strC : vecPluginOutputColors) {
00354             strColors += (strColors != "" ? ", " : "") + string("\033[0;") + strC + "m" + strC + "\033[0m";
00355           }
00356           
00357           this->warn("Defaulting to: " + strColors);
00358         }
00359         
00360         // -> Set the global settings
00361         ConfigSettings cfgsetCurrent = configSettings();
00362         cfgsetCurrent.bLoadDevelopmentPlugins = bLoadDevelopmentPlugins;
00363         cfgsetCurrent.bFailedPluginsInvalidateStartup = bFailedPluginsInvalidateStartup;
00364         cfgsetCurrent.bUseMongoDB = bUseMongoDB;
00365         cfgsetCurrent.strMongoDBHost = strMongoDBHost;
00366         cfgsetCurrent.nMongoDBPort = nMongoDBPort;
00367         cfgsetCurrent.strMongoDBDatabase = strMongoDBDatabase;
00368         cfgsetCurrent.strExperimentNameMask = strExperimentNameMask;
00369         cfgsetCurrent.strBaseDataDirectory = strBaseDataDirectory;
00370         cfgsetCurrent.strSymlinkName = strSymlinkName;
00371         cfgsetCurrent.bDisplayUnhandledEvents = bDisplayUnhandledEvents;
00372         cfgsetCurrent.bDisplayUnhandledServiceEvents = bDisplayUnhandledServiceEvents;
00373         cfgsetCurrent.vecPluginOutputColors = vecPluginOutputColors;
00374         cfgsetCurrent.bOnlyDisplayImportant = m_bOnlyDisplayImportant;
00375         setConfigSettings(cfgsetCurrent);
00376         
00377         return true;
00378       } catch(libconfig::ParseException e) {
00379         std::stringstream sts;
00380         sts << e.getLine();
00381         
00382         this->fail("Error while parsing config file '" + strConfigFile + "': " + e.getError() + ", on line " + sts.str());
00383       } catch(...) {
00384         this->fail("Undefined error while parsing config file '" + strConfigFile + "'");
00385       }
00386     }
00387     
00388     return false;
00389   }
00390   
00391   bool Beliefstate::loadIndividualPluginConfigurationBranch(libconfig::Setting &sBranch, CKeyValuePair* ckvpInto, std::string strConfigPath, bool bIgnorePluginField) {
00392     for(int nJ = 0; nJ < sBranch.getLength(); nJ++) {
00393       if(sBranch.getType() != libconfig::Setting::TypeGroup) {
00394         for(int nI = 0; nI < sBranch.getLength(); nI++) {
00395           std::stringstream sts;
00396           sts << nI;
00397           
00398           this->info(" - " + strConfigPath + (strConfigPath == "" ? "" : "/") + sts.str());
00399           CKeyValuePair* ckvpChild = ckvpInto->addChild(sts.str());
00400           
00401           switch(sBranch[nI].getType()) {
00402           case libconfig::Setting::TypeString: {
00403             std::string strContent = sBranch[nI];
00404             strContent = this->resolveDirectoryTokens(strContent);
00405             ckvpInto->setValue(sts.str(), strContent);
00406           } break;
00407             
00408           case libconfig::Setting::TypeInt:
00409           case libconfig::Setting::TypeInt64: {
00410             int nContent = sBranch[nI];
00411             ckvpInto->setValue(sts.str(), nContent);
00412           } break;
00413             
00414           case libconfig::Setting::TypeFloat: {
00415             int fContent = sBranch[nI];
00416             ckvpInto->setValue(sts.str(), fContent);
00417           } break;
00418             
00419           case libconfig::Setting::TypeBoolean: {
00420             bool bContent = sBranch[nI];
00421             ckvpInto->setValue(sts.str(), bContent);
00422           } break;
00423           }
00424         }
00425       } else {
00426         std::string strConfigDetailName = sBranch[nJ].getName();
00427         
00428         if(strConfigDetailName != "plugin" || !bIgnorePluginField) {
00429           this->info(" - " + strConfigPath + (strConfigPath == "" ? "" : "/") + strConfigDetailName);
00430           
00431           switch(sBranch[strConfigDetailName].getType()) {
00432           case libconfig::Setting::TypeString: {
00433             std::string strContent;
00434             sBranch.lookupValue(strConfigDetailName, strContent);
00435             strContent = this->resolveDirectoryTokens(strContent);
00436             ckvpInto->setValue(strConfigDetailName, strContent);
00437           } break;
00438                       
00439           case libconfig::Setting::TypeInt:
00440           case libconfig::Setting::TypeInt64: {
00441             int nContent;
00442             sBranch.lookupValue(strConfigDetailName, nContent);
00443             ckvpInto->setValue(strConfigDetailName, nContent);
00444           } break;
00445                       
00446           case libconfig::Setting::TypeFloat: {
00447             int fContent;
00448             sBranch.lookupValue(strConfigDetailName, fContent);
00449             ckvpInto->setValue(strConfigDetailName, fContent);
00450           } break;
00451                       
00452           case libconfig::Setting::TypeBoolean: {
00453             bool bContent;
00454             sBranch.lookupValue(strConfigDetailName, bContent);
00455             ckvpInto->setValue(strConfigDetailName, bContent);
00456           } break;
00457           
00458           case libconfig::Setting::TypeGroup: {
00459             CKeyValuePair* ckvpChild = ckvpInto->addChild(strConfigDetailName);
00460             libconfig::Setting& sBranchChild = sBranch[strConfigDetailName];
00461             
00462             if(this->loadIndividualPluginConfigurationBranch(sBranchChild, ckvpChild, strConfigPath + (strConfigPath == "" ? "" : "/") + strConfigDetailName) == false) {
00463               return false;
00464             }
00465           } break;
00466             
00467           case libconfig::Setting::TypeArray: {
00468             CKeyValuePair* ckvpChild = ckvpInto->addChild(strConfigDetailName);
00469             libconfig::Setting& sBranchChild = sBranch[strConfigDetailName];
00470             
00471             if(this->loadIndividualPluginConfigurationBranch(sBranchChild, ckvpChild, strConfigPath + (strConfigPath == "" ? "" : "/") + strConfigDetailName) == false) {
00472               return false;
00473             }
00474           } break;
00475           }
00476         }
00477       }
00478     }
00479     
00480     return true;
00481   }
00482   
00483   bool Beliefstate::spreadEvent(Event evEvent) {
00484     if(m_psPlugins->spreadEvent(evEvent) == 0) {
00485       ConfigSettings cfgSet = configSettings();
00486       if(cfgSet.bDisplayUnhandledEvents) {
00487         this->warn("Unhandled event dropped: '" + evEvent.strEventName + "'");
00488         
00489         if(evEvent.cdDesignator) {
00490           //this->warn("Content was:");
00491           //evEvent.cdDesignator->printDesignator();
00492         }
00493       }
00494       
00495       if(!this->handleUnhandledEvent(evEvent)) {
00496         if(!evEvent.bPreempt) {
00497           //m_lstGlobalEvents.push_back(evEvent);
00498         }
00499       }
00500       
00501       return false; // Event was not received
00502     }
00503     
00504     return true; // Event was received by some entity (e.g. plugin)
00505   }
00506   
00507   void Beliefstate::spreadServiceEvent(ServiceEvent seServiceEvent) {
00508     if(m_psPlugins->spreadServiceEvent(seServiceEvent) == 0) {
00509       // The service event wasn't handled (i.e. there was no valid
00510       // receiver for it).
00511       ConfigSettings cfgSet = configSettings();
00512       
00513       if(cfgSet.bDisplayUnhandledServiceEvents) {
00514         this->warn("Unhandled service event ('" + seServiceEvent.strServiceName + "') dropped.");
00515         
00516         if(seServiceEvent.cdDesignator) {
00517           //this->warn("Content was:");
00518           //seServiceEvent.cdDesignator->printDesignator();
00519         }
00520       }
00521       
00522       // Send back an answer to the initial caller, stating that there
00523       // was no response (this will help avoiding deadlocks on plugins
00524       // that actually wait for the reply).
00525       
00526       // TODO(winkler): Implement automatic reply to non-answered
00527       // service event requests.
00528     }
00529   }
00530   
00531   bool Beliefstate::cycle() {
00532     bool bContinue = true;
00533     
00534     if(m_bRun) {
00535       Result resCycle = m_psPlugins->cycle();
00536       
00537       // Forward all status messages collected from the plugins and
00538       // the core into the event system
00539       std::list<StatusMessage> lstCoreMessages = queuedMessages();
00540       for(StatusMessage smCurrent : lstCoreMessages) {
00541         resCycle.lstStatusMessages.push_back(smCurrent);
00542       }
00543       
00544       for(StatusMessage smCurrent : resCycle.lstStatusMessages) {
00545         Event evEvent = defaultEvent("status-message");
00546         evEvent.msgStatusMessage = smCurrent;
00547         evEvent.bPreempt = false;
00548         
00549         if(this->spreadEvent(evEvent)) {
00550           this->setRedirectOutput(true);
00551         }
00552       }
00553       
00554       for(Event evtCurrent : m_lstGlobalEvents) {
00555         resCycle.lstEvents.push_back(evtCurrent);
00556       }
00557       
00558       if(m_lstGlobalEvents.size() > 0) {
00559         m_lstGlobalEvents.clear();
00560       }
00561       
00562       if(resCycle.bSuccess) {
00563         // NOTE(winkler): (Service)Event distribution was done in a
00564         // linear manner before. This was changed, as the incoming
00565         // events in the feeder plugins (for example, ROS) might
00566         // appear in a different order than they are actually
00567         // processed in the message queue. The order in the feeder
00568         // plugins is __CORRECT__. Therefore, all events in them are
00569         // (automatically) equipped with a sequence number. This
00570         // number is evaluated here, distributing (i.e. spreading) the
00571         // next event on the line, starting with the lowest. This
00572         // measure was taken to prevent race conditions, which came up
00573         // due to fast, but ordered messages from outside.
00574         
00575         // While there are events in either list, look for the lowest
00576         // one.
00577         while(resCycle.lstEvents.size() > 0 || resCycle.lstServiceEvents.size() > 0) {
00578           // Identify the next highest (i.e. at the moment lowest)
00579           // sequence number
00580           int nSequenceNumber = 100000; // Dirty: Don't put more than
00581                                         // 100000 msgs in the queue at
00582                                         // the same time, or the
00583                                         // system will deadlock.
00584           
00585           // In Events
00586           for(Event evEvent : resCycle.lstEvents) {
00587             if(evEvent.nSequenceNumber < nSequenceNumber) {
00588               nSequenceNumber = evEvent.nSequenceNumber;
00589             }
00590           }
00591           
00592           // In ServiceEvents
00593           for(ServiceEvent seEvent : resCycle.lstServiceEvents) {
00594             if(seEvent.nSequenceNumber < nSequenceNumber) {
00595               nSequenceNumber = seEvent.nSequenceNumber;
00596             }
00597           }
00598           
00599           // Spread the respective (Service)Event
00600           bool bWasSpread = false;
00601           
00602           for(list<Event>::iterator itEvent = resCycle.lstEvents.begin();
00603               itEvent != resCycle.lstEvents.end(); itEvent++) {
00604             Event evEvent = *itEvent;
00605             
00606             if(evEvent.nSequenceNumber == nSequenceNumber) {
00607               // Distribute the event
00608               this->spreadEvent(evEvent);
00609               
00610               // Clean up
00611               if(evEvent.cdDesignator) {
00612                 delete evEvent.cdDesignator;
00613               }
00614               
00615               resCycle.lstEvents.erase(itEvent);
00616               
00617               nSequenceNumber = evEvent.nSequenceNumber;
00618               bWasSpread = true;
00619               
00620               break;
00621             }
00622           }
00623           
00624           if(!bWasSpread) {
00625             for(list<ServiceEvent>::iterator itEvent = resCycle.lstServiceEvents.begin();
00626                 itEvent != resCycle.lstServiceEvents.end(); itEvent++) {
00627               ServiceEvent seEvent = *itEvent;
00628               
00629               if(seEvent.nSequenceNumber == nSequenceNumber) {
00630                 // Distribute the event
00631                 this->spreadServiceEvent(seEvent);
00632                 
00633                 // Clean up
00634                 if(seEvent.cdDesignator) {
00635                   if(!seEvent.bPreserve) {
00636                     delete seEvent.cdDesignator;
00637                   }
00638                 }
00639                 
00640                 resCycle.lstServiceEvents.erase(itEvent);
00641                 
00642                 nSequenceNumber = seEvent.nSequenceNumber;
00643                 bWasSpread = true;
00644                 
00645                 break;
00646               }
00647             }
00648           }
00649           
00650           if(!bWasSpread) {
00651             // This should __never_ever__ happen. The sequence number
00652             // we found before wasn't found again. This means either
00653             // binary or memory corruption.
00654             this->fail("Sequence number hazard! Restart and possibly recompile.");
00655           }
00656         }
00657         
00658         resetSequenceNumbers();
00659         
00660         // Special events
00661         m_mtxTerminalResize.lock();
00662         bool bTerminalWindowResize = m_bTerminalWindowResize;
00663         m_bTerminalWindowResize = false;
00664         m_mtxTerminalResize.unlock();
00665         
00666         if(bTerminalWindowResize) {
00667           Event evResize = defaultEvent("resize-terminal-window");
00668           this->spreadEvent(evResize);
00669         }
00670       }
00671     } else {
00672       bContinue = false;
00673       
00674       // Last shot for the unhandled messages
00675       std::list<StatusMessage> lstCoreMessages = queuedMessages();
00676       for(StatusMessage smCurrent : lstCoreMessages) {
00677         Event evMessage = defaultEvent("status-message");
00678         evMessage.msgStatusMessage = smCurrent;
00679         
00680         this->handleUnhandledEvent(evMessage);
00681       }
00682       
00683       // Send the shutdown message
00684       m_lstGlobalEvents.push_back(defaultEvent("shutdown"));
00685     }
00686     
00687     return bContinue;
00688   }
00689   
00690   void Beliefstate::triggerShutdown() {
00691     m_bRun = false;
00692   }
00693   
00694   void Beliefstate::triggerTerminalResize() {
00695     m_mtxTerminalResize.lock();
00696     m_bTerminalWindowResize = true;
00697     m_mtxTerminalResize.unlock();
00698   }
00699   
00700   void Beliefstate::setBaseDataDirectory(std::string strBaseDataDirectory) {
00701     ConfigSettings cfgsetCurrent = configSettings();
00702     cfgsetCurrent.strBaseDataDirectory = strBaseDataDirectory;
00703     setConfigSettings(cfgsetCurrent);
00704   }
00705   
00706   std::string Beliefstate::baseDataDirectory() {
00707     ConfigSettings cfgsetCurrent = configSettings();
00708     return cfgsetCurrent.strBaseDataDirectory;
00709   }
00710   
00711   std::string Beliefstate::workspaceDirectory() {
00712     return m_strWorkspaceDirectory;
00713   }
00714   
00715   std::string Beliefstate::homeDirectory() {
00716     std::string strHome = "";
00717     
00718     char* cHome = getenv("HOME");
00719     if(cHome) {
00720       strHome = cHome;
00721     }
00722     
00723     return strHome;
00724   }
00725   
00726   std::string Beliefstate::resolveDirectoryTokens(std::string strSubject) {
00727     // First, make list of things to replace
00728     std::list< std::pair<std::string, bool> > lstTokens;
00729     
00730     size_t pos = 0;
00731     while((pos = strSubject.find("$", pos)) != string::npos) {
00732       size_t offset = 1;
00733       
00734       if(pos < strSubject.size() - 1) {
00735         if(strSubject.at(pos + 1) != ' ') {
00736           std::string strToken = "";
00737           bool bInBrackets = false;
00738           
00739           if(strSubject.at(pos + 1) == '{') {
00740             offset++;
00741             size_t pos_endbracket = strSubject.find("}", pos + 1);
00742             
00743             if(pos_endbracket != string::npos) {
00744               strToken = strSubject.substr(pos + 2, pos_endbracket - (pos + 2));
00745               offset += 1 + pos_endbracket - (pos + 2);
00746               bInBrackets = true;
00747             } else {
00748               // This token is invalid (no ending bracket).
00749             }
00750           } else {
00751             size_t pos_space_or_end = strSubject.find_first_of(" /.~_-\\$", pos + 1);
00752             if(pos_space_or_end == string::npos) {
00753               // The rest of the string is part of the token
00754               strToken = strSubject.substr(pos + 1);
00755               offset += pos + 1;
00756             } else {
00757               // The token is delimited by a space
00758               strToken = strSubject.substr(pos + 1, pos_space_or_end - (pos + 1));
00759               offset += pos_space_or_end - (pos + 1);
00760             }
00761           }
00762           
00763           if(strToken != "") {
00764             lstTokens.push_back(make_pair(strToken, bInBrackets));
00765           }
00766         }
00767       }
00768       
00769       pos += offset;
00770     }
00771     
00772     for(pair<string, bool> prToken : lstTokens) {
00773       std::string strToken = prToken.first;
00774       bool bInBrackets = prToken.second;
00775       std::string strToReplace = (bInBrackets ? "${" + strToken + "}" : "$" + strToken);
00776       std::string strReplacement = this->findTokenReplacement(strToken);
00777       
00778       if(strReplacement == "") {
00779         this->warn("Failed to resolve directory token '" + strToken + "', asserting value \"\".");
00780       }
00781       
00782       this->replaceStringInPlace(strSubject, strToReplace, strReplacement);
00783     }
00784     
00785     return strSubject;
00786   }
00787   
00788   std::string Beliefstate::findTokenReplacement(std::string strToken) {
00789     std::string strReplacement = "";
00790     
00791     if(strToken == "HOME") {
00792       strReplacement = this->homeDirectory();
00793     }
00794     
00795     return strReplacement;
00796   }
00797   
00798   bool Beliefstate::handleUnhandledEvent(Event evEvent) {
00799     if(evEvent.strEventName == "status-message") {
00800       StatusMessage msgStatus = evEvent.msgStatusMessage;
00801       
00802       if(m_bCommandLineOutput) {
00803         this->setRedirectOutput(false);
00804       } else {
00805         this->setRedirectOutput(true);
00806       }
00807       
00808       return true;
00809     }
00810     
00811     return false;
00812   }
00813   
00814   std::string Beliefstate::findPrefixPath(std::string strPathList, std::string strMatchingSuffix, std::string strDelimiter) {
00815     std::string strPathReturn = "";
00816     size_t szLastPos = 0;
00817     size_t szCurrentPos = 0;
00818     
00819     if(strPathList != "") {
00820       while(szLastPos != string::npos) {
00821         szCurrentPos = strPathList.find(strDelimiter, szLastPos + strDelimiter.length());
00822         
00823         if(szCurrentPos != string::npos) {
00824           std::string strPath = strPathList.substr(szLastPos + (szLastPos != 0 ? strDelimiter.length() : 0), szCurrentPos - (szLastPos + (szLastPos == 0 ? 0 : strDelimiter.length())));
00825           
00826           if(strPath.length() >= strMatchingSuffix.length()) {
00827             if(strPath.substr(strPath.length() - strMatchingSuffix.length()) == strMatchingSuffix) {
00828               strPathReturn = this->stripPostfix(strPath, strMatchingSuffix);
00829               break;
00830             }
00831           }
00832         }
00833         
00834         szLastPos = szCurrentPos;
00835       }
00836     }
00837     
00838     return strPathReturn;
00839   }
00840 }


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