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