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