DeploymentComponent.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   tag: Peter Soetens  Thu Jul 3 15:34:40 CEST 2008  DeploymentComponent.cpp
00003 
00004                         DeploymentComponent.cpp -  description
00005                            -------------------
00006     begin                : Thu July 03 2008
00007     copyright            : (C) 2008 Peter Soetens
00008     email                : peter.soetens@fmtc.be
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place,                                    *
00024  *   Suite 330, Boston, MA  02111-1307  USA                                *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 
00029 
00030 #include <rtt/RTT.hpp>
00031 #include "DeploymentComponent.hpp"
00032 #include <rtt/deployment/ComponentLoader.hpp>
00033 #include <rtt/extras/Activities.hpp>
00034 #include <rtt/extras/SequentialActivity.hpp>
00035 #include <rtt/extras/FileDescriptorActivity.hpp>
00036 #include <rtt/marsh/PropertyMarshaller.hpp>
00037 #include <rtt/marsh/PropertyDemarshaller.hpp>
00038 #include <rtt/scripting/Scripting.hpp>
00039 #include <rtt/ConnPolicy.hpp>
00040 #include <rtt/plugin/PluginLoader.hpp>
00041 
00042 # if defined(_POSIX_VERSION)
00043 #   define USE_SIGNALS 1
00044 # endif
00045 
00046 #ifdef USE_SIGNALS
00047 #include <signal.h>
00048 #endif
00049 
00050 #include <boost/algorithm/string.hpp>
00051 #include <rtt/base/OperationCallerBaseInvoker.hpp>
00052 
00053 #include <cstdio>
00054 #include <cstdlib>
00055 
00056 #include "ocl/Component.hpp"
00057 #include <rtt/marsh/PropertyLoader.hpp>
00058 
00059 #undef _POSIX_C_SOURCE
00060 #include <sys/types.h>
00061 #include <iostream>
00062 #include <fstream>
00063 #include <set>
00064 
00065 
00066 
00067 using namespace Orocos;
00068 
00069 namespace OCL
00070 {
00071     using namespace std;
00072     using namespace RTT;
00073     using namespace RTT::marsh;
00074     using namespace RTT::detail;
00075 
00079     static std::set<string> valid_names;
00080 
00081     static int got_signal = -1;
00082 
00083     // Signal code only on Posix:
00084 #if defined(USE_SIGNALS)
00085     // catch ctrl+c signal
00086     void ctrl_c_catcher(int sig)
00087     {
00088         // Ctrl-C received (or any other signal)
00089         got_signal = sig;
00090     }
00091 #endif
00092 
00093 #define ORO_str(s) ORO__str(s)
00094 #define ORO__str(s) #s
00095 
00096     DeploymentComponent::DeploymentComponent(std::string name, std::string siteFile)
00097         : RTT::TaskContext(name, Stopped),
00098           autoUnload("AutoUnload",
00099                      "Stop, cleanup and unload all components loaded by the DeploymentComponent when it is destroyed.",
00100                      true),
00101           validConfig("Valid", false),
00102           sched_RT("ORO_SCHED_RT", ORO_SCHED_RT ),
00103           sched_OTHER("ORO_SCHED_OTHER", ORO_SCHED_OTHER ),
00104           lowest_Priority("LowestPriority", RTT::os::LowestPriority ),
00105           highest_Priority("HighestPriority", RTT::os::HighestPriority ),
00106           target("Target",
00107                  ORO_str(OROCOS_TARGET) ),
00108           nextGroup(0)
00109     {
00110         this->addProperty( "RTT_COMPONENT_PATH", compPath ).doc("Locations to look for components. Use a colon or semi-colon separated list of paths. Defaults to the environment variable with the same name.");
00111         this->addProperty( autoUnload );
00112         this->addAttribute( target );
00113 
00114         this->addAttribute( validConfig );
00115         this->addAttribute( sched_RT );
00116         this->addAttribute( sched_OTHER );
00117         this->addAttribute( lowest_Priority );
00118         this->addAttribute( highest_Priority );
00119 
00120 
00121         this->addOperation("reloadLibrary", &DeploymentComponent::reloadLibrary, this, ClientThread).doc("Reload a new component library into memory.").arg("FilePath", "The absolute file name of the to be reloaded library. Warning: this is a low-level function only to be used during development/testing.");
00122         this->addOperation("loadLibrary", &DeploymentComponent::loadLibrary, this, ClientThread).doc("Load a new library (component, plugin or typekit) into memory.").arg("Name", "The absolute or relative name of the to be loaded library. Warning: this is a low-level function you should only use if import() doesn't work for you.");
00123         this->addOperation("import", &DeploymentComponent::import, this, ClientThread).doc("Import all components, plugins and typekits from a given package or directory in the search path.").arg("Package", "The name absolute or relative name of a directory or package.");
00124         this->addOperation("path", &DeploymentComponent::path, this, ClientThread).doc("Add additional directories to the component search path without importing them.").arg("Paths", "A colon or semi-colon separated list of paths to search for packages.");
00125 
00126         this->addOperation("loadComponent", &DeploymentComponent::loadComponent, this, ClientThread).doc("Load a new component instance from a library.").arg("Name", "The name of the to be created component").arg("Type", "The component type, used to lookup the library.");
00127         // avoid warning about overriding
00128         this->provides()->removeOperation("loadService");
00129         this->addOperation("loadService", &DeploymentComponent::loadService, this, ClientThread).doc("Load a discovered service or plugin in an existing component.").arg("Name", "The name of the component which will receive the service").arg("Service", "The name of the service or plugin.");
00130         this->addOperation("unloadComponent", &DeploymentComponent::unloadComponent, this, ClientThread).doc("Unload a loaded component instance.").arg("Name", "The name of the to be created component");
00131         this->addOperation("displayComponentTypes", &DeploymentComponent::displayComponentTypes, this, ClientThread).doc("Print out a list of all component types this component can create.");
00132         this->addOperation("getComponentTypes", &DeploymentComponent::getComponentTypes, this, ClientThread).doc("return a vector of all component types this component can create.");
00133 
00134         this->addOperation("loadConfiguration", &DeploymentComponent::loadConfiguration, this, ClientThread).doc("Load a new XML configuration from a file (identical to loadComponents).").arg("File", "The file which contains the new configuration.");
00135         this->addOperation("loadConfigurationString", &DeploymentComponent::loadConfigurationString, this, ClientThread).doc("Load a new XML configuration from a string.").arg("Text", "The string which contains the new configuration.");
00136         this->addOperation("clearConfiguration", &DeploymentComponent::clearConfiguration, this, ClientThread).doc("Clear all configuration settings.");
00137 
00138         this->addOperation("loadComponents", &DeploymentComponent::loadComponents, this, ClientThread).doc("Load components listed in an XML configuration file.").arg("File", "The file which contains the new configuration.");
00139         this->addOperation("configureComponents", &DeploymentComponent::configureComponents, this, ClientThread).doc("Apply a loaded configuration to the components and configure() them if AutoConf is set.");
00140         this->addOperation("startComponents", &DeploymentComponent::startComponents, this, ClientThread).doc("Start the components configured for AutoStart.");
00141         this->addOperation("stopComponents", &DeploymentComponent::stopComponents, this, ClientThread).doc("Stop all the configured components (with or without AutoStart).");
00142         this->addOperation("cleanupComponents", &DeploymentComponent::cleanupComponents, this, ClientThread).doc("Cleanup all the configured components (with or without AutoConf).");
00143         this->addOperation("unloadComponents", &DeploymentComponent::unloadComponents, this, ClientThread).doc("Unload all the previously loaded components.");
00144 
00145         this->addOperation("runScript", &DeploymentComponent::runScript, this, ClientThread).doc("Runs a script.").arg("File", "An Orocos program script.");
00146         this->addOperation("kickStart", &DeploymentComponent::kickStart, this, ClientThread).doc("Calls loadComponents, configureComponents and startComponents in a row.").arg("File", "The file which contains the XML configuration to use.");
00147         this->addOperation("kickOutAll", &DeploymentComponent::kickOutAll, this, ClientThread).doc("Calls stopComponents, cleanupComponents and unloadComponents in a row.");
00148 
00149         this->addOperation("kickOutComponent", &DeploymentComponent::kickOutComponent, this, ClientThread).doc("Calls stopComponents, cleanupComponent and unloadComponent in a row.").arg("comp_name", "component name");
00150         this->addOperation("kickOut", &DeploymentComponent::kickOut, this, ClientThread).doc("Calls stopComponents, cleanupComponents and unloadComponents in a row.").arg("File", "The file which contains the name of the components to kickOut (for example, the same used in kickStart).");
00151 
00152         this->addOperation("waitForInterrupt", &DeploymentComponent::waitForInterrupt, this, ClientThread).doc("This operation waits for the SIGINT signal and then returns. This allows you to wait in a script for ^C.");
00153         this->addOperation("waitForSignal", &DeploymentComponent::waitForSignal, this, ClientThread).doc("This operation waits for the signal of the argument and then returns. This allows you to wait in a script for any signal except SIGKILL and SIGSTOP.").arg("signal number","The signal number to wait for.");
00154 
00155 
00156         // Work around compiler ambiguity:
00157         typedef bool(DeploymentComponent::*DCFun)(const std::string&, const std::string&);
00158         DCFun cp = &DeploymentComponent::connectPeers;
00159         this->addOperation("connectPeers", cp, this, ClientThread).doc("Connect two Components known to this Component.").arg("One", "The first component.").arg("Two", "The second component.");
00160         cp = &DeploymentComponent::connectPorts;
00161         this->addOperation("connectPorts", cp, this, ClientThread).doc("DEPRECATED. Connect the Data Ports of two Components known to this Component.").arg("One", "The first component.").arg("Two", "The second component.");
00162         typedef bool(DeploymentComponent::*DC4Fun)(const std::string&, const std::string&,
00163                                                    const std::string&, const std::string&);
00164         DC4Fun cp4 = &DeploymentComponent::connectPorts;
00165         this->addOperation("connectTwoPorts", cp4, this, ClientThread).doc("DEPRECATED. Connect two ports of Components known to this Component.")
00166                 .arg("One", "The first component.")
00167                 .arg("PortOne", "The port name of the first component.")
00168                 .arg("Two", "The second component.")
00169                 .arg("PortTwo", "The port name of the second component.");
00170         this->addOperation("createStream", &DeploymentComponent::createStream, this, ClientThread).doc("DEPRECATED. Creates a stream to or from a port.")
00171                 .arg("component", "The component which owns 'port'.")
00172                 .arg("port", "The port to create a stream from or to.")
00173                 .arg("policy", "The connection policy which serves to describe the stream to be created.");
00174 
00175         // New API:
00176         this->addOperation("connect", &DeploymentComponent::connect, this, ClientThread).doc("Creates a connection between two ports.")
00177                 .arg("portOne", "The first port of the connection. Use a dot-separated-path.")
00178                 .arg("portTwo", "The second port of the connection. Use a dot-separated-path.")
00179                 .arg("policy", "The connection policy which serves to describe the stream to be created. Use 'ConnPolicy()' to use the default.");
00180         this->addOperation("stream", &DeploymentComponent::stream, this, ClientThread).doc("Creates a stream to or from a port.")
00181                 .arg("port", "The port to create a stream from or to. Use a dot-separated-path.")
00182                 .arg("policy", "The connection policy which serves to describe the stream to be created. Use 'ConnPolicy()' to use the default.");
00183 
00184         this->addOperation("connectServices", (bool(DeploymentComponent::*)(const std::string&, const std::string&))&DeploymentComponent::connectServices, this, ClientThread).doc("Connect the matching provides/requires services of two Components known to this Component.").arg("One", "The first component.").arg("Two", "The second component.");
00185         this->addOperation("connectOperations", &DeploymentComponent::connectOperations, this, ClientThread).doc("Connect the matching provides/requires operations of two Components known to this Component.").arg("Requested", "The requested operation (dot-separated path).").arg("Provided", "The provided operation (dot-separated path).");
00186 
00187         cp = &DeploymentComponent::addPeer;
00188         this->addOperation("addPeer", cp, this, ClientThread).doc("Add a peer to a Component.").arg("From", "The first component.").arg("To", "The other component.");
00189         this->addOperation("aliasPeer", &DeploymentComponent::aliasPeer, this, ClientThread).doc("Add a peer to a Component with an alternative name.").arg("From", "The component which will see 'To' in its peer list.").arg("To", "The component which will be seen by 'From'.").arg("Alias","The name under which 'To' is known to 'From'");
00190         typedef void(DeploymentComponent::*RPFun)(const std::string&);
00191         RPFun rp = &RTT::TaskContext::removePeer;
00192         this->addOperation("removePeer", rp, this, ClientThread).doc("Remove a peer from this Component.").arg("PeerName", "The name of the peer to remove.");
00193 
00194         this->addOperation("setActivity", &DeploymentComponent::setActivity, this, ClientThread).doc("Attach an activity to a Component.").arg("CompName", "The name of the Component.").arg("Period", "The period of the activity (set to 0.0 for non periodic).").arg("Priority", "The priority of the activity.").arg("SchedType", "The scheduler type of the activity.");
00195         this->addOperation("setActivityOnCPU", &DeploymentComponent::setActivityOnCPU, this, ClientThread).doc("Attach an activity to a Component.").arg("CompName", "The name of the Component.").arg("Period", "The period of the activity (set to 0.0 for non periodic).").arg("Priority", "The priority of the activity.").arg("SchedType", "The scheduler type of the activity.").arg("CPU","The CPU to run on, starting from zero.");
00196         this->addOperation("setPeriodicActivity", &DeploymentComponent::setPeriodicActivity, this, ClientThread).doc("Attach a periodic activity to a Component.").arg("CompName", "The name of the Component.").arg("Period", "The period of the activity.").arg("Priority", "The priority of the activity.").arg("SchedType", "The scheduler type of the activity.");
00197         this->addOperation("setSequentialActivity", &DeploymentComponent::setSequentialActivity, this, ClientThread).doc("Attach a 'stand alone' sequential activity to a Component.").arg("CompName", "The name of the Component.");
00198         this->addOperation("setSlaveActivity", &DeploymentComponent::setSlaveActivity, this, ClientThread).doc("Attach a 'stand alone' slave activity to a Component.").arg("CompName", "The name of the Component.").arg("Period", "The period of the activity (set to zero for non periodic).");
00199         this->addOperation("setMasterSlaveActivity", &DeploymentComponent::setMasterSlaveActivity, this, ClientThread).doc("Attach a slave activity with a master to a Component. The slave becomes a peer of the master as well.").arg("Master", "The name of the Component which is master of the Slave.").arg("Slave", "The name of the Component which gets the SlaveActivity.");
00200                 this->addOperation("setFileDescriptorActivity", &DeploymentComponent::setFileDescriptorActivity, this, ClientThread)
00201                         .doc("Attach a File Descriptor activity to a Component.")
00202                         .arg("CompName", "The name of the Component.")
00203                         .arg("Timeout", "The timeout of the activity (set to zero for no timeout).")
00204                         .arg("Priority", "The priority of the activity.")
00205                         .arg("SchedType", "The scheduler type of the activity.");
00206 
00207         valid_names.insert("AutoUnload");
00208         valid_names.insert("UseNamingService");
00209         valid_names.insert("Server");
00210         valid_names.insert("AutoConf");
00211         valid_names.insert("AutoStart");
00212         valid_names.insert("AutoConnect");
00213         valid_names.insert("AutoSave");
00214         valid_names.insert("PropertyFile");
00215         valid_names.insert("UpdateProperties");
00216         valid_names.insert("LoadProperties");
00217         valid_names.insert("ProgramScript");
00218         valid_names.insert("StateMachineScript");
00219         valid_names.insert("Ports");
00220         valid_names.insert("Peers");
00221         valid_names.insert("Activity");
00222         valid_names.insert("Master");
00223         valid_names.insert("Properties");
00224         valid_names.insert("Service");
00225         valid_names.insert("Plugin"); // equivalent to Service.
00226         valid_names.insert("Provides"); // equivalent to Service.
00227         valid_names.insert("RunScript"); // runs a program script in a component.
00228 
00229         // Check for 'Deployer-site.cpf' XML file.
00230         if (siteFile.empty())
00231             siteFile = this->getName() + "-site.cpf";
00232         std::ifstream hassite(siteFile.c_str());
00233         if ( !hassite ) {
00234             // if not, just configure
00235             this->configure();
00236 
00237             // Backwards compatibility with < 2.3: import OCL by default
00238             log(Info) << "No site file was found. Importing 'ocl' by default." <<endlog();
00239             try {
00240                 import("ocl");
00241             } catch (std::exception& e) {
00242                 // ignore errors.
00243             }
00244             return;
00245         }
00246 
00247         // OK: kick-start it. Need to do import("ocl") and set AutoConf to configure self.
00248         log(Info) << "Using site file '" << siteFile << "'." << endlog();
00249         this->kickStart( siteFile );
00250 
00251     }
00252 
00253     bool DeploymentComponent::configureHook()
00254     {
00255         Logger::In in("DeploymentComponent::configure");
00256         if (compPath.empty() )
00257         {
00258             compPath = ComponentLoader::Instance()->getComponentPath();
00259         } else {
00260             log(Info) <<"RTT_COMPONENT_PATH was set to " << compPath << endlog();
00261             log(Info) <<"Re-scanning for plugins and components..."<<endlog();
00262             PluginLoader::Instance()->setPluginPath(compPath);
00263             ComponentLoader::Instance()->setComponentPath(compPath);
00264             ComponentLoader::Instance()->import(compPath);
00265         }
00266         return true;
00267     }
00268 
00269     bool DeploymentComponent::componentLoaded(RTT::TaskContext* c) { return true; }
00270 
00271     void DeploymentComponent::componentUnloaded(TaskContext* c) { }
00272 
00273     DeploymentComponent::~DeploymentComponent()
00274     {
00275       // Should we unload all loaded components here ?
00276       if ( autoUnload.get() ) {
00277           kickOutAll();
00278       }
00279       ComponentLoader::Release();
00280     }
00281 
00282     bool DeploymentComponent::waitForInterrupt() {
00283         if ( !waitForSignal(SIGINT) )
00284                 return false;
00285         cout << "DeploymentComponent: Got interrupt !" <<endl;
00286         return true;
00287     }
00288 
00289     bool DeploymentComponent::waitForSignal(int sig) {
00290 #ifdef USE_SIGNALS
00291         struct sigaction sa, sold;
00292         sa.sa_handler = ctrl_c_catcher;
00293         if ( ::sigaction(sig, &sa, &sold) != 0) {
00294                 cout << "DeploymentComponent: Failed to install signal handler for signal " << sig << endl;
00295                 return false;
00296         }
00297         while (got_signal != sig) {
00298                 TIME_SPEC ts;
00299                 ts.tv_sec = 1;
00300                 ts.tv_nsec = 0;
00301                 rtos_nanosleep(&ts, 0);
00302         }
00303         got_signal = -1;
00304         // reinstall previous handler if present.
00305         if (sold.sa_handler || sold.sa_sigaction)
00306                 ::sigaction(sig, &sold, NULL);
00307         return true;
00308 #else
00309                 cout << "DeploymentComponent: Failed to install signal handler for signal " << sig << ": Not supported by this Operating System. "<<endl;
00310                 return false;
00311 #endif
00312     }
00313 
00314     bool DeploymentComponent::connectPeers(const std::string& one, const std::string& other)
00315     {
00316         RTT::Logger::In in("DeploymentComponent::connectPeers");
00317         RTT::TaskContext* t1 = one == this->getName() ? this : this->getPeer(one);
00318         RTT::TaskContext* t2 = other == this->getName() ? this : this->getPeer(other);
00319         if (!t1) {
00320             log(Error)<< "No such peer: "<<one<<endlog();
00321             return false;
00322         }
00323         if (!t2) {
00324             log(Error) << "No such peer: "<<other<<endlog();
00325             return false;
00326         }
00327         return t1->connectPeers(t2);
00328     }
00329 
00330     bool DeploymentComponent::addPeer(const std::string& from, const std::string& to)
00331     {
00332         RTT::Logger::In in("DeploymentComponent::addPeer");
00333         RTT::TaskContext* t1 = from == this->getName() ? this : this->getPeer(from);
00334         RTT::TaskContext* t2 = to == this->getName() ? this : this->getPeer(to);
00335         if (!t1) {
00336             log(Error)<< "No such peer: "<<from<<endlog();
00337             return false;
00338         }
00339         if (!t2) {
00340             log(Error)<< "No such peer: "<<to<<endlog();
00341             return false;
00342         }
00343         return t1->addPeer(t2);
00344     }
00345 
00346     bool DeploymentComponent::aliasPeer(const std::string& from, const std::string& to, const std::string& alias)
00347     {
00348         RTT::Logger::In in("DeploymentComponent::addPeer");
00349         RTT::TaskContext* t1 = from == this->getName() ? this : this->getPeer(from);
00350         RTT::TaskContext* t2 = to == this->getName() ? this : this->getPeer(to);
00351         if (!t1) {
00352             log(Error)<< "No such peer known to deployer '"<< this->getName()<< "': "<<from<<endlog();
00353             return false;
00354         }
00355         if (!t2) {
00356             log(Error)<< "No such peer known to deployer '"<< this->getName()<< "': "<<to<<endlog();
00357             return false;
00358         }
00359         return t1->addPeer(t2, alias);
00360     }
00361 
00362     Service::shared_ptr DeploymentComponent::stringToService(string const& names) {
00363         std::vector<std::string> strs;
00364         boost::split(strs, names, boost::is_any_of("."));
00365 
00366       // strs could be empty because of a bug in Boost 1.44 (see https://svn.boost.org/trac/boost/ticket/4751)
00367       if (strs.empty()) return Service::shared_ptr();
00368 
00369         string component = strs.front();
00370         if (!hasPeer(component) && component != this->getName() ) {
00371                 log(Error) << "No such component: '"<< component <<"'" <<endlog();
00372                 if ( names.find('.') != string::npos )
00373                         log(Error)<< " when looking for service '" << names <<"'" <<endlog();
00374                 return Service::shared_ptr();
00375         }
00376         // component is peer or self:
00377         Service::shared_ptr ret = (component != this->getName() ? getPeer(component)->provides() : this->provides());
00378 
00379         // remove component name:
00380         strs.erase( strs.begin() );
00381 
00382         // iterate over remainders:
00383         while ( !strs.empty() && ret) {
00384                 ret = ret->getService( strs.front() );
00385                 if (ret)
00386                         strs.erase( strs.begin() );
00387         }
00388         if (!ret) {
00389                 log(Error) <<"No such service: '"<< strs.front() <<"' while looking for service '"<< names<<"'"<<endlog();
00390         }
00391         return ret;
00392     }
00393 
00394     ServiceRequester* DeploymentComponent::stringToServiceRequester(string const& names) {
00395         std::vector<std::string> strs;
00396         boost::split(strs, names, boost::is_any_of("."));
00397 
00398         string component = strs.front();
00399         if (!hasPeer(component) && component != this->getName() ) {
00400             log(Error) << "No such component: '"<< component <<"'" <<endlog();
00401             if ( names.find('.') != string::npos )
00402                 log(Error)<< " when looking for service '" << names <<"'" <<endlog();
00403             return NULL;
00404         }
00405         // component is peer or self:
00406         ServiceRequester* ret = (component != this->getName() ? getPeer(component)->requires() : this->requires());
00407 
00408         // remove component name:
00409         strs.erase( strs.begin() );
00410 
00411         // iterate over remainders:
00412         while ( !strs.empty() && ret) {
00413             ret = ret->requires( strs.front() );
00414             if (ret)
00415                 strs.erase( strs.begin() );
00416         }
00417         if (!ret) {
00418             log(Error) <<"No such service: '"<< strs.front() <<"' while looking for service '"<< names<<"'"<<endlog();
00419         }
00420         return ret;
00421     }
00422 
00423     base::PortInterface* DeploymentComponent::stringToPort(string const& names) {
00424         std::vector<std::string> strs;
00425         boost::split(strs, names, boost::is_any_of("."));
00426 
00427       // strs could be empty because of a bug in Boost 1.44 (see https://svn.boost.org/trac/boost/ticket/4751)
00428       if (strs.empty()) return 0;
00429 
00430         string component = strs.front();
00431         if (!hasPeer(component) && component != this->getName() ) {
00432                 log(Error) << "No such component: '"<< component <<"'" ;
00433                 log(Error)<< " when looking for port '" << names <<"'" <<endlog();
00434                 return 0;
00435         }
00436         // component is peer or self:
00437         Service::shared_ptr serv = (component != this->getName() ? getPeer(component)->provides() : this->provides());
00438         base::PortInterface* ret = 0;
00439 
00440         // remove component name:
00441         strs.erase( strs.begin() );
00442 
00443         // iterate over remainders:
00444         while ( strs.size() != 1 && serv) {
00445                 serv = serv->getService( strs.front() );
00446                 if (serv)
00447                         strs.erase( strs.begin() );
00448         }
00449         if (!serv) {
00450                 log(Error) <<"No such service: '"<< strs.front() <<"' while looking for port '"<< names<<"'"<<endlog();
00451                 return 0;
00452         }
00453         ret = serv->getPort(strs.front());
00454         if (!ret) {
00455                 log(Error) <<"No such port: '"<< strs.front() <<"' while looking for port '"<< names<<"'"<<endlog();
00456         }
00457 
00458         return ret;
00459     }
00460 
00461     bool DeploymentComponent::connectPorts(const std::string& one, const std::string& other)
00462     {
00463         RTT::Logger::In in("DeploymentComponent::connectPorts");
00464         RTT::TaskContext* a, *b;
00465         a = getPeer(one);
00466         b = getPeer(other);
00467         if ( !a ) {
00468             log(Error) << one <<" could not be found."<< endlog();
00469             return false;
00470         }
00471         if ( !b ) {
00472             log(Error) << other <<" could not be found."<< endlog();
00473             return false;
00474         }
00475 
00476         return a->connectPorts(b);
00477     }
00478 
00479     bool DeploymentComponent::connectPorts(const std::string& one, const std::string& one_port,
00480                                            const std::string& other, const std::string& other_port)
00481     {
00482         RTT::Logger::In in("DeploymentComponent::connectPorts");
00483                 Service::shared_ptr a,b;
00484                 a = stringToService(one);
00485                 b = stringToService(other);
00486                 if (!a || !b)
00487                         return false;
00488         base::PortInterface* ap, *bp;
00489         ap = a->getPort(one_port);
00490         bp = b->getPort(other_port);
00491         if ( !ap ) {
00492             log(Error) << one <<" does not have a port "<<one_port<< endlog();
00493             return false;
00494         }
00495         if ( !bp ) {
00496             log(Error) << other <<" does not have a port "<<other_port<< endlog();
00497             return false;
00498         }
00499 
00500         // Warn about already connected ports.
00501         if ( ap->connected() && bp->connected() ) {
00502             log(Debug) << "Port '"<< ap->getName() << "' of Component '"<<a->getName()
00503                        << "' and port '"<< bp->getName() << "' of Component '"<<b->getName()
00504                        << "' are already connected but (probably) not to each other. Connecting them anyway."<<endlog();
00505         }
00506 
00507         // use the base::PortInterface implementation
00508         if ( ap->connectTo( bp ) ) {
00509             // all went fine.
00510             log(Info)<< "Connected Port " << one +"." + one_port << " to  "<< other +"." + other_port <<"." << endlog();
00511             return true;
00512         } else {
00513             log(Error)<< "Failed to connect Port " << one +"." + one_port << " to  "<< other +"." + other_port <<"." << endlog();
00514             return true;
00515         }
00516     }
00517 
00518     bool DeploymentComponent::createStream(const std::string& comp, const std::string& port, ConnPolicy policy)
00519     {
00520         Service::shared_ptr serv = stringToService(comp);
00521         if ( !serv )
00522             return false;
00523         PortInterface* porti = serv->getPort(port);
00524         if ( !porti ) {
00525             log(Error) <<"Service in component "<<comp<<" has no port "<< port << "."<< endlog();
00526             return false;
00527         }
00528         return porti->createStream( policy );
00529     }
00530 
00531     // New API:
00532     bool DeploymentComponent::connect(const std::string& one, const std::string& other, ConnPolicy cp)
00533     {
00534         RTT::Logger::In in("DeploymentComponent::connect");
00535                 base::PortInterface* ap, *bp;
00536                 ap = stringToPort(one);
00537                 bp = stringToPort(other);
00538                 if (!ap || !bp)
00539                         return false;
00540 
00541         // Warn about already connected ports.
00542         if ( ap->connected() && bp->connected() ) {
00543             log(Debug) << "Port '"<< ap->getName() << "' of '"<< one
00544                        << "' and port '"<< bp->getName() << "' of '"<< other
00545                        << "' are already connected but (probably) not to each other. Connecting them anyway."<<endlog();
00546         }
00547 
00548         // use the base::PortInterface implementation
00549         if ( ap->connectTo( bp, cp ) ) {
00550             // all went fine.
00551             log(Info)<< "Connected Port " << one << " to  "<< other <<"." << endlog();
00552             return true;
00553         } else {
00554             log(Error)<< "Failed to connect Port " << one << " to  "<< other <<"." << endlog();
00555             return false;
00556         }
00557     }
00558 
00559     bool DeploymentComponent::stream(const std::string& port, ConnPolicy policy)
00560     {
00561         base::PortInterface* porti = stringToPort(port);
00562         if ( !porti ) {
00563             return false;
00564         }
00565         return porti->createStream( policy );
00566     }
00567 
00568     bool DeploymentComponent::connectServices(const std::string& one, const std::string& other)
00569     {
00570     RTT::Logger::In in("DeploymentComponent::connectServices");
00571         RTT::TaskContext* a, *b;
00572         a = getPeer(one);
00573         b = getPeer(other);
00574         if ( !a ) {
00575             log(Error) << one <<" could not be found."<< endlog();
00576             return false;
00577         }
00578         if ( !b ) {
00579             log(Error) << other <<" could not be found."<< endlog();
00580             return false;
00581         }
00582 
00583         return a->connectServices(b);
00584     }
00585 
00586     bool DeploymentComponent::connectOperations(const std::string& required, const std::string& provided)
00587     {
00588         RTT::Logger::In in("DeploymentComponent::connectOperations");
00589         // Required service
00590         boost::iterator_range<std::string::const_iterator> reqs = boost::algorithm::find_last(required, ".");
00591         std::string reqs_name(required.begin(), reqs.begin());
00592         std::string rop_name(reqs.begin()+1, required.end());
00593         log(Debug) << "Looking for required operation " << rop_name << " in service " << reqs_name << endlog();
00594         ServiceRequester* r = this->stringToServiceRequester(reqs_name);
00595         // Provided service
00596         boost::iterator_range<std::string::const_iterator> pros = boost::algorithm::find_last(provided, ".");
00597         std::string pros_name(provided.begin(), pros.begin());
00598         std::string pop_name(pros.begin()+1, provided.end());
00599         log(Debug) << "Looking for provided operation " << pop_name << " in service " << pros_name << endlog();
00600         Service::shared_ptr p = this->stringToService(pros_name);
00601         // Requested operation
00602         RTT::base::OperationCallerBaseInvoker* rop = r->getOperationCaller(rop_name);
00603         if (! rop) {
00604             log(Error) << "No requested operation " << rop_name << " found in service " << reqs_name << endlog();
00605             return false;
00606         }
00607         if ( rop->ready() ) {
00608             log(Error) << "Requested operation " << rop_name << " already connected to a provided operation!" << endlog();
00609             return false;
00610         }
00611         // Provided operation
00612         if (! p->hasOperation(pop_name)) {
00613             log(Error) << "No provided operation " << pop_name << " found in service " << pros_name << endlog();
00614             return false;
00615         }
00616         // Connection
00617         rop->setImplementation(p->getLocalOperation( pop_name ), r->getServiceOwner()->engine());
00618         if ( rop->ready() )
00619             log(Debug) << "Successfully set up OperationCaller for operation " << rop_name << endlog();
00620         return rop->ready();
00621     }
00622 
00623     int string_to_oro_sched(const std::string& sched) {
00624         if ( sched == "ORO_SCHED_OTHER" )
00625             return ORO_SCHED_OTHER;
00626         if (sched == "ORO_SCHED_RT" )
00627             return ORO_SCHED_RT;
00628         log(Error)<<"Unknown scheduler type: "<< sched <<endlog();
00629         return -1;
00630     }
00631 
00632     bool DeploymentComponent::loadConfigurationString(const std::string& text)
00633     {
00634         const char* tmpfile = ".loadConfigurationString.cpf";
00635         std::ofstream file( tmpfile );
00636         file << text.c_str();
00637         file.close();
00638         return this->loadConfiguration( tmpfile );
00639     }
00640 
00641     bool DeploymentComponent::runScript(const std::string& file_name)
00642     {
00643         return this->getProvider<Scripting>("scripting")->runScript( file_name );
00644     }
00645 
00646     bool DeploymentComponent::kickStart(const std::string& configurationfile)
00647     {
00648         int thisGroup = nextGroup;
00649         ++nextGroup;    // whether succeed or fail
00650         if ( this->loadComponentsInGroup(configurationfile, thisGroup) ) {
00651             if (this->configureComponentsGroup(thisGroup) ) {
00652                 if ( this->startComponentsGroup(thisGroup) ) {
00653                     log(Info) <<"Successfully loaded, configured and started components from "<< configurationfile <<endlog();
00654                     return true;
00655                 } else {
00656                     log(Error) <<"Failed to start a component: aborting kick-start."<<endlog();
00657                 }
00658             } else {
00659                 log(Error) <<"Failed to configure a component: aborting kick-start."<<endlog();
00660             }
00661         } else {
00662             log(Error) <<"Failed to load a component: aborting kick-start."<<endlog();
00663         }
00664         return false;
00665     }
00666 
00667     bool DeploymentComponent::kickOutAll()
00668     {
00669         bool    ok = true;
00670         while (nextGroup != -1 )
00671         {
00672             ok &= kickOutGroup(nextGroup);
00673             --nextGroup;
00674         }
00675         // reset group counter to zero
00676         nextGroup = 0;
00677         return ok;
00678     }
00679 
00680     bool DeploymentComponent::kickOutGroup(const int group)
00681     {
00682         bool sret = this->stopComponentsGroup(group);
00683         bool cret = this->cleanupComponentsGroup(group);
00684         bool uret = this->unloadComponentsGroup(group);
00685         if ( sret && cret && uret) {
00686             log(Info) << "Kick-out of group " << group << " successful."<<endlog();
00687             return true;
00688         }
00689         // Diagnostics:
00690         log(Critical) << "Kick-out of group " << group << " failed: ";
00691         if (!sret)
00692             log(Critical) << " stopComponents() failed.";
00693         if (!cret)
00694             log(Critical) << " cleanupComponents() failed.";
00695         if (!uret)
00696             log(Critical) << " unloadComponents() failed.";
00697         log(Critical) << endlog();
00698         return false;
00699     }
00700 
00701     bool DeploymentComponent::loadConfiguration(const std::string& configurationfile)
00702     {
00703         return this->loadComponents(configurationfile);
00704     }
00705 
00706     bool DeploymentComponent::loadComponents(const std::string& configurationfile)
00707     {
00708         bool valid = loadComponentsInGroup(configurationfile, nextGroup);
00709         ++nextGroup;
00710         return valid;
00711     }
00712 
00713     bool DeploymentComponent::loadComponentsInGroup(const std::string& configurationfile,
00714                                                     const int group)
00715     {
00716         RTT::Logger::In in("DeploymentComponent::loadComponents");
00717 
00718         RTT::PropertyBag from_file;
00719         log(Info) << "Loading '" <<configurationfile<<"' in group " << group << "."<< endlog();
00720         // demarshalling failures:
00721         bool failure = false;
00722         // semantic failures:
00723         bool valid = validConfig.get();
00724         marsh::PropertyDemarshaller demarshaller(configurationfile);
00725         try {
00726             if ( demarshaller.deserialize( from_file ) )
00727                 {
00728                     valid = true;
00729                     log(Info)<<"Validating new configuration..."<<endlog();
00730                     if ( from_file.empty() ) {
00731                         log(Error)<< "Configuration was empty !" <<endlog();
00732                         valid = false;
00733                     }
00734 
00735                     //for (RTT::PropertyBag::Names::iterator it= nams.begin();it != nams.end();it++) {
00736                     for (RTT::PropertyBag::iterator it= from_file.begin(); it!=from_file.end();it++) {
00737                         // Read in global options.
00738                         if ( (*it)->getName() == "Import" ) {
00739                             RTT::Property<std::string> importp = *it;
00740                             if ( !importp.ready() ) {
00741                                 log(Error)<< "Found 'Import' statement, but it is not of type='string'."<<endlog();
00742                                 valid = false;
00743                                 continue;
00744                             }
00745                             if ( this->import( importp.get() ) == false )
00746                                 valid = false;
00747                             continue;
00748                         }
00749                         if ( (*it)->getName() == "LoadLibrary" ) {
00750                             RTT::Property<std::string> importp = *it;
00751                             if ( !importp.ready() ) {
00752                                 log(Error)<< "Found 'LoadLibrary' statement, but it is not of type='string'."<<endlog();
00753                                 valid = false;
00754                                 continue;
00755                             }
00756                             if ( this->loadLibrary( importp.get() ) == false )
00757                                 valid = false;
00758                             continue;
00759                         }
00760                         if ( (*it)->getName() == "Path" ) {
00761                             RTT::Property<std::string> pathp = *it;
00762                             if ( !pathp.ready() ) {
00763                                 log(Error)<< "Found 'Path' statement, but it is not of type='string'."<<endlog();
00764                                 valid = false;
00765                                 continue;
00766                             }
00767                             this->path( pathp.get() );
00768                             continue;
00769                         }
00770                         if ( (*it)->getName() == "Include" ) {
00771                             RTT::Property<std::string> includep = *it;
00772                             if ( !includep.ready() ) {
00773                                 log(Error)<< "Found 'Include' statement, but it is not of type='string'."<<endlog();
00774                                 valid = false;
00775                                 continue;
00776                             }
00777                             // recursively call this function.
00778                             if ( this->loadComponentsInGroup( includep.get(), group ) == false )
00779                                 valid = false;
00780                             continue;
00781                         }
00782                         // Check if it is a propertybag.
00783                         RTT::Property<RTT::PropertyBag> comp = *it;
00784                         if ( !comp.ready() ) {
00785                             log(Error)<< "RTT::Property '"<< *it <<"' should be a struct, Include, Path or Import statement." << endlog();
00786                             valid = false;
00787                             continue;
00788                         }
00789 
00790                         //Check if it is a ConnPolicy
00791                         // convert to Property<ConnPolicy>
00792                         Property<ConnPolicy> cp_prop((*it)->getName(),"");
00793                         assert( cp_prop.ready() );
00794                         if ( cp_prop.compose( comp ) ) {
00795                             //It's a connection policy.
00796                             conmap[cp_prop.getName()].policy = cp_prop.get();
00797                             log(Debug) << "Saw connection policy " << (*it)->getName() << endlog();
00798                             continue;
00799                         }
00800 
00801                         // Parse the options before creating the component:
00802                         for (RTT::PropertyBag::const_iterator optit= comp.rvalue().begin(); optit != comp.rvalue().end();optit++) {
00803                             if ( valid_names.find( (*optit)->getName() ) == valid_names.end() ) {
00804                                 log(Error) << "Unknown type syntax: '"<< (*optit)->getName() << "' in component struct "<< comp.getName() <<endlog();
00805                                 valid = false;
00806                                 continue;
00807                             }
00808                             if ( (*optit)->getName() == "AutoConnect" ) {
00809                                 RTT::Property<bool> ps = comp.rvalue().getProperty("AutoConnect");
00810                                 if (!ps.ready()) {
00811                                     log(Error) << "AutoConnect must be of type <boolean>" << endlog();
00812                                     valid = false;
00813                                 } else
00814                                     comps[comp.getName()].autoconnect = ps.get();
00815                                 continue;
00816                             }
00817                             if ( (*optit)->getName() == "AutoStart" ) {
00818                                 RTT::Property<bool> ps = comp.rvalue().getProperty("AutoStart");
00819                                 if (!ps.ready()) {
00820                                     log(Error) << "AutoStart must be of type <boolean>" << endlog();
00821                                     valid = false;
00822                                 } else
00823                                     comps[comp.getName()].autostart = ps.get();
00824                                 continue;
00825                             }
00826                             if ( (*optit)->getName() == "AutoSave" ) {
00827                                 RTT::Property<bool> ps = comp.rvalue().getProperty("AutoSave");
00828                                 if (!ps.ready()) {
00829                                     log(Error) << "AutoSave must be of type <boolean>" << endlog();
00830                                     valid = false;
00831                                 } else
00832                                     comps[comp.getName()].autosave = ps.get();
00833                                 continue;
00834                             }
00835                             if ( (*optit)->getName() == "AutoConf" ) {
00836                                 RTT::Property<bool> ps = comp.rvalue().getProperty("AutoConf");
00837                                 if (!ps.ready()) {
00838                                     log(Error) << "AutoConf must be of type <boolean>" << endlog();
00839                                     valid = false;
00840                                 } else
00841                                     comps[comp.getName()].autoconf = ps.get();
00842                                 continue;
00843                             }
00844                             if ( (*optit)->getName() == "Server" ) {
00845                                 RTT::Property<bool> ps = comp.rvalue().getProperty("Server");
00846                                 if (!ps.ready()) {
00847                                     log(Error) << "Server must be of type <boolean>" << endlog();
00848                                     valid = false;
00849                                 } else
00850                                     comps[comp.getName()].server = ps.get();
00851                                 continue;
00852                             }
00853                             if ( (*optit)->getName() == "Service" || (*optit)->getName() == "Plugin"  || (*optit)->getName() == "Provides") {
00854                                 RTT::Property<string> ps = *optit;
00855                                 if (!ps.ready()) {
00856                                     log(Error) << (*optit)->getName() << " must be of type <string>" << endlog();
00857                                     valid = false;
00858                                 } else {
00859                                     comps[comp.getName()].plugins.push_back(ps.value());
00860                                 }
00861                                 continue;
00862                             }
00863                             if ( (*optit)->getName() == "UseNamingService" ) {
00864                                 RTT::Property<bool> ps = comp.rvalue().getProperty("UseNamingService");
00865                                 if (!ps.ready()) {
00866                                     log(Error) << "UseNamingService must be of type <boolean>" << endlog();
00867                                     valid = false;
00868                                 } else
00869                                     comps[comp.getName()].use_naming = ps.get();
00870                                 continue;
00871                             }
00872                             if ( (*optit)->getName() == "PropertyFile" ) {
00873                                 RTT::Property<string> ps = comp.rvalue().getProperty("PropertyFile");
00874                                 if (!ps.ready()) {
00875                                     log(Error) << "PropertyFile must be of type <string>" << endlog();
00876                                     valid = false;
00877                                 } else
00878                                     comps[comp.getName()].configfile = ps.get();
00879                                 continue;
00880                             }
00881                             if ( (*optit)->getName() == "UpdateProperties" ) {
00882                                 RTT::Property<string> ps = comp.rvalue().getProperty("UpdateProperties");
00883                                 if (!ps.ready()) {
00884                                     log(Error) << "UpdateProperties must be of type <string>" << endlog();
00885                                     valid = false;
00886                                 } else
00887                                     comps[comp.getName()].configfile = ps.get();
00888                                 continue;
00889                             }
00890                             if ( (*optit)->getName() == "LoadProperties" ) {
00891                                 RTT::Property<string> ps = comp.rvalue().getProperty("LoadProperties");
00892                                 if (!ps.ready()) {
00893                                     log(Error) << "LoadProperties must be of type <string>" << endlog();
00894                                     valid = false;
00895                                 } else
00896                                     comps[comp.getName()].configfile = ps.get();
00897                                 continue;
00898                             }
00899                             if ( (*optit)->getName() == "Properties" ) {
00900                                 base::PropertyBase* ps = comp.rvalue().getProperty("Properties");
00901                                 if (!ps) {
00902                                     log(Error) << "Properties must be a <struct>" << endlog();
00903                                     valid = false;
00904                                 }
00905                                 continue;
00906                             }
00907                             if ( (*optit)->getName() == "RunScript" ) {
00908                                 base::PropertyBase* ps = comp.rvalue().getProperty("RunScript");
00909                                 if (!ps) {
00910                                     log(Error) << "RunScript must be of type <string>" << endlog();
00911                                     valid = false;
00912                                 }
00913                                 continue;
00914                             }
00915                             if ( (*optit)->getName() == "ProgramScript" ) {
00916                                 log(Warning) << "ProgramScript tag is deprecated. Rename it to 'RunScript'." <<endlog();
00917                                 base::PropertyBase* ps = comp.rvalue().getProperty("ProgramScript");
00918                                 if (!ps) {
00919                                     log(Error) << "ProgramScript must be of type <string>" << endlog();
00920                                     valid = false;
00921                                 }
00922                                 continue;
00923                             }
00924                             if ( (*optit)->getName() == "StateMachineScript" ) {
00925                                 log(Warning) << "StateMachineScript tag is deprecated. Rename it to 'RunScript'." <<endlog();
00926                                 base::PropertyBase* ps = comp.rvalue().getProperty("StateMachineScript");
00927                                 if (!ps) {
00928                                     log(Error) << "StateMachineScript must be of type <string>" << endlog();
00929                                     valid = false;
00930                                 }
00931                                 continue;
00932                             }
00933                         }
00934 
00935                         // Check if we know or are this component.
00936                         RTT::TaskContext* c = 0;
00937                         if ( (*it)->getName() == this->getName() )
00938                             c = this;
00939                         else
00940                             c = this->getPeer( (*it)->getName() );
00941                         if ( !c ) {
00942                             // try to load it.
00943                             if (this->loadComponent( (*it)->getName(), comp.rvalue().getType() ) == false) {
00944                                 log(Warning)<< "Could not configure '"<< (*it)->getName() <<"': No such peer."<< endlog();
00945                                 valid = false;
00946                                 continue;
00947                             }
00948                             c = comps[(*it)->getName()].instance;
00949                         } else {
00950                             // If the user added c as a peer (outside of Deployer) store the pointer
00951                             comps[(*it)->getName()].instance = c;
00952                         }
00953 
00954                         assert(c);
00955 
00956                         // load plugins/services:
00957                         vector<string>& services = comps[(*it)->getName()].plugins;
00958                         for (vector<string>::iterator svit = services.begin(); svit != services.end(); ++svit) {
00959                             if ( c->provides()->hasService( *svit ) == false) {
00960                                 PluginLoader::Instance()->loadService(*svit, c);
00961                             }
00962                         }
00963 
00964                         // set PropFile name if present
00965                         if ( comp.value().getProperty("PropFile") )  // PropFile is deprecated
00966                             comp.value().getProperty("PropFile")->setName("PropertyFile");
00967 
00968                         // connect ports 'Ports' tag is optional.
00969                         RTT::Property<RTT::PropertyBag>* ports = comp.value().getPropertyType<PropertyBag>("Ports");
00970                         if ( ports != 0 ) {
00971                             for (RTT::PropertyBag::iterator pit = ports->value().begin(); pit != ports->value().end(); pit++) {
00972                                 Property<string> portcon = *pit;
00973                                 if ( !portcon.ready() ) {
00974                                     log(Error)<< "RTT::Property '"<< (*pit)->getName() <<"' is not of type 'string'." << endlog();
00975                                     valid = false;
00976                                     continue;
00977                                 }
00978                                 base::PortInterface* p = c->ports()->getPort( portcon.getName() );
00979                                 if ( !p ) {
00980                                     log(Error)<< "Component '"<< c->getName() <<"' does not have a Port '"<< portcon.getName()<<"'." << endlog();
00981                                     valid = false;
00982                                 }
00983                                 // store the port
00984                                 if (valid){
00985                                     string conn_name = portcon.value(); // reads field of property
00986                                     bool to_add = true;
00987                                     // go through the vector to avoid duplicate items.
00988                                     // NOTE the sizes conmap[conn_name].ports.size() and conmap[conn_name].owners.size() are supposed to be equal
00989                                     for(unsigned int a=0; a < conmap[conn_name].ports.size(); a++)
00990                                         {
00991                                             if(  conmap[conn_name].ports.at(a) == p && conmap[conn_name].owners.at(a) == c)
00992                                                 {
00993                                                     to_add = false;
00994                                                     continue;
00995                                                 }
00996                                         }
00997 
00998                                     if(to_add)
00999                                         {
01000                                             log(Debug)<<"storing Port: "<<c->getName()<<"."<< portcon.getName();
01001                                             log(Debug)<<" in " << conn_name <<endlog();
01002                                             conmap[conn_name].ports.push_back( p );
01003                                             conmap[conn_name].owners.push_back( c );
01004                                         }
01005                                 }
01006                             }
01007                         }
01008 
01009                         // Setup the connections from this
01010                         // component to the others.
01011                         if ( comp.value().find("Peers") != 0) {
01012                             RTT::Property<RTT::PropertyBag> nm = comp.value().find("Peers");
01013                             if ( !nm.ready() ) {
01014                                 log(Error)<<"RTT::Property 'Peers' must be a 'struct', was type "<< comp.value().find("Peers")->getType() << endlog();
01015                                 valid = false;
01016                             } else {
01017                                 for (RTT::PropertyBag::const_iterator it= nm.rvalue().begin(); it != nm.rvalue().end();it++) {
01018                                     RTT::Property<std::string> pr = *it;
01019                                     if ( !pr.ready() ) {
01020                                         log(Error)<<"RTT::Property 'Peer' does not have type 'string'."<<endlog();
01021                                         valid = false;
01022                                         continue;
01023                                     }
01024                                 }
01025                             }
01026                         }
01027 
01028                         // Read the activity profile if present.
01029                         if ( comp.value().find("Activity") != 0) {
01030                             RTT::Property<RTT::PropertyBag> nm = comp.value().find("Activity");
01031                             if ( !nm.ready() ) {
01032                                 log(Error)<<"RTT::Property 'Activity' must be a 'struct'."<<endlog();
01033                                 valid = false;
01034                             } else {
01035                                 if ( nm.rvalue().getType() == "PeriodicActivity" ) {
01036                                     RTT::Property<double> per = nm.rvalue().getProperty("Period"); // work around RTT 1.0.2 bug.
01037                                     if ( !per.ready() ) {
01038                                         log(Error)<<"Please specify period <double> of PeriodicActivity."<<endlog();
01039                                         valid = false;
01040                                     }
01041                                     RTT::Property<int> prio = nm.rvalue().getProperty("Priority"); // work around RTT 1.0.2 bug
01042                                     if ( !prio.ready() ) {
01043                                         log(Error)<<"Please specify priority <short> of PeriodicActivity."<<endlog();
01044                                         valid = false;
01045                                     }
01046 
01047                                     unsigned cpu_affinity = ~0; // default to all CPUs
01048                                     RTT::Property<unsigned> cpu_affinity_prop = nm.rvalue().getProperty("CpuAffinity");
01049                                     if(cpu_affinity_prop.ready()) {
01050                                         cpu_affinity = cpu_affinity_prop.get();
01051                                     }
01052                                     // else ignore as is optional
01053 
01054                                     RTT::Property<string> sched;
01055                                     if (nm.rvalue().getProperty("Scheduler") )
01056                                         sched = nm.rvalue().getProperty("Scheduler"); // work around RTT 1.0.2 bug
01057                                     int scheduler = ORO_SCHED_RT;
01058                                     if ( sched.ready() ) {
01059                                         scheduler = string_to_oro_sched( sched.get());
01060                                         if (scheduler == -1 )
01061                                             valid = false;
01062                                     }
01063                                     if (valid) {
01064                                         this->setNamedActivity(comp.getName(), nm.rvalue().getType(), per.get(), prio.get(), scheduler, cpu_affinity );
01065                                     }
01066                                 } else
01067                                     if ( nm.rvalue().getType() == "Activity" || nm.rvalue().getType() == "NonPeriodicActivity" ) {
01068                                         RTT::Property<double> per = nm.rvalue().getProperty("Period");
01069                                         if ( !per.ready() ) {
01070                                             per = Property<double>("p","",0.0); // default to 0.0
01071                                         }
01072                                         RTT::Property<int> prio = nm.rvalue().getProperty("Priority");
01073                                         if ( !prio.ready() ) {
01074                                             log(Error)<<"Please specify priority <short> of Activity."<<endlog();
01075                                             valid = false;
01076                                         }
01077 
01078                                         unsigned int cpu_affinity = ~0; // default to all CPUs
01079                                         RTT::Property<unsigned int> cpu_affinity_prop = nm.rvalue().getProperty("CpuAffinity");
01080                                         if(cpu_affinity_prop.ready()) {
01081                                             cpu_affinity = cpu_affinity_prop.get();
01082                                         }
01083                                         // else ignore as is optional
01084 
01085                                         RTT::Property<string> sched = nm.rvalue().getProperty("Scheduler");
01086                                         int scheduler = ORO_SCHED_RT;
01087                                         if ( sched.ready() ) {
01088                                             scheduler = string_to_oro_sched( sched.get());
01089                                             if (scheduler == -1 )
01090                                                 valid = false;
01091                                         }
01092                                         if (valid) {
01093                                             this->setNamedActivity(comp.getName(), nm.rvalue().getType(), per.get(), prio.get(), scheduler, cpu_affinity );
01094                                         }
01095                                     } else
01096                                         if ( nm.rvalue().getType() == "SlaveActivity" ) {
01097                                             double period = 0.0;
01098                                             string master;
01099                                             if ( nm.rvalue().getProperty("Master") ) {
01100                                                 master = nm.rvalue().getPropertyType<string>("Master")->get();
01101                                                 if (valid) {
01102                                                     this->setNamedActivity(comp.getName(), nm.rvalue().getType(), period, 0, 0, master );
01103                                                 }
01104                                             } else {
01105                                                 // No master given.
01106                                                 if ( nm.rvalue().getProperty("Period") )
01107                                                     period = nm.rvalue().getPropertyType<double>("Period")->get();
01108                                                 if (valid) {
01109                                                     this->setNamedActivity(comp.getName(), nm.rvalue().getType(), period, 0, 0 );
01110                                                 }
01111                                             }
01112                                         } else
01113                                             if ( nm.rvalue().getType() == "SequentialActivity" ) {
01114                                                 this->setNamedActivity(comp.getName(), nm.rvalue().getType(), 0, 0, 0 );
01115                                             } else {
01116                                                 log(Error) << "Unknown activity type: " << nm.rvalue().getType()<<endlog();
01117                                                 valid = false;
01118                                             }
01119                             }
01120                         } else {
01121                             // no 'Activity' element, default to Slave:
01122                             //this->setNamedActivity(comp.getName(), "extras::SlaveActivity", 0.0, 0, 0 );
01123                         }
01124                         // put this component in the root config.
01125                         // existing component options are updated, new components are
01126                         // added to the back.
01127                         // great: a hack to allow 'CompName.ior' as property name.
01128                         string delimiter("@!#?<!");
01129                         bool ret = updateProperty( root, from_file, comp.getName(), delimiter );
01130                         if (!ret) {
01131                             log(Error) << "Failed to store deployment properties for component " << comp.getName() <<endlog();
01132                             valid = false;
01133                         }
01134                         else
01135                         {
01136                             log(Info) << "Added component " << (*it)->getName() << " to group " << group << endlog();
01137                             comps[(*it)->getName()].group = group;
01138                         }
01139                     }
01140 
01141                     deletePropertyBag( from_file );
01142                 }
01143             else
01144                 {
01145                     log(Error)<< "Some error occured while parsing "<< configurationfile <<endlog();
01146                     failure = true;
01147                 }
01148         } catch (...)
01149             {
01150                 log(Error)<< "Uncaught exception in loadcomponents() !"<< endlog();
01151                 failure = true;
01152             }
01153         validConfig.set(valid);
01154         return !failure && valid;
01155     }
01156 
01157     bool DeploymentComponent::configureComponents()
01158     {
01159         RTT::Logger::In in("DeploymentComponent::configureComponents");
01160         // do all groups
01161         bool valid = true;
01162         for (int group = nextGroup - 1; group > 0; --group) {
01163             valid &= configureComponentsGroup(group);
01164         }
01165         return valid;
01166     }
01167 
01168     bool DeploymentComponent::configureComponentsGroup(const int group)
01169     {
01170         RTT::Logger::In in("DeploymentComponent::configureComponents");
01171         if ( root.empty() ) {
01172             RTT::Logger::log() << RTT::Logger::Error
01173                           << "No components loaded by DeploymentComponent !" <<endlog();
01174             return false;
01175         }
01176 
01177         bool valid = true;
01178         log(Info) << "Configuring components in group " << group << endlog();
01179 
01180         // Connect peers
01181         for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
01182 
01183             RTT::Property<RTT::PropertyBag> comp = *it;
01184 
01185             // only components in this group
01186             if (group != comps[ comp.getName() ].group) {
01187                 continue;
01188             }
01189 
01190             RTT::TaskContext* peer = comps[ comp.getName() ].instance;
01191             if ( !peer ) {
01192                 log(Error) << "Peer not found: "<< comp.getName() <<endlog();
01193                 valid=false;
01194                 continue;
01195             }
01196 
01197             comps[comp.getName()].instance = peer;
01198 
01199             // Setup the connections from each component to the
01200             // others.
01201             RTT::Property<RTT::PropertyBag> peers = comp.rvalue().find("Peers");
01202             if ( peers.ready() )
01203                 for (RTT::PropertyBag::const_iterator it= peers.rvalue().begin(); it != peers.rvalue().end();it++) {
01204                     RTT::Property<string> nm = (*it);
01205                     if ( nm.ready() )
01206                         {
01207                             this->addPeer( comps[comp.getName()].instance->getName(), nm.value() );
01208                             log(Info) << this->getName() << " connects " <<
01209                                 comps[comp.getName()].instance->getName() << " to "<< nm.value()  << endlog();
01210                         }
01211                     else {
01212                         log(Error) << "Wrong property type in Peers struct. Expected property of type 'string',"
01213                                    << " got type "<< (*it)->getType() <<endlog();
01214                         valid = false;
01215                     }
01216                 }
01217         }
01218 
01219         // Create data port connections:
01220         for(ConMap::iterator it = conmap.begin(); it != conmap.end(); ++it) {
01221             ConnectionData *connection =  &(it->second);
01222             std::string connection_name = it->first;
01223 
01224             if ( connection->ports.size() == 1 ){
01225                 string owner = connection->owners[0]->getName();
01226                 string portname = connection->ports.front()->getName();
01227                 string porttype = dynamic_cast<InputPortInterface*>(connection->ports.front() ) ? "InputPort" : "OutputPort";
01228                 if ( connection->ports.front()->createStream( connection->policy ) == false) {
01229                     log(Warning) << "Creating stream with name "<<connection_name<<" with Port "<<portname<<" from "<< owner << " failed."<< endlog();
01230                 } else {
01231                     log(Info) << "Component "<< owner << "'s " + porttype<< " " + portname << " will stream to "<< connection->policy.name_id << endlog();
01232                 }
01233                 continue;
01234             }
01235             // first find all write ports.
01236             base::PortInterface* writer = 0;
01237             ConnectionData::Ports::iterator p = connection->ports.begin();
01238 
01239             // If one of the ports is connected, use that one as writer to connect to.
01240             vector<OutputPortInterface*> writers;
01241             while (p !=connection->ports.end() ) {
01242                 if ( OutputPortInterface* out = dynamic_cast<base::OutputPortInterface*>( *p ) ) {
01243                     if ( writer ) {
01244                         log(Info) << "Forming multi-output connections with additional OutputPort " << (*p)->getName() << "."<<endlog();
01245                     } else
01246                         writer = *p;
01247                     writers.push_back( out );
01248                     std::string owner = it->second.owners[p - it->second.ports.begin()]->getName();
01249                     log(Info) << "Component "<< owner << "'s OutputPort "<< writer->getName()<< " will write topic "<<it->first<< endlog();
01250                 }
01251                 ++p;
01252             }
01253 
01254             // Inform the user of non-optimal connections:
01255             if ( writer == 0 ) {
01256                 log(Error) << "No OutputPort listed that writes " << it->first << endlog();
01257                 valid = false;
01258                 break;
01259             }
01260 
01261             // connect all ports to writer
01262             p = connection->ports.begin();
01263             vector<OutputPortInterface*>::iterator w = writers.begin();
01264 
01265             while (w != writers.end() ) {
01266                 while (p != connection->ports.end() ) {
01267                     // connect all readers to the list of writers
01268                     if ( dynamic_cast<base::InputPortInterface*>( *p ) )
01269                     {
01270                         string owner = connection->owners[p - connection->ports.begin()]->getName();
01271                         // only try to connect p if it is not in the same connection of writer.
01272                         // OK. p is definately no part of writer's connection. Try to connect and flag errors if it fails.
01273                         if ( (*w)->connectTo( *p, connection->policy ) == false) {
01274                             log(Error) << "Could not subscribe InputPort "<< owner<<"."<< (*p)->getName() << " to topic " << (*w)->getName() <<'/'<< connection_name <<endlog();
01275                             valid = false;
01276                         } else {
01277                             log(Info) << "Subscribed InputPort "<< owner<<"."<< (*p)->getName() <<" to topic " << (*w)->getName() <<'/'<< connection_name <<endlog();
01278                         }
01279                     }
01280                     ++p;
01281                 }
01282                 ++w;
01283                 p = connection->ports.begin();
01284             }
01285         }
01286 
01287         // Autoconnect ports. The port name is the topic name.
01288         for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
01289             RTT::Property<RTT::PropertyBag> comp = *it;
01290             if ( !comp.ready() )
01291                 continue;
01292 
01293             // only components in this group
01294             if (group != comps[ comp.getName() ].group) {
01295                 continue;
01296             }
01297 
01298             RTT::TaskContext* peer = comps[ comp.getName() ].instance;
01299 
01300             // only autoconnect if AutoConnect == 1 and peer has AutoConnect == 1
01301             // There should only be one writer; more than one will lead to undefined behaviour.
01302             // reader<->reader connections will silently fail and be retried once a writer is found.
01303             if ( comps[comp.getName()].autoconnect ) {
01304                 // XXX/TODO This is broken: we should not rely on the peers to implement AutoConnect!
01305                 RTT::TaskContext::PeerList peers = peer->getPeerList();
01306                 for(RTT::TaskContext::PeerList::iterator pit = peers.begin(); pit != peers.end(); ++pit) {
01307                     if ( comps.count( *pit ) && comps[ *pit ].autoconnect ) {
01308                         RTT::TaskContext* other = peer->getPeer( *pit );
01309                         ::RTT::connectPorts( peer, other );
01310                     }
01311                 }
01312             }
01313         }
01314 
01315         // Main configuration
01316         for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
01317 
01318             RTT::Property<RTT::PropertyBag> comp = *it;
01319 
01320             // only components in this group
01321             if (group != comps[ comp.getName() ].group) {
01322                 continue;
01323             }
01324 
01325             RTT::Property<string> dummy;
01326             RTT::TaskContext* peer = comps[ comp.getName() ].instance;
01327 
01328             // do not configure when not stopped.
01329             if ( peer->getTaskState() > Stopped) {
01330                 log(Warning) << "Component "<< peer->getName()<< " doesn't need to be configured (already Running)." <<endlog();
01331                 continue;
01332             }
01333 
01334             // Check for default properties to set.
01335             for (RTT::PropertyBag::const_iterator pf = comp.rvalue().begin(); pf!= comp.rvalue().end(); ++pf) {
01336                 // set PropFile name if present
01337                 if ( (*pf)->getName() == "Properties"){
01338                     RTT::Property<RTT::PropertyBag> props = *pf; // convert to type.
01339                     bool ret = updateProperties( *peer->properties(), props);
01340                     if (!ret) {
01341                         log(Error) << "Failed to configure properties from main configuration file for component "<< comp.getName() <<endlog();
01342                         valid = false;
01343                     } else {
01344                         log(Info) << "Configured Properties of "<< comp.getName() <<" from main configuration file." <<endlog();
01345                     }
01346                 }
01347             }
01348             // Load/update from property files.
01349             for (RTT::PropertyBag::const_iterator pf = comp.rvalue().begin(); pf!= comp.rvalue().end(); ++pf) {
01350                 // set PropFile name if present
01351                 if ( (*pf)->getName() == "PropertyFile" || (*pf)->getName() == "UpdateProperties" || (*pf)->getName() == "LoadProperties"){
01352                     dummy = *pf; // convert to type.
01353                     string filename = dummy.get();
01354                     marsh::PropertyLoader pl(peer);
01355                     bool strict = (*pf)->getName() == "PropertyFile" ? true : false;
01356                     bool load = (*pf)->getName() == "LoadProperties" ? true : false;
01357                     bool ret;
01358                     if (!load)
01359                         ret = pl.configure( filename, strict );
01360                     else
01361                         ret = pl.load(filename);
01362                     if (!ret) {
01363                         log(Error) << "Failed to configure properties for component "<< comp.getName() <<endlog();
01364                         valid = false;
01365                     } else {
01366                         log(Info) << "Configured Properties of "<< comp.getName() << " from "<<filename<<endlog();
01367                         comps[ comp.getName() ].loadedProperties = true;
01368                     }
01369                 }
01370             }
01371 
01372             // Attach activities
01373             if ( comps[comp.getName()].act ) {
01374                 if ( peer->getActivity() ) {
01375                     log(Info) << "Re-setting activity of "<< comp.getName() <<endlog();
01376                 } else {
01377                     log(Info) << "Setting activity of "<< comp.getName() <<endlog();
01378                 }
01379                 peer->setActivity( comps[comp.getName()].act );
01380                 assert( peer->engine()->getActivity() == comps[comp.getName()].act );
01381                 comps[comp.getName()].act = 0; // drops ownership.
01382             }
01383 
01384             // Load scripts in order of appearance
01385             for (RTT::PropertyBag::const_iterator ps = comp.rvalue().begin(); ps!= comp.rvalue().end(); ++ps) {
01386                 RTT::Property<string> script;
01387                 if ( (*ps)->getName() == "RunScript" )
01388                     script = *ps;
01389                 if ( script.ready() ) {
01390                     valid = valid && peer->getProvider<Scripting>("scripting")->runScript( script.get() );
01391                 }
01392                 // deprecated:
01393                 RTT::Property<string> pscript;
01394                 if ( (*ps)->getName() == "ProgramScript" )
01395                     pscript = *ps;
01396                 if ( pscript.ready() ) {
01397                     valid = valid && peer->getProvider<Scripting>("scripting")->loadPrograms( pscript.get() );
01398                 }
01399                 RTT::Property<string> sscript;
01400                 if ( (*ps)->getName() == "StateMachineScript" )
01401                     sscript = *ps;
01402                 if ( sscript.ready() ) {
01403                     valid = valid && peer->getProvider<Scripting>("scripting")->loadStateMachines( sscript.get() );
01404                 }
01405             }
01406 
01407             // AutoConf
01408             if (comps[comp.getName()].autoconf )
01409                 {
01410                     if( !peer->isRunning() )
01411                         {
01412                             OperationCaller<bool(void)> peerconfigure = peer->getOperation("configure");
01413                             if ( peerconfigure() == false)
01414                                 valid = false;
01415                         }
01416                     else
01417                         log(Warning) << "Apparently component "<< peer->getName()<< " don't need to be configured (already Running)." <<endlog();
01418                 }
01419         }
01420 
01421         // Finally, report success/failure (but ignore components that are actually running, as
01422         // they will have been configured/started previously)
01423         if (!valid) {
01424             for ( CompList::iterator cit = comps.begin(); cit != comps.end(); ++cit) {
01425                 ComponentData* cd = &(cit->second);
01426                 if ( group == cd->group && cd->loaded && cd->autoconf &&
01427                      (cd->instance->getTaskState() != TaskCore::Stopped) &&
01428                      (cd->instance->getTaskState() != TaskCore::Running))
01429                     log(Error) << "Failed to configure component "<< cd->instance->getName()
01430                                << ": state is " << cd->instance->getTaskState() <<endlog();
01431             }
01432         } else {
01433             log(Info) << "Configuration successful for group " << group << "." <<endlog();
01434         }
01435 
01436         validConfig.set(valid);
01437         return valid;
01438     }
01439 
01440     bool DeploymentComponent::startComponents()
01441     {
01442         // do all groups
01443         bool valid = true;
01444         for (int group = nextGroup - 1; group > 0; --group) {
01445             valid &= startComponentsGroup(group);
01446         }
01447         return valid;
01448     }
01449 
01450     bool DeploymentComponent::startComponentsGroup(const int group)
01451     {
01452         RTT::Logger::In in("DeploymentComponent::startComponentsGroup");
01453         if (validConfig.get() == false) {
01454             log(Error) << "Not starting components with invalid configuration." <<endlog();
01455             return false;
01456         }
01457         bool valid = true;
01458         for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
01459 
01460             // only components in this group
01461             if (group != comps[ (*it)->getName() ].group) {
01462                 continue;
01463             }
01464 
01465             TaskContext* peer = comps[ (*it)->getName() ].instance;
01466 
01467             // only start if not already running (peer may have been previously
01468             // loaded/configured/started from the site deployer file)
01469             if (peer->isRunning())
01470             {
01471                 continue;
01472             }
01473 
01474             // AutoStart
01475             OperationCaller<bool(void)> peerstart = peer->getOperation("start");
01476             if (comps[(*it)->getName()].autostart )
01477                 if ( !peer || ( !peer->isRunning() && peerstart() == false) )
01478                     valid = false;
01479         }
01480         // Finally, report success/failure:
01481         if (!valid) {
01482             for ( CompList::iterator cit = comps.begin(); cit != comps.end(); ++cit) {
01483                 ComponentData* it = &(cit->second);
01484 
01485                 // only components in this group
01486                 if (group != it->group) {
01487                     continue;
01488                 }
01489 
01490                 if ( it->instance == 0 ) {
01491                     log(Error) << "Failed to start component "<< cit->first << ": not found." << endlog();
01492                     continue;
01493                 }
01494                 if ( it->autostart && it->instance->getTaskState() != base::TaskCore::Running )
01495                     log(Error) << "Failed to start component "<< it->instance->getName() <<endlog();
01496             }
01497         } else {
01498                 log(Info) << "Startup of 'AutoStart' components successful for group " << group << "." <<endlog();
01499         }
01500         return valid;
01501     }
01502 
01503     bool DeploymentComponent::stopComponents()
01504     {
01505         // do all groups
01506         bool valid = true;
01507         for (int group = nextGroup ; group != -1; --group) {
01508             valid &= stopComponentsGroup(group);
01509         }
01510         return valid;
01511     }
01512 
01513     bool DeploymentComponent::stopComponentsGroup(const int group)
01514     {
01515         RTT::Logger::In in("DeploymentComponent::stopComponentsGroup");
01516         log(Info) << "Stopping group " << group << endlog();
01517         bool valid = true;
01518         // 1. Stop all activities, give components chance to cleanup.
01519         for ( CompList::iterator cit = comps.begin(); cit != comps.end(); ++cit) {
01520             ComponentData* it = &(cit->second);
01521             if ( (group == it->group) && it->instance && !it->proxy ) {
01522                 OperationCaller<bool(void)> instancestop = it->instance->getOperation("stop");
01523                 if ( !it->instance->isRunning() ||
01524                      instancestop() ) {
01525                     log(Info) << "Stopped "<< it->instance->getName() <<endlog();
01526                 } else {
01527                     log(Error) << "Could not stop loaded Component "<< it->instance->getName() <<endlog();
01528                     valid = false;
01529                 }
01530             }
01531         }
01532         return valid;
01533     }
01534 
01535     bool DeploymentComponent::cleanupComponents()
01536     {
01537         // do all groups
01538         bool valid = true;
01539         for (int group = nextGroup ; group != -1; --group) {
01540             valid &= cleanupComponentsGroup(group);
01541         }
01542         return valid;
01543     }
01544 
01545     bool DeploymentComponent::cleanupComponentsGroup(const int group)
01546     {
01547         RTT::Logger::In in("DeploymentComponent::cleanupComponentsGroup");
01548         bool valid = true;
01549         log(Info) << "Cleaning up group " << group << endlog();
01550         // 1. Cleanup all activities, give components chance to cleanup.
01551         for ( CompList::iterator cit = comps.begin(); cit != comps.end(); ++cit) {
01552             ComponentData* it = &(cit->second);
01553 
01554             // only components in this group
01555             if (group != it->group) {
01556                 continue;
01557             }
01558 
01559             if (it->instance && !it->proxy) {
01560                 if ( it->instance->getTaskState() <= base::TaskCore::Stopped ) {
01561                     if ( it->autosave && !it->configfile.empty()) {
01562                         if (it->loadedProperties) {
01563                             string file = it->configfile; // get file name
01564                             PropertyLoader pl(it->instance);
01565                             bool ret = pl.save( file, true ); // save all !
01566                             if (!ret) {
01567                                 log(Error) << "Failed to save properties for component "<< it->instance->getName() <<endlog();
01568                                 valid = false;
01569                             } else {
01570                                 log(Info) << "Refusing to save property file that was not loaded for "<< it->instance->getName() <<endlog();
01571                             }
01572                         } else if (it->autosave) {
01573                             log(Error) << "AutoSave set but no property file specified. Specify one using the UpdateProperties simple element."<<endlog();
01574                         }
01575                     } else if (it->autosave) {
01576                         log(Error) << "AutoSave set but no property file specified. Specify one using the UpdateProperties simple element."<<endlog();
01577                     }
01578                     OperationCaller<bool(void)> instancecleanup = it->instance->getOperation("cleanup");
01579                     instancecleanup();
01580                     log(Info) << "Cleaned up "<< it->instance->getName() <<endlog();
01581                 } else {
01582                     log(Error) << "Could not cleanup Component "<< it->instance->getName() << " (not Stopped)"<<endlog();
01583                     valid = false;
01584                 }
01585             }
01586         }
01587         return valid;
01588     }
01589 
01590     bool DeploymentComponent::unloadComponents()
01591     {
01592         // do all groups
01593         bool valid = true;
01594         for (int group = nextGroup ; group != -1; --group) {
01595             valid &= unloadComponentsGroup(group);
01596         }
01597         return valid;
01598     }
01599 
01600     bool DeploymentComponent::unloadComponentsGroup(const int group)
01601     {
01602         log(Info) << "Unloading group " << group << endlog();
01603         // 2. Disconnect and destroy all components in group
01604         bool valid = true;
01605         CompList::iterator cit = comps.begin();
01606         while ( valid && cit != comps.end())
01607             {
01608                 ComponentData* it = &(cit->second);
01609                 if (group == it->group)
01610                 {
01611                     // this call modifies comps
01612                     valid &= this->unloadComponentImpl(cit);
01613                     // so restart search
01614                     cit = comps.begin();
01615                 }
01616                 else
01617                 {
01618                     ++cit;
01619                 }
01620             }
01621 
01622 
01623         return valid;
01624     }
01625 
01626     void DeploymentComponent::clearConfiguration()
01627     {
01628         log(Info) << "Clearing configuration options."<< endlog();
01629         conmap.clear();
01630         deletePropertyBag( root );
01631     }
01632 
01633     bool DeploymentComponent::import(const std::string& package)
01634     {
01635         RTT::Logger::In in("DeploymentComponent::import");
01636         return ComponentLoader::Instance()->import( package, "" ); // search in existing search paths
01637     }
01638 
01639     void DeploymentComponent::path(const std::string& path)
01640     {
01641         RTT::Logger::In in("DeploymentComponent::path");
01642         ComponentLoader::Instance()->setComponentPath( ComponentLoader::Instance()->getComponentPath() + path );
01643         PluginLoader::Instance()->setPluginPath( PluginLoader::Instance()->getPluginPath() + path );
01644     }
01645 
01646     bool DeploymentComponent::loadLibrary(const std::string& name)
01647     {
01648         RTT::Logger::In in("DeploymentComponent::loadLibrary");
01649         return PluginLoader::Instance()->loadLibrary(name) || ComponentLoader::Instance()->loadLibrary(name);
01650     }
01651 
01652     bool DeploymentComponent::reloadLibrary(const std::string& name)
01653     {
01654         RTT::Logger::In in("DeploymentComponent::reloadLibrary");
01655         return ComponentLoader::Instance()->reloadLibrary(name);
01656     }
01657 
01658     bool DeploymentComponent::loadService(const std::string& name, const std::string& type) {
01659         TaskContext* peer = 0;
01660         if (name == getName() )
01661             peer = this;
01662         else if ( (peer = getPeer(name)) == 0) {
01663             log(Error)<<"No such peer: "<< name<< ". Can not load service '"<<type<<"'."<<endlog();
01664             return false;
01665         }
01666         // note: in case the service is not exposed as a 'service' object with the same name,
01667         // we can not detect double loads. So this check is flaky.
01668         if (peer->provides()->hasService(type))
01669             return true;
01670         return PluginLoader::Instance()->loadService(type, peer);
01671     }
01672 
01673     // or type is a shared library or it is a class type.
01674     bool DeploymentComponent::loadComponent(const std::string& name, const std::string& type)
01675     {
01676         RTT::Logger::In in("DeploymentComponent::loadComponent");
01677 
01678         if ( type == "RTT::PropertyBag" )
01679             return false; // It should be present as peer.
01680 
01681         if ( this->getPeer(name) || ( comps.find(name) != comps.end() && comps[name].instance != 0) ) {
01682             log(Error) <<"Failed to load component with name "<<name<<": already present as peer or loaded."<<endlog();
01683             return false;
01684         }
01685 
01686         TaskContext* instance = ComponentLoader::Instance()->loadComponent(name, type);
01687 
01688         if (!instance) {
01689             return false;
01690         }
01691 
01692         // we need to set instance such that componentLoaded can lookup 'instance' in 'comps'
01693         comps[name].instance = instance;
01694 
01695         if (!this->componentLoaded( instance ) ) {
01696             log(Error) << "This deployer type refused to connect to "<< instance->getName() << ": aborting !" << endlog(Error);
01697             comps[name].instance = 0;
01698             ComponentLoader::Instance()->unloadComponent( instance );
01699             return false;
01700         }
01701 
01702         // unlikely that this fails (checked at entry)!
01703         this->addPeer( instance );
01704         log(Info) << "Adding "<< instance->getName() << " as new peer:  OK."<< endlog(Info);
01705 
01706         comps[name].loaded = true;
01707 
01708         return true;
01709     }
01710 
01715     bool DeploymentComponent::unloadComponentImpl( CompList::iterator cit )
01716     {
01717         bool valid = true;
01718         ComponentData* it = &(cit->second);
01719         std::string  name = cit->first;
01720 
01721         if ( it->loaded && it->instance ) {
01722             if ( !it->instance->isRunning() ) {
01723                 if (!it->proxy ) {
01724                     // allow subclasses to do cleanup too.
01725                     componentUnloaded( it->instance );
01726                     log(Debug) << "Disconnecting " <<name <<endlog();
01727                     it->instance->disconnect();
01728                     log(Debug) << "Terminating " <<name <<endlog();
01729                 } else
01730                     log(Debug) << "Removing proxy for " <<name <<endlog();
01731 
01732                 // Lookup and erase port+owner from conmap.
01733                 for( ConMap::iterator cmit = conmap.begin(); cmit != conmap.end(); ++cmit) {
01734                     size_t n = 0;
01735                     while ( n != cmit->second.owners.size() ) {
01736                         if (cmit->second.owners[n] == it->instance ) {
01737                             cmit->second.owners.erase( cmit->second.owners.begin() + n );
01738                             cmit->second.ports.erase( cmit->second.ports.begin() + n );
01739                             n = 0;
01740                         } else
01741                             ++n;
01742                     }
01743                 }
01744                 // Lookup in the property configuration and remove:
01745                 RTT::Property<RTT::PropertyBag>* pcomp = root.getPropertyType<PropertyBag>(name);
01746                 if (pcomp) {
01747                     root.removeProperty(pcomp);
01748                 }
01749 
01750                 // Finally, delete the activity before the TC !
01751                 delete it->act;
01752                 it->act = 0;
01753                 ComponentLoader::Instance()->unloadComponent( it->instance );
01754                 it->instance = 0;
01755                 log(Info) << "Disconnected and destroyed "<< name <<endlog();
01756             } else {
01757                 log(Error) << "Could not unload Component "<< name <<": still running." <<endlog();
01758                 valid=false;
01759             }
01760         }
01761         if (valid) {
01762             // NOTE there is no reason to keep the ComponentData in the vector.
01763             // actually it may cause errors if we try to re-load the Component later.
01764             comps.erase(cit);
01765         }
01766         return valid;
01767     }
01768 
01769     bool DeploymentComponent::unloadComponent(const std::string& name)
01770     {
01771         CompList::iterator it;
01772             // no such peer: try looking for the map name
01773             if ( comps.count( name ) == 0 || comps[name].loaded == false ) {
01774                 log(Error) << "Can't unload component '"<<name<<"': not loaded by "<<this->getName()<<endlog();
01775                 return false;
01776                 }
01777 
01778         // Ok. Go on with loaded component.
01779         it = comps.find(name);
01780 
01781         if ( this->unloadComponentImpl( it ) == false )
01782             return false;
01783 
01784         log(Info) << "Successfully unloaded component "<<name<<"."<<endlog();
01785         return true;
01786     }
01787 
01788     void DeploymentComponent::displayComponentTypes() const
01789     {
01790         FactoryMap::const_iterator it;
01791         cout << "I can create the following component types: " <<endl;
01792         for(it = getFactories().begin(); it != getFactories().end(); ++it) {
01793             cout << "   " << it->first << endl;
01794         }
01795         if ( getFactories().size() == 0 )
01796             cout << "   (none)"<<endl;
01797     }
01798 
01799     std::vector<std::string> DeploymentComponent::getComponentTypes() const
01800     {
01801         std::vector<std::string> s;
01802         FactoryMap::const_iterator it;
01803         for(it = getFactories().begin(); it != getFactories().end(); ++it)
01804             s.push_back(it->first);
01805 
01806         return s;
01807     }
01808 
01809     bool DeploymentComponent::setActivity(const std::string& comp_name,
01810                                           double period, int priority,
01811                                           int scheduler)
01812     {
01813         if ( this->setNamedActivity(comp_name, "Activity", period, priority, scheduler) ) {
01814             assert( comps[comp_name].instance );
01815             assert( comps[comp_name].act );
01816             comps[comp_name].instance->setActivity( comps[comp_name].act );
01817             comps[comp_name].act = 0;
01818             return true;
01819         }
01820         return false;
01821     }
01822 
01823         bool DeploymentComponent::setFileDescriptorActivity(const std::string& comp_name,
01824                                           double timeout, int priority,
01825                                           int scheduler)
01826     {
01827         if ( this->setNamedActivity(comp_name, "FileDescriptorActivity", timeout, priority, scheduler) ) {
01828             assert( comps[comp_name].instance );
01829             assert( comps[comp_name].act );
01830             comps[comp_name].instance->setActivity( comps[comp_name].act );
01831             comps[comp_name].act = 0;
01832             return true;
01833         }
01834         return false;
01835     }
01836         
01837     bool DeploymentComponent::setActivityOnCPU(const std::string& comp_name,
01838                                           double period, int priority,
01839                                                int scheduler, unsigned int cpu_nr)
01840     {
01841         unsigned int mask = 0x1 << cpu_nr;
01842         if ( this->setNamedActivity(comp_name, "Activity", period, priority, scheduler, mask) ) {
01843             assert( comps[comp_name].instance );
01844             assert( comps[comp_name].act );
01845             comps[comp_name].instance->setActivity( comps[comp_name].act );
01846             comps[comp_name].act = 0;
01847             return true;
01848         }
01849         return false;
01850     }
01851 
01852     bool DeploymentComponent::setPeriodicActivity(const std::string& comp_name,
01853                                                   double period, int priority,
01854                                                   int scheduler)
01855     {
01856         if ( this->setNamedActivity(comp_name, "PeriodicActivity", period, priority, scheduler) ) {
01857             assert( comps[comp_name].instance );
01858             assert( comps[comp_name].act );
01859             comps[comp_name].instance->setActivity( comps[comp_name].act );
01860             comps[comp_name].act = 0;
01861             return true;
01862         }
01863         return false;
01864     }
01865 
01866     bool DeploymentComponent::setSlaveActivity(const std::string& comp_name,
01867                                                double period)
01868     {
01869         if ( this->setNamedActivity(comp_name, "SlaveActivity", period, 0, ORO_SCHED_OTHER ) ) {
01870             assert( comps[comp_name].instance );
01871             assert( comps[comp_name].act );
01872             comps[comp_name].instance->setActivity( comps[comp_name].act );
01873             comps[comp_name].act = 0;
01874             return true;
01875         }
01876         return false;
01877     }
01878 
01879     bool DeploymentComponent::setSequentialActivity(const std::string& comp_name)
01880     {
01881         if ( this->setNamedActivity(comp_name, "SequentialActivity", 0, 0, 0 ) ) {
01882             assert( comps[comp_name].instance );
01883             assert( comps[comp_name].act );
01884             comps[comp_name].instance->setActivity( comps[comp_name].act );
01885             comps[comp_name].act = 0;
01886             return true;
01887         }
01888         return false;
01889     }
01890 
01891     bool DeploymentComponent::setMasterSlaveActivity(const std::string& master,
01892                                                    const std::string& slave)
01893     {
01894         if ( this->setNamedActivity(slave, "SlaveActivity", 0, 0, ORO_SCHED_OTHER, master ) ) {
01895             assert( comps[slave].instance );
01896             assert( comps[slave].act );
01897             comps[slave].instance->setActivity( comps[slave].act );
01898             comps[slave].act = 0;
01899             return true;
01900         }
01901         return false;
01902     }
01903 
01904 
01905     bool DeploymentComponent::setNamedActivity(const std::string& comp_name,
01906                                                const std::string& act_type,
01907                                                double period, int priority,
01908                                                int scheduler, const std::string& master_name)
01909     {
01910         return setNamedActivity(comp_name,
01911                                 act_type,
01912                                 period,
01913                                 priority,
01914                                 scheduler,
01915                                 ~0,             // cpu_affinity == all CPUs
01916                                 master_name);
01917     }
01918 
01919     bool DeploymentComponent::setNamedActivity(const std::string& comp_name,
01920                                                const std::string& act_type,
01921                                                double period, int priority,
01922                                                int scheduler, unsigned cpu_affinity,
01923                                                const std::string& master_name)
01924     {
01925         // This helper function does not actualy set the activity, it just creates it and
01926         // stores it in comps[comp_name].act
01927         RTT::TaskContext* peer = 0;
01928         base::ActivityInterface* master_act = 0;
01929         if ( comp_name == this->getName() )
01930             peer = this;
01931         else
01932             if ( comps.count(comp_name) )
01933                 peer = comps[comp_name].instance;
01934             else
01935                 peer = this->getPeer(comp_name); // last resort.
01936         if (!peer) {
01937             log(Error) << "Can't create Activity: component "<<comp_name<<" not found."<<endlog();
01938             return false;
01939         }
01940         if ( !master_name.empty() ) {
01941             if ( master_name == this->getName() )
01942                 master_act = this->engine()->getActivity();
01943             else
01944                 if ( comps.count(master_name) && comps[master_name].act )
01945                     master_act = comps[master_name].act;
01946                 else
01947                     master_act = this->getPeer(master_name) ? getPeer(master_name)->engine()->getActivity() : 0; // last resort.
01948 
01949             if ( !this->getPeer(master_name) ) {
01950                 log(Error) << "Can't create SlaveActivity: Master component "<<master_name<<" not known as peer."<<endlog();
01951                 return false;
01952             }
01953 
01954             if (!master_act) {
01955                 log(Error) << "Can't create SlaveActivity: Master component "<<master_name<<" has no activity set."<<endlog();
01956                 return false;
01957             }
01958         }
01959         // this is required for lateron attaching the engine()
01960         comps[comp_name].instance = peer;
01961         if ( peer->isRunning() ) {
01962             log(Error) << "Can't change activity of component "<<comp_name<<" since it is still running."<<endlog();
01963             return false;
01964         }
01965 
01966         base::ActivityInterface* newact = 0;
01967         // standard case:
01968         if ( act_type == "Activity")
01969             newact = new RTT::Activity(scheduler, priority, period, cpu_affinity, 0, comp_name);
01970         else
01971             // special cases:
01972             if ( act_type == "PeriodicActivity" && period != 0.0)
01973                 newact = new RTT::extras::PeriodicActivity(scheduler, priority, period, cpu_affinity, 0);
01974             else
01975             if ( act_type == "NonPeriodicActivity" && period == 0.0)
01976                 newact = new RTT::Activity(scheduler, priority, period, cpu_affinity, 0);
01977             else
01978                 if ( act_type == "SlaveActivity" ) {
01979                     if ( master_act == 0 )
01980                         newact = new extras::SlaveActivity(period);
01981                     else {
01982                         newact = new extras::SlaveActivity(master_act);
01983                         this->getPeer(master_name)->addPeer( peer );
01984                     }
01985                 }
01986                 else
01987                     if (act_type == "Activity") {
01988                         newact = new Activity(scheduler, priority, period, cpu_affinity, 0, comp_name);
01989                     }
01990                     else
01991                         if (act_type == "SequentialActivity") {
01992                             newact = new SequentialActivity();
01993                         }
01994                         else if ( act_type == "FileDescriptorActivity") {
01995                                 using namespace RTT::extras;
01996                 newact = new FileDescriptorActivity(scheduler, priority, 0);
01997                                 FileDescriptorActivity* fdact = dynamic_cast< RTT::extras::FileDescriptorActivity* > (newact);
01998                                 if (fdact) fdact->setTimeout(period);
01999                                 else newact = 0;
02000                         }
02001         if (newact == 0) {
02002             log(Error) << "Can't create '"<< act_type << "' for component "<<comp_name<<": incorrect arguments."<<endlog();
02003             return false;
02004         }
02005 
02006         // this must never happen if component is running:
02007         assert( peer->isRunning() == false );
02008         delete comps[comp_name].act;
02009         comps[comp_name].act = newact;
02010 
02011         return true;
02012     }
02013 
02014     bool DeploymentComponent::configure(const std::string& name)
02015     {
02016         return configureFromFile( name,  name + ".cpf" );
02017     }
02018 
02019     bool DeploymentComponent::configureFromFile(const std::string& name, const std::string& filename)
02020     {
02021         RTT::Logger::In in("DeploymentComponent");
02022         RTT::TaskContext* c;
02023         if ( name == this->getName() )
02024             c = this;
02025         else
02026             c = this->getPeer(name);
02027         if (!c) {
02028             log(Error)<<"No such peer to configure: "<<name<<endlog();
02029             return false;
02030         }
02031 
02032         marsh::PropertyLoader pl(c);
02033         return pl.configure( filename, true ); // strict:true
02034     }
02035 
02036     const FactoryMap& DeploymentComponent::getFactories() const
02037     {
02038         return RTT::ComponentLoader::Instance()->getFactories();
02039     }
02040 
02041     void DeploymentComponent::kickOut(const std::string& config_file)
02042     {
02043         RTT::Logger::In in("DeploymentComponent::kickOut");
02044         RTT::PropertyBag from_file;
02045         RTT::Property<std::string>  import_file;
02046         std::vector<std::string> deleted_components_type;
02047 
02048         marsh::PropertyDemarshaller demarshaller(config_file);
02049         try {
02050             if ( demarshaller.deserialize( from_file ) ){
02051                 for (RTT::PropertyBag::iterator it= from_file.begin(); it!=from_file.end();it++) {
02052                     if ( (*it)->getName() == "Import" ) continue;
02053                     if ( (*it)->getName() == "Include" ) continue;
02054 
02055                     kickOutComponent(  (*it)->getName() );
02056                 }
02057                 deletePropertyBag( from_file );
02058             }
02059             else {
02060                 log(Error)<< "Some error occured while parsing "<< config_file <<endlog();
02061             }
02062         } catch (...)
02063             {
02064                 log(Error)<< "Uncaught exception in kickOut() !"<< endlog();
02065             }
02066     }
02067 
02068     bool DeploymentComponent::cleanupComponent(RTT::TaskContext *instance)
02069     {
02070         RTT::Logger::In in("DeploymentComponent::cleanupComponent");
02071         bool valid = true;
02072         // 1. Cleanup a single activities, give components chance to cleanup.
02073         if (instance) {
02074             if ( instance->getTaskState() <= base::TaskCore::Stopped ) {
02075                 OperationCaller<bool(void)> instancecleanup = instance->getOperation("cleanup");
02076                 instancecleanup();
02077                 log(Info) << "Cleaned up "<< instance->getName() <<endlog();
02078             } else {
02079                 log(Error) << "Could not cleanup Component "<< instance->getName() << " (not Stopped)"<<endlog();
02080                 valid = false;
02081             }
02082         }
02083         return valid;
02084     }
02085 
02086     bool DeploymentComponent::stopComponent(RTT::TaskContext *instance)
02087     {
02088         RTT::Logger::In in("DeploymentComponent::stopComponent");
02089         bool valid = true;
02090 
02091         if ( instance ) {
02092             OperationCaller<bool(void)> instancestop = instance->getOperation("stop");
02093             if ( !instance->isRunning() ||
02094                  instancestop() ) {
02095                 log(Info) << "Stopped "<< instance->getName() <<endlog();
02096             }
02097             else {
02098                 log(Error) << "Could not stop loaded Component "<< instance->getName() <<endlog();
02099                 valid = false;
02100             }
02101         }
02102         return valid;
02103     }
02104 
02105     bool DeploymentComponent::kickOutComponent(const std::string& comp_name)
02106     {
02107         RTT::Logger::In in("DeploymentComponent::kickOutComponent");
02108 
02109         RTT::TaskContext* peer = comps.count(comp_name) ? comps[ comp_name ].instance : 0;
02110 
02111         if ( !peer ) {
02112             log(Error) << "Component not loaded by this Deployer: "<< comp_name <<endlog();
02113             return false;
02114         }
02115         stopComponent( peer );
02116         cleanupComponent (peer );
02117         unloadComponent( comp_name);
02118 
02119         // also remove from XML if present:
02120         root.removeProperty( root.find( comp_name ) );
02121 
02122         return true;
02123     }
02124 
02125     void DeploymentComponent::shutdownDeployment()
02126     {
02127         static const char*      PEER="Application";
02128         static const char*      NAME="shutdownDeployment";
02129 
02130         // names of override properties
02131         static const char*      WAIT_PROP_NAME="shutdownWait_ms";
02132         static const char*      TOTAL_WAIT_PROP_NAME="shutdownTotalWait_ms";
02133 
02134         // if have operation named NAME in peer PEER then call it
02135         RTT::TaskContext* peer = getPeer(PEER);
02136         if (0 != peer)
02137         {
02138             RTT::OperationCaller<void(void)>    ds =
02139                 peer->getOperation(NAME);
02140             if (ds.ready())
02141             {
02142                 log(Info) << "Shutting down deployment." << endlog();
02143                 RTT::SendHandle<void(void)> handle = ds.send();
02144                 if (handle.ready())
02145                 {
02146                     // set defaults
02147 
02148                     // number milliseconds to wait in between completion checks
02149                     int wait            = 50;
02150                     // total number milliseconds to wait for completion
02151                     int totalWait       = 2000;
02152 
02153                     // any overrides?
02154                     RTT::Property<int> wait_prop =
02155                         this->properties()->getProperty(WAIT_PROP_NAME);
02156                     if (wait_prop.ready())
02157                     {
02158                         int w = wait_prop.rvalue();
02159                         if (0 < w)
02160                         {
02161                             wait = w;
02162                             log(Debug) << "Using override value for " << WAIT_PROP_NAME << endlog();
02163                         }
02164                         else
02165                         {
02166                             log(Warning) << "Ignoring illegal value for " << WAIT_PROP_NAME << endlog();
02167                         }
02168                     }
02169                     else
02170                     {
02171                         log(Debug) << "Using default value for " << WAIT_PROP_NAME << endlog();
02172                     }
02173 
02174                     RTT::Property<int> totalWait_prop =
02175                         this->properties()->getProperty(TOTAL_WAIT_PROP_NAME);
02176                     if (totalWait_prop.ready())
02177                     {
02178                         int w = totalWait_prop.rvalue();
02179                         if (0 < w)
02180                         {
02181                             totalWait = w;
02182                             log(Debug) << "Using override value for " << TOTAL_WAIT_PROP_NAME << endlog();
02183                         }
02184 
02185                         {
02186                             log(Warning) << "Ignoring illegal value for " << TOTAL_WAIT_PROP_NAME << endlog();
02187                         }
02188                     }
02189                     else
02190                     {
02191                         log(Debug) << "Using default value for " << TOTAL_WAIT_PROP_NAME << endlog();
02192                     }
02193 
02194                     // enforce constraints
02195                     if (wait > totalWait)
02196                     {
02197                         wait = totalWait;
02198                         log(Warning) << "Setting wait == totalWait" << endlog();
02199                     }
02200 
02201                     const long int wait_ns = wait * 1000000LL;
02202                     TIME_SPEC ts;
02203                     ts.tv_sec  = wait_ns / 1000000000LL;
02204                     ts.tv_nsec = wait_ns % 1000000000LL;
02205 
02206                     // wait till done or timed out
02207                     log(Debug) << "Waiting for deployment shutdown to complete ..." << endlog();
02208                     int waited = 0;
02209                     while ((RTT::SendNotReady == handle.collectIfDone()) &&
02210                            (waited < totalWait))
02211                     {
02212                         (void)rtos_nanosleep(&ts, NULL);
02213                         waited += wait;
02214                     }
02215                     if (waited >= totalWait)
02216                     {
02217                         log(Error) << "Timed out waiting for deployment shutdown to complete." << endlog();
02218                     }
02219                     else
02220                     {
02221                         log(Debug) << "Deployment shutdown completed." << endlog();
02222                     }
02223                 }
02224                 else
02225                 {
02226                     log(Error) << "Failed to start operation: " << NAME << endlog();
02227                 }
02228 
02229             }
02230             else
02231             {
02232                 log(Info) << "Ignoring missing deployment shutdown function." << endlog();
02233             }
02234         }
02235         else
02236         {
02237             log(Info) << "Ignoring deployment shutdown function due to missing peer." << endlog();
02238         }
02239     }
02240 
02241 }


ocl
Author(s): OCL Development Team
autogenerated on Thu Jan 2 2014 11:38:08