OrocosComponentLibrary
2.7.0
|
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 }