DeploymentComponent.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Thu Jul 3 15:34:40 CEST 2008 DeploymentComponent.cpp
3 
4  DeploymentComponent.cpp - description
5  -------------------
6  begin : Thu July 03 2008
7  copyright : (C) 2008 Peter Soetens
8  email : peter.soetens@fmtc.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU Lesser General Public *
13  * License as published by the Free Software Foundation; either *
14  * version 2.1 of the License, or (at your option) any later version. *
15  * *
16  * This library is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19  * Lesser General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU Lesser General Public *
22  * License along with this library; if not, write to the Free Software *
23  * Foundation, Inc., 59 Temple Place, *
24  * Suite 330, Boston, MA 02111-1307 USA *
25  * *
26  ***************************************************************************/
27 
28 
29 
30 #include <rtt/RTT.hpp>
31 #include "DeploymentComponent.hpp"
39 #include <rtt/ConnPolicy.hpp>
42 
43 # if defined(_POSIX_VERSION)
44 # define USE_SIGNALS 1
45 # endif
46 
47 #ifdef USE_SIGNALS
48 #include <signal.h>
49 #endif
50 
51 #include <boost/algorithm/string.hpp>
53 
54 #include <cstdio>
55 #include <cstdlib>
56 
57 #include "ocl/Component.hpp"
59 
60 #undef _POSIX_C_SOURCE
61 #include <sys/types.h>
62 #include <iostream>
63 #include <fstream>
64 #include <set>
65 
66 
67 
68 using namespace Orocos;
69 
70 namespace OCL
71 {
72  using namespace std;
73  using namespace RTT;
74  using namespace RTT::marsh;
75  using namespace RTT::detail;
76 
80  static std::set<string> valid_names;
81 
82  static int got_signal = -1;
83 
84  // Signal code only on Posix:
85 #if defined(USE_SIGNALS)
86  // catch ctrl+c signal
87  void ctrl_c_catcher(int sig)
88  {
89  // Ctrl-C received (or any other signal)
90  got_signal = sig;
91  }
92 #endif
93 
94 #define ORO_str(s) ORO__str(s)
95 #define ORO__str(s) #s
96 
97  DeploymentComponent::DeploymentComponent(std::string name, std::string siteFile)
98  : RTT::TaskContext(name, Stopped),
99  defaultWaitPeriodPolicy(ORO_WAIT_ABS),
100  autoUnload("AutoUnload",
101  "Stop, cleanup and unload all components loaded by the DeploymentComponent when it is destroyed.",
102  true),
103  validConfig("Valid", false),
104  sched_RT("ORO_SCHED_RT", ORO_SCHED_RT ),
105  sched_OTHER("ORO_SCHED_OTHER", ORO_SCHED_OTHER ),
106  lowest_Priority("LowestPriority", RTT::os::LowestPriority ),
107  highest_Priority("HighestPriority", RTT::os::HighestPriority ),
108  target("Target",
109  ORO_str(OROCOS_TARGET) ),
110  nextGroup(0)
111  {
112  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.");
113  this->addProperty( "DefaultWaitPeriodPolicy", defaultWaitPeriodPolicy ).doc("The default value for the wait period policy property for threads of newly created activities (ORO_WAIT_ABS or ORO_WAIT_REL).");
114  this->addProperty( autoUnload );
115  this->addAttribute( target );
116 
117  this->addAttribute( validConfig );
118  this->addAttribute( sched_RT );
119  this->addAttribute( sched_OTHER );
120  this->addAttribute( lowest_Priority );
122 
123 
124  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.");
125  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.");
126  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.");
127  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.");
128 
129  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.");
130  this->addOperation("configureComponent", (bool (DeploymentComponent::*)(const std::string&))&DeploymentComponent::configureComponent, this, ClientThread).doc("Configure a component who is a peer of this deployer by name.").arg("Name", "The component's name");
131  this->addOperation("startComponent", (bool (DeploymentComponent::*)(const std::string&))&DeploymentComponent::startComponent, this, ClientThread).doc("Start a component who is a peer of this deployer by name.").arg("Name", "The component's name");
132  this->addOperation("stopComponent", (bool (DeploymentComponent::*)(const std::string&))&DeploymentComponent::stopComponent, this, ClientThread).doc("Stop a component who is a peer of this deployer by name.").arg("Name", "The component's name");
133  // avoid warning about overriding
134  this->provides()->removeOperation("loadService");
135  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.");
136  this->addOperation("unloadComponent", &DeploymentComponent::unloadComponent, this, ClientThread).doc("Unload a loaded component instance.").arg("Name", "The name of the to be created component");
137  this->addOperation("displayComponentTypes", &DeploymentComponent::displayComponentTypes, this, ClientThread).doc("Print out a list of all component types this component can create.");
138  this->addOperation("getComponentTypes", &DeploymentComponent::getComponentTypes, this, ClientThread).doc("return a vector of all component types this component can create.");
139 
140  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.");
141  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.");
142  this->addOperation("clearConfiguration", &DeploymentComponent::clearConfiguration, this, ClientThread).doc("Clear all configuration settings.");
143 
144  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.");
145  this->addOperation("configureComponents", &DeploymentComponent::configureComponents, this, ClientThread).doc("Apply a loaded configuration to the components and configure() them if AutoConf is set.");
146  this->addOperation("startComponents", &DeploymentComponent::startComponents, this, ClientThread).doc("Start the components configured for AutoStart.");
147  this->addOperation("stopComponents", &DeploymentComponent::stopComponents, this, ClientThread).doc("Stop all the configured components (with or without AutoStart).");
148  this->addOperation("cleanupComponents", &DeploymentComponent::cleanupComponents, this, ClientThread).doc("Cleanup all the configured components (with or without AutoConf).");
149  this->addOperation("unloadComponents", &DeploymentComponent::unloadComponents, this, ClientThread).doc("Unload all the previously loaded components.");
150 
151  this->addOperation("runScript", &DeploymentComponent::runScript, this, ClientThread).doc("Runs a script.").arg("File", "An Orocos program script.");
152  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.");
153  this->addOperation("kickOutAll", &DeploymentComponent::kickOutAll, this, ClientThread).doc("Calls stopComponents, cleanupComponents and unloadComponents in a row.");
154 
155  this->addOperation("kickOutComponent", &DeploymentComponent::kickOutComponent, this, ClientThread).doc("Calls stopComponents, cleanupComponent and unloadComponent in a row.").arg("comp_name", "component name");
156  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).");
157 
158  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.");
159  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.");
160 
161 
162  // Work around compiler ambiguity:
163  typedef bool(DeploymentComponent::*DCFun)(const std::string&, const std::string&);
165  this->addOperation("connectPeers", cp, this, ClientThread).doc("Connect two Components known to this Component.").arg("One", "The first component.").arg("Two", "The second component.");
167  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.");
168  typedef bool(DeploymentComponent::*DC4Fun)(const std::string&, const std::string&,
169  const std::string&, const std::string&);
170  DC4Fun cp4 = &DeploymentComponent::connectPorts;
171  this->addOperation("connectTwoPorts", cp4, this, ClientThread).doc("DEPRECATED. Connect two ports of Components known to this Component.")
172  .arg("One", "The first component.")
173  .arg("PortOne", "The port name of the first component.")
174  .arg("Two", "The second component.")
175  .arg("PortTwo", "The port name of the second component.");
176  this->addOperation("createStream", &DeploymentComponent::createStream, this, ClientThread).doc("DEPRECATED. Creates a stream to or from a port.")
177  .arg("component", "The component which owns 'port'.")
178  .arg("port", "The port to create a stream from or to.")
179  .arg("policy", "The connection policy which serves to describe the stream to be created.");
180 
181  // New API:
182  this->addOperation("connect", &DeploymentComponent::connect, this, ClientThread).doc("Creates a connection between two ports.")
183  .arg("portOne", "The first port of the connection. Use a dot-separated-path.")
184  .arg("portTwo", "The second port of the connection. Use a dot-separated-path.")
185  .arg("policy", "The connection policy which serves to describe the stream to be created. Use 'ConnPolicy()' to use the default.");
186  this->addOperation("stream", &DeploymentComponent::stream, this, ClientThread).doc("Creates a stream to or from a port.")
187  .arg("port", "The port to create a stream from or to. Use a dot-separated-path.")
188  .arg("policy", "The connection policy which serves to describe the stream to be created. Use 'ConnPolicy()' to use the default.");
189 
190  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.");
191  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).");
192 
194  this->addOperation("addPeer", cp, this, ClientThread).doc("Add a peer to a Component.").arg("From", "The first component.").arg("To", "The other component.");
195  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'");
196  typedef void(DeploymentComponent::*RPFun)(const std::string&);
197  RPFun rp = &RTT::TaskContext::removePeer;
198  this->addOperation("removePeer", rp, this, ClientThread).doc("Remove a peer from this Component.").arg("PeerName", "The name of the peer to remove.");
199 
200  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.");
201  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.");
202  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.");
203  this->addOperation("setSequentialActivity", &DeploymentComponent::setSequentialActivity, this, ClientThread).doc("Attach a 'stand alone' sequential activity to a Component.").arg("CompName", "The name of the Component.");
204  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).");
205  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.");
206  this->addOperation("setFileDescriptorActivity", &DeploymentComponent::setFileDescriptorActivity, this, ClientThread)
207  .doc("Attach a File Descriptor activity to a Component.")
208  .arg("CompName", "The name of the Component.")
209  .arg("Timeout", "The timeout of the activity (set to zero for no timeout).")
210  .arg("Priority", "The priority of the activity.")
211  .arg("SchedType", "The scheduler type of the activity.");
212 
213  this->addOperation("setWaitPeriodPolicy", &DeploymentComponent::setWaitPeriodPolicy, this, ClientThread).doc("Sets the wait period policy of an existing component thread.").arg("CompName", "The name of the Component.").arg("Policy", "The new policy (ORO_WAIT_ABS or ORO_WAIT_REL).");
214 
215  valid_names.insert("AutoUnload");
216  valid_names.insert("UseNamingService");
217  valid_names.insert("Server");
218  valid_names.insert("AutoConf");
219  valid_names.insert("AutoStart");
220  valid_names.insert("AutoConnect");
221  valid_names.insert("AutoSave");
222  valid_names.insert("PropertyFile");
223  valid_names.insert("UpdateProperties");
224  valid_names.insert("LoadProperties");
225  valid_names.insert("ProgramScript");
226  valid_names.insert("StateMachineScript");
227  valid_names.insert("Ports");
228  valid_names.insert("Peers");
229  valid_names.insert("Activity");
230  valid_names.insert("Master");
231  valid_names.insert("Properties");
232  valid_names.insert("Service");
233  valid_names.insert("Plugin"); // equivalent to Service.
234  valid_names.insert("Provides"); // equivalent to Service.
235  valid_names.insert("RunScript"); // runs a program script in a component.
236 
237  // Check for 'Deployer-site.cpf' XML file.
238  if (siteFile.empty())
239  siteFile = this->getName() + "-site.cpf";
240  std::ifstream hassite(siteFile.c_str());
241  if ( !hassite ) {
242  // if not, just configure
243  this->configure();
244 
245  // Backwards compatibility with < 2.3: import OCL by default
246  log(Info) << "No site file was found. Importing 'ocl' by default." <<endlog();
247  try {
248  import("ocl");
249  } catch (std::exception& e) {
250  // ignore errors.
251  }
252  return;
253  }
254 
255  // OK: kick-start it. Need to do import("ocl") and set AutoConf to configure self.
256  log(Info) << "Using site file '" << siteFile << "'." << endlog();
257  this->kickStart( siteFile );
258 
259  }
260 
262  {
263  Logger::In in("configure");
264  if (compPath.empty() )
265  {
266  compPath = ComponentLoader::Instance()->getComponentPath();
267  } else {
268  log(Info) <<"RTT_COMPONENT_PATH was set to " << compPath << endlog();
269  log(Info) <<"Re-scanning for plugins and components..."<<endlog();
270  PluginLoader::Instance()->setPluginPath(compPath);
271  ComponentLoader::Instance()->setComponentPath(compPath);
273  }
274  return true;
275  }
276 
278 
280 
282  {
283  // Should we unload all loaded components here ?
284  if ( autoUnload.get() ) {
285  kickOutAll();
286  }
287  }
288 
290  int sigs[] = { SIGINT, SIGTERM, SIGHUP };
291  if ( !waitForSignals(sigs, 3) )
292  return false;
293  cout << "DeploymentComponent: Got interrupt !" <<endl;
294  return true;
295  }
296 
298  return waitForSignals(&sig, 1);
299  }
300 
301  bool DeploymentComponent::waitForSignals(int *sigs, std::size_t sig_count) {
302 #ifdef USE_SIGNALS
303  struct sigaction sa, sold[sig_count];
304  std::size_t index = 0;
305  sa.sa_handler = ctrl_c_catcher;
306  for( ; index < sig_count; ++index) {
307  if ( ::sigaction(sigs[index], &sa, &sold[index]) != 0) {
308  cout << "DeploymentComponent: Failed to install signal handler for signal " << sigs[index] << endl;
309  break;
310  }
311  }
312 
313  if (index == sig_count) {
314  bool break_loop = false;
315  while(!break_loop) {
316  for(std::size_t check = 0; check < sig_count; ++check) {
317  if (got_signal == sigs[check]) break_loop = true;
318  }
319  TIME_SPEC ts;
320  ts.tv_sec = 1;
321  ts.tv_nsec = 0;
322  rtos_nanosleep(&ts, 0);
323  }
324  }
325  got_signal = -1;
326 
327  // reinstall previous handlers if present.
328  while(index > 0) {
329  index--;
330  if (sold[index].sa_handler || sold[index].sa_sigaction) {
331  ::sigaction(sigs[index], &sold[index], NULL);
332  }
333  }
334  return true;
335 #else
336  cout << "DeploymentComponent: Failed to install signal handler for signal " << sig << ": Not supported by this Operating System. "<<endl;
337  return false;
338 #endif
339  }
340 
341  bool DeploymentComponent::connectPeers(const std::string& one, const std::string& other)
342  {
343  RTT::Logger::In in("connectPeers");
344  RTT::TaskContext* t1 = (((one == this->getName()) || (one == "this")) ? this : this->getPeer(one));
345  RTT::TaskContext* t2 = (((other == this->getName()) || (other == "this")) ? this : this->getPeer(other));
346  if (!t1) {
347  log(Error)<< "No such peer: "<<one<<endlog();
348  return false;
349  }
350  if (!t2) {
351  log(Error) << "No such peer: "<<other<<endlog();
352  return false;
353  }
354  return t1->connectPeers(t2);
355  }
356 
357  bool DeploymentComponent::addPeer(const std::string& from, const std::string& to)
358  {
359  RTT::Logger::In in("addPeer");
360  RTT::TaskContext* t1 = (((from == this->getName()) || (from == "this")) ? this : this->getPeer(from));
361  RTT::TaskContext* t2 = (((to == this->getName()) || (to == "this")) ? this : this->getPeer(to));
362  if (!t1) {
363  log(Error)<< "No such peer: "<<from<<endlog();
364  return false;
365  }
366  if (!t2) {
367  log(Error)<< "No such peer: "<<to<<endlog();
368  return false;
369  }
370  if ( t1->hasPeer(to) ) {
371  log(Info) << "addPeer: "<< to << " is already a peer of " << from << endlog();
372  return true;
373  }
374  return t1->addPeer(t2,to);
375  }
376 
377  bool DeploymentComponent::aliasPeer(const std::string& from, const std::string& to, const std::string& alias)
378  {
379  RTT::Logger::In in("addPeer");
380  RTT::TaskContext* t1 = (((from == this->getName()) || (from == "this")) ? this : this->getPeer(from));
381  RTT::TaskContext* t2 = (((to == this->getName()) || (to == "this")) ? this : this->getPeer(to));
382  if (!t1) {
383  log(Error)<< "No such peer known to deployer '"<< this->getName()<< "': "<<from<<endlog();
384  return false;
385  }
386  if (!t2) {
387  log(Error)<< "No such peer known to deployer '"<< this->getName()<< "': "<<to<<endlog();
388  return false;
389  }
390  return t1->addPeer(t2, alias);
391  }
392 
394  std::vector<std::string> strs;
395  boost::split(strs, names, boost::is_any_of("."));
396 
397  // strs could be empty because of a bug in Boost 1.44 (see https://svn.boost.org/trac/boost/ticket/4751)
398  if (strs.empty()) return Service::shared_ptr();
399 
400  string component = strs.front();
401  RTT::TaskContext *tc = (((component == this->getName()) || (component == "this")) ? this : getPeer(component));
402  if (!tc) {
403  log(Error) << "No such component: '"<< component << "'";
404  if ( names.find('.') != string::npos )
405  log(Error) << " when looking for service '" << names <<" '";
406  log() << endlog();
407  return Service::shared_ptr();
408  }
409  // component is peer or self:
410  Service::shared_ptr ret = tc->provides();
411 
412  // remove component name:
413  strs.erase( strs.begin() );
414 
415  // iterate over remainders:
416  while ( !strs.empty() && ret) {
417  ret = ret->getService( strs.front() );
418  if (ret)
419  strs.erase( strs.begin() );
420  }
421  if (!ret) {
422  log(Error) <<"No such service: '"<< strs.front() <<"' while looking for service '"<< names<<"'"<<endlog();
423  }
424  return ret;
425  }
426 
428  std::vector<std::string> strs;
429  boost::split(strs, names, boost::is_any_of("."));
430 
431  string component = strs.front();
432  RTT::TaskContext *tc = (((component == this->getName()) || (component == "this")) ? this : getPeer(component));
433  if (!tc) {
434  log(Error) << "No such component: '"<< component <<"'" <<endlog();
435  if ( names.find('.') != string::npos )
436  log(Error)<< " when looking for service '" << names <<"'" <<endlog();
438  }
439  // component is peer or self:
441 
442  // remove component name:
443  strs.erase( strs.begin() );
444 
445  // iterate over remainders:
446  while ( !strs.empty() && ret) {
447  ret = ret->requires( strs.front() );
448  if (ret)
449  strs.erase( strs.begin() );
450  }
451  if (!ret) {
452  log(Error) <<"No such service: '"<< strs.front() <<"' while looking for service '"<< names<<"'"<<endlog();
453  }
454  return ret;
455  }
456 
458  std::vector<std::string> strs;
459  boost::split(strs, names, boost::is_any_of("."));
460 
461  // strs could be empty because of a bug in Boost 1.44 (see https://svn.boost.org/trac/boost/ticket/4751)
462  if (strs.empty()) return 0;
463 
464  string component = strs.front();
465  RTT::TaskContext *tc = (((component == this->getName()) || (component == "this")) ? this : getPeer(component));
466  if (!tc) {
467  log(Error) << "No such component: '"<< component <<"'" ;
468  log(Error)<< " when looking for port '" << names <<"'" <<endlog();
469  return 0;
470  }
471  // component is peer or self:
472  Service::shared_ptr serv = tc->provides();
473  base::PortInterface* ret = 0;
474 
475  // remove component name:
476  strs.erase( strs.begin() );
477 
478  // iterate over remainders:
479  while ( strs.size() != 1 && serv) {
480  serv = serv->getService( strs.front() );
481  if (serv)
482  strs.erase( strs.begin() );
483  }
484  if (!serv) {
485  log(Error) <<"No such service: '"<< strs.front() <<"' while looking for port '"<< names<<"'"<<endlog();
486  return 0;
487  }
488  ret = serv->getPort(strs.front());
489  if (!ret) {
490  log(Error) <<"No such port: '"<< strs.front() <<"' while looking for port '"<< names<<"'"<<endlog();
491  }
492 
493  return ret;
494  }
495 
496  bool DeploymentComponent::connectPorts(const std::string& one, const std::string& other)
497  {
498  RTT::Logger::In in("connectPorts");
499  RTT::TaskContext* a, *b;
500  a = getPeer(one);
501  b = getPeer(other);
502  if ( !a ) {
503  log(Error) << one <<" could not be found."<< endlog();
504  return false;
505  }
506  if ( !b ) {
507  log(Error) << other <<" could not be found."<< endlog();
508  return false;
509  }
510 
511  return a->connectPorts(b);
512  }
513 
514  bool DeploymentComponent::connectPorts(const std::string& one, const std::string& one_port,
515  const std::string& other, const std::string& other_port)
516  {
517  RTT::Logger::In in("connectPorts");
519  a = stringToService(one);
520  b = stringToService(other);
521  if (!a || !b)
522  return false;
523  base::PortInterface* ap, *bp;
524  ap = a->getPort(one_port);
525  bp = b->getPort(other_port);
526  if ( !ap ) {
527  log(Error) << one <<" does not have a port "<<one_port<< endlog();
528  return false;
529  }
530  if ( !bp ) {
531  log(Error) << other <<" does not have a port "<<other_port<< endlog();
532  return false;
533  }
534 
535  // Warn about already connected ports.
536  if ( ap->connected() && bp->connected() ) {
537  log(Debug) << "Port '"<< ap->getName() << "' of Component '"<<a->getName()
538  << "' and port '"<< bp->getName() << "' of Component '"<<b->getName()
539  << "' are already connected but (probably) not to each other. Connecting them anyway."<<endlog();
540  }
541 
542  // use the base::PortInterface implementation
543  if ( ap->connectTo( bp ) ) {
544  // all went fine.
545  log(Info)<< "Connected Port " << one +"." + one_port << " to "<< other +"." + other_port <<"." << endlog();
546  return true;
547  } else {
548  log(Error)<< "Failed to connect Port " << one +"." + one_port << " to "<< other +"." + other_port <<"." << endlog();
549  return true;
550  }
551  }
552 
553  bool DeploymentComponent::createStream(const std::string& comp, const std::string& port, ConnPolicy policy)
554  {
556  if ( !serv )
557  return false;
558  PortInterface* porti = serv->getPort(port);
559  if ( !porti ) {
560  log(Error) <<"Service in component "<<comp<<" has no port "<< port << "."<< endlog();
561  return false;
562  }
563  return porti->createStream( policy );
564  }
565 
566  // New API:
567  bool DeploymentComponent::connect(const std::string& one, const std::string& other, ConnPolicy cp)
568  {
569  RTT::Logger::In in("connect");
570  base::PortInterface* ap, *bp;
571  ap = stringToPort(one);
572  bp = stringToPort(other);
573  if (!ap || !bp)
574  return false;
575 
576  // Warn about already connected ports.
577  if ( ap->connected() && bp->connected() ) {
578  log(Debug) << "Port '"<< ap->getName() << "' of '"<< one
579  << "' and port '"<< bp->getName() << "' of '"<< other
580  << "' are already connected but (probably) not to each other. Connecting them anyway."<<endlog();
581  }
582 
583  // use the base::PortInterface implementation
584  if ( ap->connectTo( bp, cp ) ) {
585  // all went fine.
586  log(Info)<< "Connected Port " << one << " to "<< other <<"." << endlog();
587  return true;
588  } else {
589  log(Error)<< "Failed to connect Port " << one << " to "<< other <<"." << endlog();
590  return false;
591  }
592  }
593 
594  bool DeploymentComponent::stream(const std::string& port, ConnPolicy policy)
595  {
596  base::PortInterface* porti = stringToPort(port);
597  if ( !porti ) {
598  return false;
599  }
600  return porti->createStream( policy );
601  }
602 
603  bool DeploymentComponent::connectServices(const std::string& one, const std::string& other)
604  {
605  RTT::Logger::In in("connectServices");
606  RTT::TaskContext* a, *b;
607  a = getPeer(one);
608  b = getPeer(other);
609  if ( !a ) {
610  log(Error) << one <<" could not be found."<< endlog();
611  return false;
612  }
613  if ( !b ) {
614  log(Error) << other <<" could not be found."<< endlog();
615  return false;
616  }
617 
618  return a->connectServices(b);
619  }
620 
621  bool DeploymentComponent::connectOperations(const std::string& required, const std::string& provided)
622  {
623  RTT::Logger::In in("connectOperations");
624  // Required service
625  boost::iterator_range<std::string::const_iterator> reqs = boost::algorithm::find_last(required, ".");
626  std::string reqs_name(required.begin(), reqs.begin());
627  std::string rop_name(reqs.begin()+1, required.end());
628  log(Debug) << "Looking for required operation " << rop_name << " in service " << reqs_name << endlog();
630  // Provided service
631  boost::iterator_range<std::string::const_iterator> pros = boost::algorithm::find_last(provided, ".");
632  std::string pros_name(provided.begin(), pros.begin());
633  std::string pop_name(pros.begin()+1, provided.end());
634  log(Debug) << "Looking for provided operation " << pop_name << " in service " << pros_name << endlog();
635  Service::shared_ptr p = this->stringToService(pros_name);
636  // Requested operation
637  RTT::base::OperationCallerBaseInvoker* rop = r->getOperationCaller(rop_name);
638  if (! rop) {
639  log(Error) << "No requested operation " << rop_name << " found in service " << reqs_name << endlog();
640  return false;
641  }
642  if ( rop->ready() ) {
643  log(Error) << "Requested operation " << rop_name << " already connected to a provided operation!" << endlog();
644  return false;
645  }
646  // Provided operation
647  if (! p->hasOperation(pop_name)) {
648  log(Error) << "No provided operation " << pop_name << " found in service " << pros_name << endlog();
649  return false;
650  }
651  // Connection
652  rop->setImplementation(p->getLocalOperation( pop_name ), r->getServiceOwner()->engine());
653  if ( rop->ready() )
654  log(Debug) << "Successfully set up OperationCaller for operation " << rop_name << endlog();
655  return rop->ready();
656  }
657 
658  int string_to_oro_sched(const std::string& sched) {
659  if ( sched == "ORO_SCHED_OTHER" )
660  return ORO_SCHED_OTHER;
661  if (sched == "ORO_SCHED_RT" )
662  return ORO_SCHED_RT;
663  log(Error)<<"Unknown scheduler type: "<< sched <<endlog();
664  return -1;
665  }
666 
667  bool DeploymentComponent::loadConfigurationString(const std::string& text)
668  {
669  const char* tmpfile = ".loadConfigurationString.cpf";
670  std::ofstream file( tmpfile );
671  file << text.c_str();
672  file.close();
673  return this->loadConfiguration( tmpfile );
674  }
675 
676  bool DeploymentComponent::runScript(const std::string& file_name)
677  {
678 #ifdef BUILD_LUA_RTT
679  if (file_name.rfind(".lua") == file_name.length() - 4) {
680  if (!this->provides()->hasService("Lua")) {
681  // Load lua scripting service
682  if(!RTT::plugin::PluginLoader::Instance()->loadService("Lua", this)) {
683  RTT::log(RTT::Error) << "Could not load lua service." << RTT::endlog();
684  return false;
685  }
686 
687  // Get exec_str operation
689  this->provides("Lua")->getOperation("exec_str");
690 
691  // Load rttlib for first-class operation support
692  exec_str("require(\"rttlib\")");
693  }
694 
695  // Get exec_file operation
697  this->provides("Lua")->getOperation("exec_file");
698 
699  return exec_file( file_name );
700  }
701 #endif
702  return this->getProvider<Scripting>("scripting")->runScript( file_name );
703  }
704 
705  bool DeploymentComponent::kickStart(const std::string& configurationfile)
706  {
707  bool loadOk = true;
708  bool configureOk = true;
709  bool startOk = true;
710 
711  const bool rc = kickStart2(configurationfile, true, loadOk, configureOk, startOk);
712 
713  // avoid compiler warnings
714  (void)loadOk;
715  (void)configureOk;
716  (void)startOk;
717 
718  return rc;
719  }
720 
721  bool DeploymentComponent::kickStart2(const std::string& configurationfile,
722  const bool doStart,
723  bool& loadOk,
724  bool& configureOk,
725  bool& startOk)
726  {
727  // set defaults
728  loadOk = true;
729  configureOk = true;
730  startOk = true;
731 
732  int thisGroup = nextGroup;
733  ++nextGroup; // whether succeed or fail
734  if ( this->loadComponentsInGroup(configurationfile, thisGroup) ) {
735  if ( root.empty() ) {
736  log(Warning) <<"No components loaded by DeploymentComponent from "<< configurationfile <<endlog();
737  return true;
738  }
739  if (this->configureComponentsGroup(thisGroup) ) {
740  if (doStart) {
741  if ( this->startComponentsGroup(thisGroup) ) {
742  log(Info) <<"Successfully loaded, configured and started components from "<< configurationfile <<endlog();
743  return true;
744  } else {
745  log(Error) <<"Failed to start a component: aborting kick-start."<<endlog();
746  startOk = false;
747  }
748  } else {
749  log(Info) <<"Successfully loaded and configured (but did not start) components from "<< configurationfile <<endlog();
750  return true;
751  }
752  } else {
753  log(Error) <<"Failed to configure a component: aborting kick-start."<<endlog();
754  configureOk = false;
755  }
756  } else {
757  log(Error) <<"Failed to load a component: aborting kick-start."<<endlog();
758  loadOk = false;
759  }
760  return false;
761  }
762 
764  {
765  bool ok = true;
766  while (nextGroup != -1 )
767  {
768  ok &= kickOutGroup(nextGroup);
769  --nextGroup;
770  }
771  // reset group counter to zero
772  nextGroup = 0;
773  return ok;
774  }
775 
776  bool DeploymentComponent::kickOutGroup(const int group)
777  {
778  bool sret = this->stopComponentsGroup(group);
779  bool cret = this->cleanupComponentsGroup(group);
780  bool uret = this->unloadComponentsGroup(group);
781  if ( sret && cret && uret) {
782  log(Info) << "Kick-out of group " << group << " successful."<<endlog();
783  return true;
784  }
785  // Diagnostics:
786  log(Critical) << "Kick-out of group " << group << " failed: ";
787  if (!sret)
788  log(Critical) << " stopComponents() failed.";
789  if (!cret)
790  log(Critical) << " cleanupComponents() failed.";
791  if (!uret)
792  log(Critical) << " unloadComponents() failed.";
793  log(Critical) << endlog();
794  return false;
795  }
796 
798  RTT::TaskContext* c,
799  const bool ignoreNonexistentPorts)
800  {
801  assert(0 != c);
802 
803  bool valid = true;
804 
805  // connect ports 'Ports' tag is optional.
806  RTT::Property<RTT::PropertyBag>* ports = comp.value().getPropertyType<PropertyBag>("Ports");
807  if ( ports != 0 ) {
808  for (RTT::PropertyBag::iterator pit = ports->value().begin(); pit != ports->value().end(); pit++) {
809  Property<string> portcon = *pit;
810  if ( !portcon.ready() ) {
811  log(Error)<< "RTT::Property '"<< (*pit)->getName() <<"' is not of type 'string'." << endlog();
812  valid = false;
813  continue;
814  }
815  base::PortInterface* p = c->ports()->getPort( portcon.getName() );
816  if ( !p ) {
817  if (ignoreNonexistentPorts)
818  {
819  log(Info)<< "Component '"<< c->getName() <<"' does not have a Port '"<< portcon.getName()<<"'. Will try to connect again later." << endlog();
820  continue; // ignore this issue
821  } else {
822  log(Error)<< "Component '"<< c->getName() <<"' does not have a Port '"<< portcon.getName()<<"'." << endlog();
823  valid = false;
824  }
825  }
826  // store the port
827  if (valid){
828  string conn_name = portcon.value(); // reads field of property
829  bool to_add = true;
830  // go through the vector to avoid duplicate items.
831  // NOTE the sizes conmap[conn_name].ports.size() and conmap[conn_name].owners.size() are supposed to be equal
832  for(unsigned int a=0; a < conmap[conn_name].ports.size(); a++)
833  {
834  if( conmap[conn_name].ports.at(a) == p && conmap[conn_name].owners.at(a) == c)
835  {
836  to_add = false;
837  continue;
838  }
839  }
840 
841  if(to_add)
842  {
843  log(Debug)<<"storing Port: "<<c->getName()<<"."<< portcon.getName();
844  log(Debug)<<" in " << conn_name <<endlog();
845  conmap[conn_name].ports.push_back( p );
846  conmap[conn_name].owners.push_back( c );
847  }
848  }
849  }
850  }
851  return valid;
852  }
853 
854  bool DeploymentComponent::loadConfiguration(const std::string& configurationfile)
855  {
856  return this->loadComponents(configurationfile);
857  }
858 
859  bool DeploymentComponent::loadComponents(const std::string& configurationfile)
860  {
861  bool valid = loadComponentsInGroup(configurationfile, nextGroup);
862  ++nextGroup;
863  return valid;
864  }
865 
866  bool DeploymentComponent::loadComponentsInGroup(const std::string& configurationfile,
867  const int group)
868  {
869  RTT::Logger::In in("loadComponents");
870 
871  RTT::PropertyBag from_file;
872  log(Info) << "Loading '" <<configurationfile<<"' in group " << group << "."<< endlog();
873  // demarshalling failures:
874  bool failure = false;
875  // semantic failures:
876  bool valid = validConfig.get();
877  marsh::PropertyDemarshaller demarshaller(configurationfile);
878  try {
879  if ( demarshaller.deserialize( from_file ) )
880  {
881  valid = true;
882  log(Info)<<"Validating new configuration..."<<endlog();
883  if ( from_file.empty() ) {
884  log(Error)<< "Configuration was empty !" <<endlog();
885  valid = false;
886  }
887 
888  //for (RTT::PropertyBag::Names::iterator it= nams.begin();it != nams.end();it++) {
889  for (RTT::PropertyBag::iterator it= from_file.begin(); it!=from_file.end();it++) {
890  // Read in global options.
891  if ( (*it)->getName() == "Import" ) {
892  RTT::Property<std::string> importp = *it;
893  if ( !importp.ready() ) {
894  log(Error)<< "Found 'Import' statement, but it is not of type='string'."<<endlog();
895  valid = false;
896  continue;
897  }
898  if ( this->import( importp.get() ) == false )
899  valid = false;
900  continue;
901  }
902  if ( (*it)->getName() == "LoadLibrary" ) {
903  RTT::Property<std::string> importp = *it;
904  if ( !importp.ready() ) {
905  log(Error)<< "Found 'LoadLibrary' statement, but it is not of type='string'."<<endlog();
906  valid = false;
907  continue;
908  }
909  if ( this->loadLibrary( importp.get() ) == false )
910  valid = false;
911  continue;
912  }
913  if ( (*it)->getName() == "Path" ) {
914  RTT::Property<std::string> pathp = *it;
915  if ( !pathp.ready() ) {
916  log(Error)<< "Found 'Path' statement, but it is not of type='string'."<<endlog();
917  valid = false;
918  continue;
919  }
920  this->path( pathp.get() );
921  continue;
922  }
923  if ( (*it)->getName() == "Include" ) {
924  RTT::Property<std::string> includep = *it;
925  if ( !includep.ready() ) {
926  log(Error)<< "Found 'Include' statement, but it is not of type='string'."<<endlog();
927  valid = false;
928  continue;
929  }
930  // recursively call this function.
931  if ( this->loadComponentsInGroup( includep.get(), group ) == false )
932  valid = false;
933  continue;
934  }
935  if ( (*it)->getName() == "GlobalsRepository" ) {
936  RTT::Property<RTT::PropertyBag> global = *it;
937  if ( !global.ready() ) {
938  log(Error)<< "Found 'GlobalsRepository' tag, but it is not a complex xml type"<<endlog();
939  valid = false;
940  continue;
941  }
942  // Check for default Global properties to be set.
943  for (RTT::PropertyBag::const_iterator pf = global.rvalue().begin(); pf != global.rvalue().end(); ++pf) {
944  if ( (*pf)->getName() == "Properties" ) {
946  if ( !props.ready() ) {
947  log(Error)<< "Found 'Properties' in 'GlobalsRepository' tag, but it is not of type PropertyBag"<<endlog();
948  valid = false;
949  continue;
950  }
952  if (!ret) {
953  log(Error) << "Failed to configure global properties from configuration file."<<endlog();
954  valid = false;
955  } else {
956  log(Info) << "Configured global properties from configuration file."<<endlog();
957  }
958  }
959  }
960  continue;
961  }
962 
963  // Check if it is a propertybag.
965  if ( !comp.ready() ) {
966  log(Error)<< "RTT::Property '"<< *it <<"' should be a struct, Include, Path or Import statement." << endlog();
967  valid = false;
968  continue;
969  }
970 
971  //Check if it is a ConnPolicy
972  // convert to Property<ConnPolicy>
973  Property<ConnPolicy> cp_prop((*it)->getName(),"");
974  assert( cp_prop.ready() );
975  if ( cp_prop.compose( comp ) ) {
976  //It's a connection policy.
977 #if defined(RTT_VERSION_GTE)
978 #if RTT_VERSION_GTE(2,8,99)
979  // Set default ConnPolicy
980  if (cp_prop.getName() == "Default") {
981  RTT::ConnPolicy::Default() = cp_prop.get();
982  } else {
983 #endif
984 #endif
985  conmap[cp_prop.getName()].policy = cp_prop.get();
986 #if defined(RTT_VERSION_GTE)
987 #if RTT_VERSION_GTE(2,8,99)
988  }
989 #endif
990 #endif
991  log(Debug) << "Saw connection policy " << (*it)->getName() << endlog();
992  continue;
993  }
994 
995  // Parse the options before creating the component:
996  for (RTT::PropertyBag::const_iterator optit= comp.rvalue().begin(); optit != comp.rvalue().end();optit++) {
997  if ( valid_names.find( (*optit)->getName() ) == valid_names.end() ) {
998  log(Error) << "Unknown type syntax: '"<< (*optit)->getName() << "' in component struct "<< comp.getName() <<endlog();
999  valid = false;
1000  continue;
1001  }
1002  if ( (*optit)->getName() == "AutoConnect" ) {
1003  RTT::Property<bool> ps = comp.rvalue().getProperty("AutoConnect");
1004  if (!ps.ready()) {
1005  log(Error) << "AutoConnect must be of type <boolean>" << endlog();
1006  valid = false;
1007  } else
1008  compmap[comp.getName()].autoconnect = ps.get();
1009  continue;
1010  }
1011  if ( (*optit)->getName() == "AutoStart" ) {
1012  RTT::Property<bool> ps = comp.rvalue().getProperty("AutoStart");
1013  if (!ps.ready()) {
1014  log(Error) << "AutoStart must be of type <boolean>" << endlog();
1015  valid = false;
1016  } else
1017  compmap[comp.getName()].autostart = ps.get();
1018  continue;
1019  }
1020  if ( (*optit)->getName() == "AutoSave" ) {
1021  RTT::Property<bool> ps = comp.rvalue().getProperty("AutoSave");
1022  if (!ps.ready()) {
1023  log(Error) << "AutoSave must be of type <boolean>" << endlog();
1024  valid = false;
1025  } else
1026  compmap[comp.getName()].autosave = ps.get();
1027  continue;
1028  }
1029  if ( (*optit)->getName() == "AutoConf" ) {
1030  RTT::Property<bool> ps = comp.rvalue().getProperty("AutoConf");
1031  if (!ps.ready()) {
1032  log(Error) << "AutoConf must be of type <boolean>" << endlog();
1033  valid = false;
1034  } else
1035  compmap[comp.getName()].autoconf = ps.get();
1036  continue;
1037  }
1038  if ( (*optit)->getName() == "Server" ) {
1039  RTT::Property<bool> ps = comp.rvalue().getProperty("Server");
1040  if (!ps.ready()) {
1041  log(Error) << "Server must be of type <boolean>" << endlog();
1042  valid = false;
1043  } else
1044  compmap[comp.getName()].server = ps.get();
1045  continue;
1046  }
1047  if ( (*optit)->getName() == "Service" || (*optit)->getName() == "Plugin" || (*optit)->getName() == "Provides") {
1048  RTT::Property<string> ps = *optit;
1049  if (!ps.ready()) {
1050  log(Error) << (*optit)->getName() << " must be of type <string>" << endlog();
1051  valid = false;
1052  } else {
1053  compmap[comp.getName()].plugins.push_back(ps.value());
1054  }
1055  continue;
1056  }
1057  if ( (*optit)->getName() == "UseNamingService" ) {
1058  RTT::Property<bool> ps = comp.rvalue().getProperty("UseNamingService");
1059  if (!ps.ready()) {
1060  log(Error) << "UseNamingService must be of type <boolean>" << endlog();
1061  valid = false;
1062  } else
1063  compmap[comp.getName()].use_naming = ps.get();
1064  continue;
1065  }
1066  if ( (*optit)->getName() == "PropertyFile" ) {
1067  RTT::Property<string> ps = comp.rvalue().getProperty("PropertyFile");
1068  if (!ps.ready()) {
1069  log(Error) << "PropertyFile must be of type <string>" << endlog();
1070  valid = false;
1071  } else
1072  compmap[comp.getName()].configfile = ps.get();
1073  continue;
1074  }
1075  if ( (*optit)->getName() == "UpdateProperties" ) {
1076  RTT::Property<string> ps = comp.rvalue().getProperty("UpdateProperties");
1077  if (!ps.ready()) {
1078  log(Error) << "UpdateProperties must be of type <string>" << endlog();
1079  valid = false;
1080  } else
1081  compmap[comp.getName()].configfile = ps.get();
1082  continue;
1083  }
1084  if ( (*optit)->getName() == "LoadProperties" ) {
1085  RTT::Property<string> ps = comp.rvalue().getProperty("LoadProperties");
1086  if (!ps.ready()) {
1087  log(Error) << "LoadProperties must be of type <string>" << endlog();
1088  valid = false;
1089  } else
1090  compmap[comp.getName()].configfile = ps.get();
1091  continue;
1092  }
1093  if ( (*optit)->getName() == "Properties" ) {
1094  base::PropertyBase* ps = comp.rvalue().getProperty("Properties");
1095  if (!ps) {
1096  log(Error) << "Properties must be a <struct>" << endlog();
1097  valid = false;
1098  }
1099  continue;
1100  }
1101  if ( (*optit)->getName() == "RunScript" ) {
1102  base::PropertyBase* ps = comp.rvalue().getProperty("RunScript");
1103  if (!ps) {
1104  log(Error) << "RunScript must be of type <string>" << endlog();
1105  valid = false;
1106  }
1107  continue;
1108  }
1109  if ( (*optit)->getName() == "ProgramScript" ) {
1110  base::PropertyBase* ps = comp.rvalue().getProperty("ProgramScript");
1111  if (!ps) {
1112  log(Error) << "ProgramScript must be of type <string>" << endlog();
1113  valid = false;
1114  }
1115  continue;
1116  }
1117  if ( (*optit)->getName() == "StateMachineScript" ) {
1118  base::PropertyBase* ps = comp.rvalue().getProperty("StateMachineScript");
1119  if (!ps) {
1120  log(Error) << "StateMachineScript must be of type <string>" << endlog();
1121  valid = false;
1122  }
1123  continue;
1124  }
1125  }
1126 
1127  // Check if we know or are this component.
1128  RTT::TaskContext* c = 0;
1129  if ( (*it)->getName() == "this" || (*it)->getName() == this->getName() )
1130  c = this;
1131  else
1132  c = this->getPeer( (*it)->getName() );
1133  if ( !c ) {
1134  // try to load it.
1135  if (this->loadComponent( (*it)->getName(), comp.rvalue().getType() ) == false) {
1136  log(Warning)<< "Could not configure '"<< (*it)->getName() <<"': No such peer."<< endlog();
1137  valid = false;
1138  continue;
1139  }
1140  c = compmap[(*it)->getName()].instance;
1141 
1142  // The component is added to a group only when it is loaded, not when a service is added or changed.
1143  compmap[(*it)->getName()].group = group;
1144  log(Info) << "Component " << (*it)->getName() << " added to group " << group << "." << endlog();
1145  } else {
1146  // If the user added c as a peer (outside of Deployer) store the pointer
1147  compmap[(*it)->getName()].instance = c;
1148  }
1149 
1150  assert(c);
1151 
1152  // load plugins/services:
1153  vector<string>& services = compmap[(*it)->getName()].plugins;
1154  for (vector<string>::iterator svit = services.begin(); svit != services.end(); ++svit) {
1155  if ( c->provides()->hasService( *svit ) == false) {
1156  PluginLoader::Instance()->loadService(*svit, c);
1157  }
1158  }
1159 
1160  // set PropFile name if present
1161  if ( comp.value().getProperty("PropFile") ) // PropFile is deprecated
1162  comp.value().getProperty("PropFile")->setName("PropertyFile");
1163 
1164  // connect ports 'Ports' tag is optional.
1165  valid &= createConnectionMapFromPortsTag(comp, c, true);
1166 
1167  // Setup the connections from this
1168  // component to the others.
1169  if ( comp.value().find("Peers") != 0) {
1170  RTT::Property<RTT::PropertyBag> nm = comp.value().find("Peers");
1171  if ( !nm.ready() ) {
1172  log(Error)<<"RTT::Property 'Peers' must be a 'struct', was type "<< comp.value().find("Peers")->getType() << endlog();
1173  valid = false;
1174  } else {
1175  for (RTT::PropertyBag::const_iterator it= nm.rvalue().begin(); it != nm.rvalue().end();it++) {
1176  RTT::Property<std::string> pr = *it;
1177  if ( !pr.ready() ) {
1178  log(Error)<<"RTT::Property 'Peer' does not have type 'string'."<<endlog();
1179  valid = false;
1180  continue;
1181  }
1182  }
1183  }
1184  }
1185 
1186  // Read the activity profile if present.
1187  if ( comp.value().find("Activity") != 0) {
1188  RTT::Property<RTT::PropertyBag> nm = comp.value().find("Activity");
1189  if ( !nm.ready() ) {
1190  log(Error)<<"RTT::Property 'Activity' must be a 'struct'."<<endlog();
1191  valid = false;
1192  } else {
1193  if ( nm.rvalue().getType() == "PeriodicActivity" ) {
1194  RTT::Property<double> per = nm.rvalue().getProperty("Period"); // work around RTT 1.0.2 bug.
1195  if ( !per.ready() ) {
1196  log(Error)<<"Please specify period <double> of PeriodicActivity."<<endlog();
1197  valid = false;
1198  }
1199  RTT::Property<int> prio = nm.rvalue().getProperty("Priority"); // work around RTT 1.0.2 bug
1200  if ( !prio.ready() ) {
1201  log(Error)<<"Please specify priority <short> of PeriodicActivity."<<endlog();
1202  valid = false;
1203  }
1204 
1205  unsigned cpu_affinity = ~0; // default to all CPUs
1206  RTT::Property<unsigned> cpu_affinity_prop = nm.rvalue().getProperty("CpuAffinity");
1207  if(cpu_affinity_prop.ready()) {
1208  cpu_affinity = cpu_affinity_prop.get();
1209  }
1210  // else ignore as is optional
1211 
1212  RTT::Property<string> sched;
1213  if (nm.rvalue().getProperty("Scheduler") )
1214  sched = nm.rvalue().getProperty("Scheduler"); // work around RTT 1.0.2 bug
1215  int scheduler = ORO_SCHED_RT;
1216  if ( sched.ready() ) {
1217  scheduler = string_to_oro_sched( sched.get());
1218  if (scheduler == -1 )
1219  valid = false;
1220  }
1221  if (valid) {
1222  this->setNamedActivity(comp.getName(), nm.rvalue().getType(), per.get(), prio.get(), scheduler, cpu_affinity );
1223  }
1224  } else
1225  if ( nm.rvalue().getType() == "Activity" || nm.rvalue().getType() == "NonPeriodicActivity" ) {
1226  RTT::Property<double> per = nm.rvalue().getProperty("Period");
1227  if ( !per.ready() ) {
1228  per = Property<double>("p","",0.0); // default to 0.0
1229  }
1230  RTT::Property<int> prio = nm.rvalue().getProperty("Priority");
1231  if ( !prio.ready() ) {
1232  log(Error)<<"Please specify priority <short> of Activity."<<endlog();
1233  valid = false;
1234  }
1235 
1236  unsigned int cpu_affinity = ~0; // default to all CPUs
1237  RTT::Property<unsigned int> cpu_affinity_prop = nm.rvalue().getProperty("CpuAffinity");
1238  if(cpu_affinity_prop.ready()) {
1239  cpu_affinity = cpu_affinity_prop.get();
1240  }
1241  // else ignore as is optional
1242 
1243  RTT::Property<string> sched = nm.rvalue().getProperty("Scheduler");
1244  int scheduler = ORO_SCHED_RT;
1245  if ( sched.ready() ) {
1246  scheduler = string_to_oro_sched( sched.get());
1247  if (scheduler == -1 )
1248  valid = false;
1249  }
1250  if (valid) {
1251  this->setNamedActivity(comp.getName(), nm.rvalue().getType(), per.get(), prio.get(), scheduler, cpu_affinity );
1252  }
1253  } else
1254  if ( nm.rvalue().getType() == "SlaveActivity" ) {
1255  double period = 0.0;
1256  string master;
1257  if ( nm.rvalue().getProperty("Master") ) {
1258  master = nm.rvalue().getPropertyType<string>("Master")->get();
1259  if (valid) {
1260  this->setNamedActivity(comp.getName(), nm.rvalue().getType(), period, 0, 0, master );
1261  }
1262  } else {
1263  // No master given.
1264  if ( nm.rvalue().getProperty("Period") )
1265  period = nm.rvalue().getPropertyType<double>("Period")->get();
1266  if (valid) {
1267  this->setNamedActivity(comp.getName(), nm.rvalue().getType(), period, 0, 0 );
1268  }
1269  }
1270  } else
1271  if ( nm.rvalue().getType() == "SequentialActivity" ) {
1272  this->setNamedActivity(comp.getName(), nm.rvalue().getType(), 0, 0, 0 );
1273  } else
1274  if ( nm.rvalue().getType() == "FileDescriptorActivity" ) {
1275  RTT::Property<double> per = nm.rvalue().getProperty("Period");
1276  if ( !per.ready() ) {
1277  per = Property<double>("p","",0.0); // default to 0.0
1278  }
1279  // else ignore as is optional
1280 
1281  RTT::Property<int> prio = nm.rvalue().getProperty("Priority");
1282  if ( !prio.ready() ) {
1283  log(Error)<<"Please specify priority <short> of FileDescriptorActivity."<<endlog();
1284  valid = false;
1285  }
1286 
1287  unsigned int cpu_affinity = ~0; // default to all CPUs
1288  RTT::Property<unsigned int> cpu_affinity_prop = nm.rvalue().getProperty("CpuAffinity");
1289  if(cpu_affinity_prop.ready()) {
1290  cpu_affinity = cpu_affinity_prop.get();
1291  }
1292  // else ignore as is optional
1293 
1294  RTT::Property<string> sched = nm.rvalue().getProperty("Scheduler");
1295  int scheduler = ORO_SCHED_RT;
1296  if ( sched.ready() ) {
1297  scheduler = string_to_oro_sched( sched.get());
1298  if (scheduler == -1 )
1299  valid = false;
1300  }
1301  if (valid) {
1302  this->setNamedActivity(comp.getName(), nm.rvalue().getType(), per.get(), prio.get(), scheduler, cpu_affinity );
1303  }
1304  } else {
1305  log(Error) << "Unknown activity type: " << nm.rvalue().getType()<<endlog();
1306  valid = false;
1307  }
1308  }
1309  } else {
1310  // no 'Activity' element, default to Slave:
1311  //this->setNamedActivity(comp.getName(), "extras::SlaveActivity", 0.0, 0, 0 );
1312  }
1313  // put this component in the root config.
1314  // existing component options are updated, new components are
1315  // added to the back.
1316  // great: a hack to allow 'CompName.ior' as property name.
1317  string delimiter("@!#?<!");
1318  bool ret = updateProperty( root, from_file, comp.getName(), delimiter );
1319  if (!ret) {
1320  log(Error) << "Failed to store deployment properties for component " << comp.getName() <<endlog();
1321  valid = false;
1322  }
1323  }
1324 
1325  deletePropertyBag( from_file );
1326  }
1327  else
1328  {
1329  log(Error)<< "Some error occured while parsing "<< configurationfile <<endlog();
1330  failure = true;
1331  }
1332  } catch (...)
1333  {
1334  log(Error)<< "Uncaught exception in loadcomponents() !"<< endlog();
1335  failure = true;
1336  }
1337  validConfig.set(valid);
1338  return !failure && valid;
1339  }
1340 
1341  bool DeploymentComponent::createDataPortConnections(const bool skipUnconnected)
1342  {
1343  bool valid = true;
1344 
1345  for(ConMap::iterator it = conmap.begin(); it != conmap.end(); ++it) {
1346  ConnectionData *connection = &(it->second);
1347  std::string connection_name = it->first;
1348 
1349  // Set the connection name as default name_id if none was given explicitly
1350  if (connection->policy.name_id.empty()) {
1351  connection->policy.name_id = connection_name;
1352  }
1353 
1354  if ( connection->ports.size() == 1 ){
1355  string owner = connection->owners[0]->getName();
1356  string portname = connection->ports.front()->getName();
1357  string porttype = dynamic_cast<InputPortInterface*>(connection->ports.front() ) ? "InputPort" : "OutputPort";
1358 
1359  // a connection that currently has only one port may end up with
1360  // two ports later on, so we skip this connection for now.
1361  if (skipUnconnected)
1362  {
1363  log(Info) << "Skipping connection with name "<<connection_name<<" with only one Port "<<portname<<" from "<< owner << endlog();
1364  }
1365  else if ( connection->ports.front()->createStream( connection->policy ) == false) {
1366  log(Warning) << "Creating stream with name "<<connection_name<<" with Port "<<portname<<" from "<< owner << " failed."<< endlog();
1367  } else {
1368  log(Info) << "Component "<< owner << "'s " + porttype<< " " + portname << " will stream to "<< connection->policy.name_id << endlog();
1369  }
1370  continue;
1371  }
1372  // first find all write ports.
1373  base::PortInterface* writer = 0;
1374  ConnectionData::Ports::iterator p = connection->ports.begin();
1375 
1376  // If one of the ports is connected, use that one as writer to connect to.
1377  vector<OutputPortInterface*> writers;
1378  while (p !=connection->ports.end() ) {
1379  if ( OutputPortInterface* out = dynamic_cast<base::OutputPortInterface*>( *p ) ) {
1380  if ( writer ) {
1381  log(Info) << "Forming multi-output connections with additional OutputPort " << (*p)->getName() << "."<<endlog();
1382  } else
1383  writer = *p;
1384  writers.push_back( out );
1385  std::string owner = it->second.owners[p - it->second.ports.begin()]->getName();
1386  log(Info) << "Component "<< owner << "'s OutputPort "<< writer->getName()<< " will write topic "<<it->first<< endlog();
1387  }
1388  ++p;
1389  }
1390 
1391  // Inform the user of non-optimal connections:
1392  if ( writer == 0 ) {
1393  log(Error) << "No OutputPort listed that writes " << it->first << endlog();
1394  valid = false;
1395  break;
1396  }
1397 
1398  // connect all ports to writer
1399  p = connection->ports.begin();
1400  vector<OutputPortInterface*>::iterator w = writers.begin();
1401 
1402  while (w != writers.end() ) {
1403  while (p != connection->ports.end() ) {
1404  // connect all readers to the list of writers
1405  if ( dynamic_cast<base::InputPortInterface*>( *p ) )
1406  {
1407  string owner = connection->owners[p - connection->ports.begin()]->getName();
1408  // only try to connect p if it is not in the same connection of writer.
1409  // OK. p is definately no part of writer's connection. Try to connect and flag errors if it fails.
1410  if ( (*w)->connectTo( *p, connection->policy ) == false) {
1411  log(Error) << "Could not subscribe InputPort "<< owner<<"."<< (*p)->getName() << " to topic " << (*w)->getName() <<'/'<< connection_name <<endlog();
1412  valid = false;
1413  } else {
1414  log(Info) << "Subscribed InputPort "<< owner<<"."<< (*p)->getName() <<" to topic " << (*w)->getName() <<'/'<< connection_name <<endlog();
1415  }
1416  }
1417  ++p;
1418  }
1419  ++w;
1420  p = connection->ports.begin();
1421  }
1422  }
1423  return valid;
1424  }
1425 
1427  {
1428  RTT::Logger::In in("configureComponents");
1429  // do all groups
1430  bool valid = true;
1431  for (int group = 0; group <= nextGroup; ++group) {
1432  valid &= configureComponentsGroup(group);
1433  }
1434  return valid;
1435  }
1436 
1438  {
1439  RTT::Logger::In in("configureComponents");
1440  if ( root.empty() ) {
1442  << "No components loaded by DeploymentComponent !" <<endlog();
1443  return false;
1444  }
1445 
1446  bool valid = true;
1447  log(Info) << "Configuring components in group " << group << endlog();
1448 
1449  // Connect peers
1450  for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
1451 
1453 
1454  // only components in this group
1455  if (group != compmap[comp.getName()].group) {
1456  continue;
1457  }
1458 
1459  RTT::TaskContext* peer = compmap[comp.getName()].instance;
1460  if ( !peer ) {
1461  log(Error) << "Peer not found: "<< comp.getName() <<endlog();
1462  valid=false;
1463  continue;
1464  }
1465 
1466  compmap[comp.getName()].instance = peer;
1467 
1468  // Setup the connections from each component to the
1469  // others.
1470  RTT::Property<RTT::PropertyBag> peers = comp.rvalue().find("Peers");
1471  if ( peers.ready() )
1472  for (RTT::PropertyBag::const_iterator it= peers.rvalue().begin(); it != peers.rvalue().end();it++) {
1473  RTT::Property<string> nm = (*it);
1474  if ( nm.ready() )
1475  {
1476  if ( this->addPeer( compmap[comp.getName()].instance->getName(), nm.value() ) == false ) {
1477  log(Error) << this->getName() << " can't make " << nm.value() << " a peer of " <<
1478  compmap[comp.getName()].instance->getName() << endlog();
1479  valid = false;
1480  } else {
1481  log(Info) << this->getName() << " makes " << nm.value() << " a peer of " <<
1482  compmap[comp.getName()].instance->getName() << endlog();
1483  }
1484  }
1485  else {
1486  log(Error) << "Wrong property type in Peers struct. Expected property of type 'string',"
1487  << " got type "<< (*it)->getType() <<endlog();
1488  valid = false;
1489  }
1490  }
1491  }
1492 
1493  // Create data port connections:
1494  valid &= createDataPortConnections(true);
1495 
1496  // Autoconnect ports. The port name is the topic name.
1497  for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
1499  if ( !comp.ready() )
1500  continue;
1501 
1502  // only components in this group
1503  if (group != compmap[ comp.getName() ].group) {
1504  continue;
1505  }
1506 
1507  RTT::TaskContext* peer = compmap[ comp.getName() ].instance;
1508 
1509  // only autoconnect if AutoConnect == 1 and peer has AutoConnect == 1
1510  // There should only be one writer; more than one will lead to undefined behaviour.
1511  // reader<->reader connections will silently fail and be retried once a writer is found.
1512  if ( compmap[comp.getName()].autoconnect ) {
1513  // XXX/TODO This is broken: we should not rely on the peers to implement AutoConnect!
1514  RTT::TaskContext::PeerList peers = peer->getPeerList();
1515  for(RTT::TaskContext::PeerList::iterator pit = peers.begin(); pit != peers.end(); ++pit) {
1516  if ( compmap.count( *pit ) && compmap[*pit].autoconnect ) {
1517  RTT::TaskContext* other = peer->getPeer( *pit );
1518  valid = RTT::connectPorts( peer, other ) && valid;
1519  }
1520  }
1521  }
1522  }
1523 
1524  // Main configuration
1525  for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
1526 
1528 
1529  // only components in this group
1530  if (group != compmap[ comp.getName() ].group) {
1531  continue;
1532  }
1533 
1534  RTT::Property<string> dummy;
1535  RTT::TaskContext* peer = compmap[ comp.getName() ].instance;
1536 
1537  // do not configure when not stopped.
1538  if ( peer->getTaskState() > Stopped) {
1539  log(Warning) << "Component "<< peer->getName()<< " doesn't need to be configured (already Running)." <<endlog();
1540  continue;
1541  }
1542 
1543  // Check for default properties to set.
1544  for (RTT::PropertyBag::const_iterator pf = comp.rvalue().begin(); pf!= comp.rvalue().end(); ++pf) {
1545  // set PropFile name if present
1546  if ( (*pf)->getName() == "Properties"){
1547  RTT::Property<RTT::PropertyBag> props = *pf; // convert to type.
1548  bool ret = updateProperties( *peer->properties(), props);
1549  if (!ret) {
1550  log(Error) << "Failed to configure properties from main configuration file for component "<< comp.getName() <<endlog();
1551  valid = false;
1552  } else {
1553  log(Info) << "Configured Properties of "<< comp.getName() <<" from main configuration file." <<endlog();
1554  }
1555  }
1556  }
1557  // Load/update from property files.
1558  for (RTT::PropertyBag::const_iterator pf = comp.rvalue().begin(); pf!= comp.rvalue().end(); ++pf) {
1559  // set PropFile name if present
1560  if ( (*pf)->getName() == "PropertyFile" || (*pf)->getName() == "UpdateProperties" || (*pf)->getName() == "LoadProperties"){
1561  dummy = *pf; // convert to type.
1562  string filename = dummy.get();
1563  marsh::PropertyLoader pl(peer);
1564  bool strict = (*pf)->getName() == "PropertyFile" ? true : false;
1565  bool load = (*pf)->getName() == "LoadProperties" ? true : false;
1566  bool ret;
1567  if (!load)
1568  ret = pl.configure( filename, strict );
1569  else
1570  ret = pl.load(filename);
1571  if (!ret) {
1572  log(Error) << "Failed to configure properties for component "<< comp.getName() <<endlog();
1573  valid = false;
1574  } else {
1575  log(Info) << "Configured Properties of "<< comp.getName() << " from "<<filename<<endlog();
1576  compmap[ comp.getName() ].loadedProperties = true;
1577  }
1578  }
1579  }
1580 
1581  // Attach activities
1582  if ( compmap[comp.getName()].act ) {
1583  if ( peer->getActivity() ) {
1584  log(Info) << "Re-setting activity of "<< comp.getName() <<endlog();
1585  } else {
1586  log(Info) << "Setting activity of "<< comp.getName() <<endlog();
1587  }
1588  if (peer->setActivity( compmap[comp.getName()].act ) == false ) {
1589  valid = false;
1590  log(Error) << "Failed to set Activity of " << comp.getName() << endlog();
1591  } else {
1592  assert( peer->engine()->getActivity() == compmap[comp.getName()].act );
1593  compmap[comp.getName()].act = 0; // drops ownership.
1594  }
1595  }
1596 
1597  // Load scripts in order of appearance
1598  for (RTT::PropertyBag::const_iterator ps = comp.rvalue().begin(); ps!= comp.rvalue().end(); ++ps) {
1599  RTT::Property<string> script;
1600  if ( (*ps)->getName() == "RunScript" )
1601  script = *ps;
1602  if ( script.ready() ) {
1603  valid = valid && peer->getProvider<Scripting>("scripting")->runScript( script.get() );
1604  }
1605  // deprecated:
1606  RTT::Property<string> pscript;
1607  if ( (*ps)->getName() == "ProgramScript" )
1608  pscript = *ps;
1609  if ( pscript.ready() ) {
1610  valid = valid && peer->getProvider<Scripting>("scripting")->loadPrograms( pscript.get() );
1611  }
1612  RTT::Property<string> sscript;
1613  if ( (*ps)->getName() == "StateMachineScript" )
1614  sscript = *ps;
1615  if ( sscript.ready() ) {
1616  valid = valid && peer->getProvider<Scripting>("scripting")->loadStateMachines( sscript.get() );
1617  }
1618  }
1619 
1620  // AutoConf
1621  if (compmap[comp.getName()].autoconf )
1622  {
1623  if( !peer->isRunning() )
1624  {
1625  OperationCaller<bool(void)> peerconfigure = peer->getOperation("configure");
1626  if ( peerconfigure() == false) {
1627  log(Error) << "Component " << peer->getName() << " returns false in configure()" << endlog();
1628  valid = false;
1629  }
1630  }
1631  else
1632  log(Warning) << "Apparently component "<< peer->getName()<< " don't need to be configured (already Running)." <<endlog();
1633  }
1634 
1635  // scan for connection changes due to ports created in configure()
1636  valid &= createConnectionMapFromPortsTag(comp, peer, false);
1637 
1638  } // for root
1639 
1640  // Create data port connections for any newly created connections/ports.
1641  valid &= createDataPortConnections(false);
1642 
1643  // Finally, report success/failure (but ignore components that are actually running, as
1644  // they will have been configured/started previously)
1645  if (!valid) {
1646  for ( CompList::iterator cit = comps.begin(); cit != comps.end(); ++cit) {
1647  ComponentData* cd = &(compmap[*cit]);
1648  if ( group == cd->group && cd->loaded && cd->autoconf &&
1649  (cd->instance->getTaskState() != TaskCore::Stopped) &&
1650  (cd->instance->getTaskState() != TaskCore::Running))
1651  log(Error) << "Failed to configure component "<< cd->instance->getName()
1652  << ": state is " << cd->instance->getTaskState() <<endlog();
1653  }
1654  } else {
1655  log(Info) << "Configuration successful for group " << group << "." <<endlog();
1656  }
1657 
1658  validConfig.set(valid);
1659  return valid;
1660  }
1661 
1663  {
1664  // do all groups
1665  bool valid = true;
1666  for (int group = 0; group <= nextGroup; ++group) {
1667  valid &= startComponentsGroup(group);
1668  }
1669  return valid;
1670  }
1671 
1673  {
1674  RTT::Logger::In in("startComponentsGroup");
1675  if (validConfig.get() == false) {
1676  log(Error) << "Not starting components with invalid configuration." <<endlog();
1677  return false;
1678  }
1679  bool valid = true;
1680  for (RTT::PropertyBag::iterator it= root.begin(); it!=root.end();it++) {
1681 
1682  // only components in this group
1683  if (group != compmap[(*it)->getName()].group) {
1684  continue;
1685  }
1686 
1687  TaskContext* peer = compmap[(*it)->getName()].instance;
1688 
1689  // only start if not already running (peer may have been previously
1690  // loaded/configured/started from the site deployer file)
1691  if (peer->isRunning())
1692  {
1693  continue;
1694  }
1695 
1696  // AutoStart
1697  OperationCaller<bool(void)> peerstart = peer->getOperation("start");
1698  if (compmap[(*it)->getName()].autostart )
1699  if ( !peer || ( !peer->isRunning() && peerstart() == false) )
1700  valid = false;
1701  }
1702  // Finally, report success/failure:
1703  if (!valid) {
1704  for ( CompList::iterator cit = comps.begin(); cit != comps.end(); ++cit) {
1705  ComponentData* it = &(compmap[*cit]);
1706 
1707  // only components in this group
1708  if (group != it->group) {
1709  continue;
1710  }
1711 
1712  if ( it->instance == 0 ) {
1713  log(Error) << "Failed to start component "<< *cit << ": not found." << endlog();
1714  continue;
1715  }
1716  if ( it->autostart && it->instance->getTaskState() != base::TaskCore::Running )
1717  log(Error) << "Failed to start component "<< it->instance->getName() <<endlog();
1718  }
1719  } else {
1720  log(Info) << "Startup of 'AutoStart' components successful for group " << group << "." <<endlog();
1721  }
1722  return valid;
1723  }
1724 
1726  {
1727  // do all groups
1728  bool valid = true;
1729  for (int group = nextGroup ; group != -1; --group) {
1730  valid &= stopComponentsGroup(group);
1731  }
1732  return valid;
1733  }
1734 
1736  {
1737  RTT::Logger::In in("stopComponentsGroup");
1738  log(Info) << "Stopping group " << group << endlog();
1739  bool valid = true;
1740  // 1. Stop all activities, give components chance to cleanup.
1741  for ( CompList::reverse_iterator cit = comps.rbegin(); cit != comps.rend(); ++cit) {
1742  ComponentData* it = &(compmap[*cit]);
1743  if ( (group == it->group) && it->instance && !it->proxy ) {
1744  OperationCaller<bool(void)> instancestop = it->instance->getOperation("stop");
1745  if ( !it->instance->isRunning() ||
1746  instancestop() ) {
1747  log(Info) << "Stopped "<< it->instance->getName() <<endlog();
1748  } else {
1749  log(Error) << "Could not stop loaded Component "<< it->instance->getName() <<endlog();
1750  valid = false;
1751  }
1752  }
1753  }
1754  return valid;
1755  }
1756 
1758  {
1759  // do all groups
1760  bool valid = true;
1761  for (int group = nextGroup ; group != -1; --group) {
1762  valid &= cleanupComponentsGroup(group);
1763  }
1764  return valid;
1765  }
1766 
1768  {
1769  RTT::Logger::In in("cleanupComponentsGroup");
1770  bool valid = true;
1771  log(Info) << "Cleaning up group " << group << endlog();
1772  // 1. Cleanup all activities, give components chance to cleanup.
1773  for ( CompList::reverse_iterator cit = comps.rbegin(); cit != comps.rend(); ++cit) {
1774  ComponentData* it = &(compmap[*cit]);
1775 
1776  // only components in this group
1777  if (group != it->group) {
1778  continue;
1779  }
1780 
1781  if (it->instance && !it->proxy) {
1782  if ( it->instance->getTaskState() <= base::TaskCore::Stopped ) {
1783  if ( it->autosave && !it->configfile.empty()) {
1784  if (it->loadedProperties) {
1785  string file = it->configfile; // get file name
1786  PropertyLoader pl(it->instance);
1787  bool ret = pl.save( file, true ); // save all !
1788  if (!ret) {
1789  log(Error) << "Failed to save properties for component "<< it->instance->getName() <<endlog();
1790  valid = false;
1791  } else {
1792  log(Info) << "Refusing to save property file that was not loaded for "<< it->instance->getName() <<endlog();
1793  }
1794  } else if (it->autosave) {
1795  log(Error) << "AutoSave set but no property file specified. Specify one using the UpdateProperties simple element."<<endlog();
1796  }
1797  } else if (it->autosave) {
1798  log(Error) << "AutoSave set but no property file specified. Specify one using the UpdateProperties simple element."<<endlog();
1799  }
1800  OperationCaller<bool(void)> instancecleanup = it->instance->getOperation("cleanup");
1801  instancecleanup();
1802  log(Info) << "Cleaned up "<< it->instance->getName() <<endlog();
1803  } else {
1804  log(Error) << "Could not cleanup Component "<< it->instance->getName() << " (not Stopped)"<<endlog();
1805  valid = false;
1806  }
1807  }
1808  }
1809  return valid;
1810  }
1811 
1813  {
1814  // do all groups
1815  bool valid = true;
1816  for (int group = nextGroup ; group != -1; --group) {
1817  valid &= unloadComponentsGroup(group);
1818  }
1819  return valid;
1820  }
1821 
1823  {
1824  log(Info) << "Unloading group " << group << endlog();
1825  // 2. Disconnect and destroy all components in group
1826  bool valid = true;
1827  CompList::reverse_iterator cit = comps.rbegin();
1828  while ( valid && cit != comps.rend())
1829  {
1830  ComponentData* it = &(compmap[*cit]);
1831  if (group == it->group)
1832  {
1833  // this call modifies comps
1834  valid &= this->unloadComponentImpl(compmap.find(*cit));
1835  // so restart search
1836  cit = comps.rbegin();
1837  }
1838  else
1839  {
1840  ++cit;
1841  }
1842  }
1843 
1844 
1845  return valid;
1846  }
1847 
1849  {
1850  log(Info) << "Clearing configuration options."<< endlog();
1851  conmap.clear();
1853  }
1854 
1855  bool DeploymentComponent::import(const std::string& package)
1856  {
1857  RTT::Logger::In in("import");
1858  return ComponentLoader::Instance()->import( package, "" ); // search in existing search paths
1859  }
1860 
1861  void DeploymentComponent::path(const std::string& path)
1862  {
1863  RTT::Logger::In in("path");
1864  ComponentLoader::Instance()->setComponentPath( ComponentLoader::Instance()->getComponentPath() + path );
1865  PluginLoader::Instance()->setPluginPath( PluginLoader::Instance()->getPluginPath() + path );
1866  }
1867 
1868  bool DeploymentComponent::loadLibrary(const std::string& name)
1869  {
1870  RTT::Logger::In in("loadLibrary");
1871  return PluginLoader::Instance()->loadLibrary(name) || ComponentLoader::Instance()->loadLibrary(name);
1872  }
1873 
1874  bool DeploymentComponent::reloadLibrary(const std::string& name)
1875  {
1876  RTT::Logger::In in("reloadLibrary");
1877  return ComponentLoader::Instance()->reloadLibrary(name);
1878  }
1879 
1880  bool DeploymentComponent::loadService(const std::string& name, const std::string& type) {
1881  TaskContext* peer = 0;
1882  if ((name == getName()) || (name == "this"))
1883  peer = this;
1884  else if ( (peer = getPeer(name)) == 0) {
1885  log(Error)<<"No such peer: "<< name<< ". Can not load service '"<<type<<"'."<<endlog();
1886  return false;
1887  }
1888  // note: in case the service is not exposed as a 'service' object with the same name,
1889  // we can not detect double loads. So this check is flaky.
1890  if (peer->provides()->hasService(type))
1891  return true;
1892  return PluginLoader::Instance()->loadService(type, peer);
1893  }
1894 
1895  // or type is a shared library or it is a class type.
1896  bool DeploymentComponent::loadComponent(const std::string& name, const std::string& type)
1897  {
1898  RTT::Logger::In in("loadComponent");
1899 
1900  if ( type == "RTT::PropertyBag" )
1901  return false; // It should be present as peer.
1902 
1903  if ( this->getPeer(name) || ( compmap.find(name) != compmap.end() && compmap[name].instance != 0) ) {
1904  log(Error) <<"Failed to load component with name "<<name<<": already present as peer or loaded."<<endlog();
1905  return false;
1906  }
1907 
1908  TaskContext* instance = ComponentLoader::Instance()->loadComponent(name, type);
1909 
1910  if (!instance) {
1911  return false;
1912  }
1913 
1914  // we need to set instance such that componentLoaded can lookup 'instance' in 'comps'
1915  compmap[name].instance = instance;
1916  comps.push_back(name);
1917 
1918  if (!this->componentLoaded( instance ) ) {
1919  log(Error) << "This deployer type refused to connect to "<< instance->getName() << ": aborting !" << endlog(Error);
1920  compmap[name].instance = 0;
1921  ComponentLoader::Instance()->unloadComponent( instance );
1922  return false;
1923  }
1924 
1925  // unlikely that this fails (checked at entry)!
1926  this->addPeer( instance, name );
1927  log(Info) << "Adding "<< name << " as new peer: OK."<< endlog(Info);
1928 
1929  compmap[name].loaded = true;
1930 
1931  return true;
1932  }
1933 
1938  bool DeploymentComponent::unloadComponentImpl( CompMap::iterator cit )
1939  {
1940  bool valid = true;
1941  ComponentData* it = &(cit->second);
1942  std::string name = cit->first;
1943 
1944  if ( it->loaded && it->instance ) {
1945  if ( !it->instance->isRunning() ) {
1946  if (!it->proxy ) {
1947  // allow subclasses to do cleanup too.
1948  componentUnloaded( it->instance );
1949  log(Debug) << "Disconnecting " <<name <<endlog();
1950  it->instance->disconnect();
1951  log(Debug) << "Terminating " <<name <<endlog();
1952  } else
1953  log(Debug) << "Removing proxy for " <<name <<endlog();
1954 
1955  // Lookup and erase port+owner from conmap.
1956  for( ConMap::iterator cmit = conmap.begin(); cmit != conmap.end(); ++cmit) {
1957  size_t n = 0;
1958  while ( n != cmit->second.owners.size() ) {
1959  if (cmit->second.owners[n] == it->instance ) {
1960  cmit->second.owners.erase( cmit->second.owners.begin() + n );
1961  cmit->second.ports.erase( cmit->second.ports.begin() + n );
1962  n = 0;
1963  } else
1964  ++n;
1965  }
1966  }
1967  // Lookup in the property configuration and remove:
1969  if (pcomp) {
1970  root.removeProperty(pcomp);
1971  }
1972 
1973  // Finally, delete the activity before the TC !
1974  delete it->act;
1975  it->act = 0;
1976  ComponentLoader::Instance()->unloadComponent( it->instance );
1977  it->instance = 0;
1978  log(Info) << "Disconnected and destroyed "<< name <<endlog();
1979  } else {
1980  log(Error) << "Could not unload Component "<< name <<": still running." <<endlog();
1981  valid=false;
1982  }
1983  }
1984  if (valid) {
1985  // NOTE there is no reason to keep the ComponentData in the vector.
1986  // actually it may cause errors if we try to re-load the Component later.
1987  compmap.erase(cit);
1988  CompList::iterator it = comps.begin();
1989  while(it != comps.end()) {
1990  if (*it == name)
1991  it = comps.erase(it);
1992  else
1993  ++it;
1994  }
1995  }
1996  return valid;
1997  }
1998 
1999  bool DeploymentComponent::unloadComponent(const std::string& name)
2000  {
2001  CompMap::iterator it;
2002  // no such peer: try looking for the map name
2003  if ( compmap.count( name ) == 0 || compmap[name].loaded == false ) {
2004  log(Error) << "Can't unload component '"<<name<<"': not loaded by "<<this->getName()<<endlog();
2005  return false;
2006  }
2007 
2008  // Ok. Go on with loaded component.
2009  it = compmap.find(name);
2010 
2011  if ( this->unloadComponentImpl( it ) == false )
2012  return false;
2013 
2014  log(Info) << "Successfully unloaded component "<<name<<"."<<endlog();
2015  return true;
2016  }
2017 
2019  {
2020  FactoryMap::const_iterator it;
2021  cout << "I can create the following component types: " <<endl;
2022  for(it = getFactories().begin(); it != getFactories().end(); ++it) {
2023  cout << " " << it->first << endl;
2024  }
2025  if ( getFactories().size() == 0 )
2026  cout << " (none)"<<endl;
2027  }
2028 
2029  std::vector<std::string> DeploymentComponent::getComponentTypes() const
2030  {
2031  std::vector<std::string> s;
2032  FactoryMap::const_iterator it;
2033  for(it = getFactories().begin(); it != getFactories().end(); ++it)
2034  s.push_back(it->first);
2035 
2036  return s;
2037  }
2038 
2039  bool DeploymentComponent::setActivity(const std::string& comp_name,
2040  double period, int priority,
2041  int scheduler)
2042  {
2043  if ( this->setNamedActivity(comp_name, "Activity", period, priority, scheduler) ) {
2044  assert( compmap[comp_name].instance );
2045  assert( compmap[comp_name].act );
2046  compmap[comp_name].instance->setActivity( compmap[comp_name].act );
2047  compmap[comp_name].act = 0;
2048  return true;
2049  }
2050  return false;
2051  }
2052 
2053  bool DeploymentComponent::setFileDescriptorActivity(const std::string& comp_name,
2054  double timeout, int priority,
2055  int scheduler)
2056  {
2057  if ( this->setNamedActivity(comp_name, "FileDescriptorActivity", timeout, priority, scheduler) ) {
2058  assert( compmap[comp_name].instance );
2059  assert( compmap[comp_name].act );
2060  compmap[comp_name].instance->setActivity( compmap[comp_name].act );
2061  compmap[comp_name].act = 0;
2062  return true;
2063  }
2064  return false;
2065  }
2066 
2067  bool DeploymentComponent::setActivityOnCPU(const std::string& comp_name,
2068  double period, int priority,
2069  int scheduler, unsigned int cpu_nr)
2070  {
2071  unsigned int mask = 0x1 << cpu_nr;
2072  if ( this->setNamedActivity(comp_name, "Activity", period, priority, scheduler, mask) ) {
2073  assert( compmap[comp_name].instance );
2074  assert( compmap[comp_name].act );
2075  compmap[comp_name].instance->setActivity( compmap[comp_name].act );
2076  compmap[comp_name].act = 0;
2077  return true;
2078  }
2079  return false;
2080  }
2081 
2082  bool DeploymentComponent::setPeriodicActivity(const std::string& comp_name,
2083  double period, int priority,
2084  int scheduler)
2085  {
2086  if ( this->setNamedActivity(comp_name, "PeriodicActivity", period, priority, scheduler) ) {
2087  assert( compmap[comp_name].instance );
2088  assert( compmap[comp_name].act );
2089  compmap[comp_name].instance->setActivity( compmap[comp_name].act );
2090  compmap[comp_name].act = 0;
2091  return true;
2092  }
2093  return false;
2094  }
2095 
2096  bool DeploymentComponent::setSlaveActivity(const std::string& comp_name,
2097  double period)
2098  {
2099  if ( this->setNamedActivity(comp_name, "SlaveActivity", period, 0, ORO_SCHED_OTHER ) ) {
2100  assert( compmap[comp_name].instance );
2101  assert( compmap[comp_name].act );
2102  compmap[comp_name].instance->setActivity( compmap[comp_name].act );
2103  compmap[comp_name].act = 0;
2104  return true;
2105  }
2106  return false;
2107  }
2108 
2109  bool DeploymentComponent::setSequentialActivity(const std::string& comp_name)
2110  {
2111  if ( this->setNamedActivity(comp_name, "SequentialActivity", 0, 0, 0 ) ) {
2112  assert( compmap[comp_name].instance );
2113  assert( compmap[comp_name].act );
2114  compmap[comp_name].instance->setActivity( compmap[comp_name].act );
2115  compmap[comp_name].act = 0;
2116  return true;
2117  }
2118  return false;
2119  }
2120 
2121  bool DeploymentComponent::setMasterSlaveActivity(const std::string& master,
2122  const std::string& slave)
2123  {
2124  if ( this->setNamedActivity(slave, "SlaveActivity", 0, 0, ORO_SCHED_OTHER, master ) ) {
2125  assert( compmap[slave].instance );
2126  assert( compmap[slave].act );
2127  compmap[slave].instance->setActivity( compmap[slave].act );
2128  compmap[slave].act = 0;
2129  return true;
2130  }
2131  return false;
2132  }
2133 
2134 
2135  bool DeploymentComponent::setNamedActivity(const std::string& comp_name,
2136  const std::string& act_type,
2137  double period, int priority,
2138  int scheduler, const std::string& master_name)
2139  {
2140  return setNamedActivity(comp_name,
2141  act_type,
2142  period,
2143  priority,
2144  scheduler,
2145  ~0, // cpu_affinity == all CPUs
2146  master_name);
2147  }
2148 
2149  bool DeploymentComponent::setNamedActivity(const std::string& comp_name,
2150  const std::string& act_type,
2151  double period, int priority,
2152  int scheduler, unsigned cpu_affinity,
2153  const std::string& master_name)
2154  {
2155  // This helper function does not actualy set the activity, it just creates it and
2156  // stores it in compmap[comp_name].act
2157  RTT::TaskContext* peer = 0;
2158  base::ActivityInterface* master_act = 0;
2159  if ( comp_name == "this" || comp_name == this->getName() )
2160  peer = this;
2161  else
2162  if ( compmap.count(comp_name) )
2163  peer = compmap[comp_name].instance;
2164  else
2165  peer = this->getPeer(comp_name); // last resort.
2166  if (!peer) {
2167  log(Error) << "Can't create Activity: component "<<comp_name<<" not found."<<endlog();
2168  return false;
2169  }
2170  if ( !master_name.empty() ) {
2171  if ( master_name == "this" || master_name == this->getName() )
2172  master_act = this->engine()->getActivity();
2173  else
2174  if ( compmap.count(master_name) && compmap[master_name].act )
2175  master_act = compmap[master_name].act;
2176  else
2177  master_act = this->getPeer(master_name) ? getPeer(master_name)->engine()->getActivity() : 0; // last resort.
2178 
2179  if ( !this->getPeer(master_name) ) {
2180  log(Error) << "Can't create SlaveActivity: Master component "<<master_name<<" not known as peer."<<endlog();
2181  return false;
2182  }
2183 
2184  if (!master_act) {
2185  log(Error) << "Can't create SlaveActivity: Master component "<<master_name<<" has no activity set."<<endlog();
2186  return false;
2187  }
2188  }
2189  // this is required for lateron attaching the engine()
2190  compmap[comp_name].instance = peer;
2191  if ( peer->isRunning() ) {
2192  log(Error) << "Can't change activity of component "<<comp_name<<" since it is still running."<<endlog();
2193  return false;
2194  }
2195 
2196  base::ActivityInterface* newact = 0;
2197  // standard case:
2198  if ( act_type == "Activity")
2199  newact = new RTT::Activity(scheduler, priority, period, cpu_affinity, 0, comp_name);
2200  else
2201  // special cases:
2202  if ( act_type == "PeriodicActivity" && period != 0.0)
2203  // WARNING RTT::PeriodicActivity does not support a name!
2204  newact = new RTT::extras::PeriodicActivity(scheduler, priority, period, cpu_affinity, 0);
2205  else
2206  if ( act_type == "NonPeriodicActivity" && period == 0.0)
2207  newact = new RTT::Activity(scheduler, priority, period, cpu_affinity, 0, comp_name);
2208  else
2209  if ( act_type == "SlaveActivity" ) {
2210  if ( master_act == 0 )
2211  newact = new extras::SlaveActivity(period);
2212  else {
2213  newact = new extras::SlaveActivity(master_act);
2214  this->getPeer(master_name)->addPeer( peer );
2215  }
2216  }
2217  else
2218  if (act_type == "Activity") {
2219  newact = new Activity(scheduler, priority, period, cpu_affinity, 0, comp_name);
2220  }
2221  else
2222  if (act_type == "SequentialActivity") {
2223  newact = new SequentialActivity();
2224  }
2225  else if ( act_type == "FileDescriptorActivity") {
2226  using namespace RTT::extras;
2227  newact = new FileDescriptorActivity(scheduler, priority, period, cpu_affinity, 0, comp_name);
2228  FileDescriptorActivity* fdact = dynamic_cast< RTT::extras::FileDescriptorActivity* > (newact);
2229  if (fdact) fdact->setTimeout(period);
2230  else newact = 0;
2231  }
2232  if (newact == 0) {
2233  log(Error) << "Can't create '"<< act_type << "' for component "<<comp_name<<": incorrect arguments."<<endlog();
2234  return false;
2235  }
2236 
2237  // assign default wait period policy to newly created activity
2239 
2240  // this must never happen if component is running:
2241  assert( peer->isRunning() == false );
2242  delete compmap[comp_name].act;
2243  compmap[comp_name].act = newact;
2244 
2245  return true;
2246  }
2247 
2248  bool DeploymentComponent::setWaitPeriodPolicy(const std::string& comp_name, int policy)
2249  {
2250  if ( !compmap.count(comp_name) ) {
2251  log(Error) << "Can't setWaitPeriodPolicy: component "<<comp_name<<" not found."<<endlog();
2252  return false;
2253  }
2254 
2255  RTT::base::ActivityInterface *activity = compmap[comp_name].instance->getActivity();
2256  if ( !activity ) {
2257  log(Error) << "Can't setWaitPeriodPolicy: component "<<comp_name<<" has no activity (yet)."<<endlog();
2258  return false;
2259  }
2260 
2261  activity->thread()->setWaitPeriodPolicy(policy);
2262  return true;
2263  }
2264 
2265  bool DeploymentComponent::configure(const std::string& name)
2266  {
2267  return configureFromFile( name, name + ".cpf" );
2268  }
2269 
2270  bool DeploymentComponent::configureFromFile(const std::string& name, const std::string& filename)
2271  {
2272  RTT::Logger::In in("DeploymentComponent");
2273  RTT::TaskContext* c;
2274  if ( name == "this" || name == this->getName() )
2275  c = this;
2276  else
2277  c = this->getPeer(name);
2278  if (!c) {
2279  log(Error)<<"No such peer to configure: "<<name<<endlog();
2280  return false;
2281  }
2282 
2283  marsh::PropertyLoader pl(c);
2284  return pl.configure( filename, true ); // strict:true
2285  }
2286 
2288  {
2289  return RTT::ComponentLoader::Instance()->getFactories();
2290  }
2291 
2292  void DeploymentComponent::kickOut(const std::string& config_file)
2293  {
2294  RTT::Logger::In in("kickOut");
2295  RTT::PropertyBag from_file;
2296  RTT::Property<std::string> import_file;
2297  std::vector<std::string> deleted_components_type;
2298 
2299  marsh::PropertyDemarshaller demarshaller(config_file);
2300  try {
2301  if ( demarshaller.deserialize( from_file ) ){
2302  for (RTT::PropertyBag::iterator it= from_file.begin(); it!=from_file.end();it++) {
2303  if ( (*it)->getName() == "Import" ) continue;
2304  if ( (*it)->getName() == "Include" ) continue;
2305 
2306  kickOutComponent( (*it)->getName() );
2307  }
2308  deletePropertyBag( from_file );
2309  }
2310  else {
2311  log(Error)<< "Some error occured while parsing "<< config_file <<endlog();
2312  }
2313  } catch (...)
2314  {
2315  log(Error)<< "Uncaught exception in kickOut() !"<< endlog();
2316  }
2317  }
2318 
2320  {
2321  RTT::Logger::In in("cleanupComponent");
2322  bool valid = true;
2323  // 1. Cleanup a single activities, give components chance to cleanup.
2324  if (instance) {
2325  if ( instance->getTaskState() <= base::TaskCore::Stopped ) {
2326  OperationCaller<bool(void)> instancecleanup = instance->getOperation("cleanup");
2327  instancecleanup();
2328  log(Info) << "Cleaned up "<< instance->getName() <<endlog();
2329  } else {
2330  log(Error) << "Could not cleanup Component "<< instance->getName() << " (not Stopped)"<<endlog();
2331  valid = false;
2332  }
2333  }
2334  return valid;
2335  }
2336 
2338  {
2339  RTT::Logger::In in("configureComponent");
2340  bool valid = false;
2341 
2342  if ( instance ) {
2343  OperationCaller<bool(void)> instanceconfigure = instance->getOperation("configure");
2344  if(instanceconfigure()) {
2345  log(Info) << "Configured " << instance->getName()<<endlog();
2346  valid = true;
2347  }
2348  else {
2349  log(Error) << "Could not configure loaded Component "<< instance->getName() <<endlog();
2350  }
2351  }
2352  return valid;
2353  }
2354 
2356  {
2357  RTT::Logger::In in("startComponent");
2358  bool valid = false;
2359 
2360  if ( instance ) {
2361  OperationCaller<bool(void)> instancestart = instance->getOperation("start");
2362  if ( instance->isRunning() ||
2363  instancestart() ) {
2364  log(Info) << "Started "<< instance->getName() <<endlog();
2365  valid = true;
2366  }
2367  else {
2368  log(Error) << "Could not start loaded Component "<< instance->getName() <<endlog();
2369  }
2370  }
2371  return valid;
2372  }
2373 
2375  {
2376  RTT::Logger::In in("stopComponent");
2377  bool valid = true;
2378 
2379  if ( instance ) {
2380  OperationCaller<bool(void)> instancestop = instance->getOperation("stop");
2381  if ( !instance->isRunning() ||
2382  instancestop() ) {
2383  log(Info) << "Stopped "<< instance->getName() <<endlog();
2384  }
2385  else {
2386  log(Error) << "Could not stop loaded Component "<< instance->getName() <<endlog();
2387  valid = false;
2388  }
2389  }
2390  return valid;
2391  }
2392 
2393  bool DeploymentComponent::kickOutComponent(const std::string& comp_name)
2394  {
2395  RTT::Logger::In in("kickOutComponent");
2396 
2397  RTT::TaskContext* peer = compmap.count(comp_name) ? compmap[ comp_name ].instance : 0;
2398 
2399  if ( !peer ) {
2400  log(Error) << "Component not loaded by this Deployer: "<< comp_name <<endlog();
2401  return false;
2402  }
2403  stopComponent( peer );
2404  cleanupComponent (peer );
2405  unloadComponent( comp_name);
2406 
2407  // also remove from XML if present:
2408  root.removeProperty( root.find( comp_name ) );
2409 
2410  return true;
2411  }
2412 
2414  {
2415  static const char* PEER="Application";
2416  static const char* NAME="shutdownDeployment";
2417 
2418  // names of override properties
2419  static const char* WAIT_PROP_NAME="shutdownWait_ms";
2420  static const char* TOTAL_WAIT_PROP_NAME="shutdownTotalWait_ms";
2421 
2423  bool has_program = false;
2424  bool has_operation = false;
2425  // if have operation named NAME in peer PEER then use that one.
2426  RTT::TaskContext* peer = getPeer(PEER);
2427  if ( 0 != peer){
2428  has_operation = peer->provides()->hasOperation(NAME);
2429  if(has_operation)
2430  ds = peer->provides()->getOperation(NAME);
2431  } else {
2432  log(Info) << "Ignoring deployment shutdown function due to missing peer." << endlog();
2433  return;
2434  }
2435  //If no such operation is found, check if we have a shutdown program?
2436  if (!ds.ready()){
2437  has_operation = false;
2438  log(Info) << "Ignoring deployment shutdown function, looking for shutdown program script." << endlog();
2439  has_program = peer->getProvider<Scripting>("scripting")->hasProgram(NAME);
2440  }
2441  //Only continue if we have a shutdown operation or program script
2442  if (has_operation || has_program)
2443  {
2444  log(Info) << "Shutting down deployment." << endlog();
2446  if(has_operation)
2447  handle = ds.send();
2448  if (handle.ready() || peer->getProvider<Scripting>("scripting")->startProgram(NAME))
2449  {
2450  // set defaults
2451 
2452  // number milliseconds to wait in between completion checks
2453  int wait = 50;
2454  // total number milliseconds to wait for completion
2455  int totalWait = 2000;
2456 
2457  // any overrides?
2458  RTT::Property<int> wait_prop =
2459  this->properties()->getProperty(WAIT_PROP_NAME);
2460  if (wait_prop.ready())
2461  {
2462  int w = wait_prop.rvalue();
2463  if (0 < w)
2464  {
2465  wait = w;
2466  log(Debug) << "Using override value for " << WAIT_PROP_NAME << endlog();
2467  }
2468  else
2469  {
2470  log(Warning) << "Ignoring illegal value for " << WAIT_PROP_NAME << endlog();
2471  }
2472  }
2473  else
2474  {
2475  log(Debug) << "Using default value for " << WAIT_PROP_NAME << endlog();
2476  }
2477 
2478  RTT::Property<int> totalWait_prop =
2479  this->properties()->getProperty(TOTAL_WAIT_PROP_NAME);
2480  if (totalWait_prop.ready())
2481  {
2482  int w = totalWait_prop.rvalue();
2483  if (0 < w)
2484  {
2485  totalWait = w;
2486  log(Debug) << "Using override value for " << TOTAL_WAIT_PROP_NAME << endlog();
2487  }
2488  else
2489  {
2490  log(Warning) << "Ignoring illegal value for " << TOTAL_WAIT_PROP_NAME << endlog();
2491  }
2492  }
2493  else
2494  {
2495  log(Debug) << "Using default value for " << TOTAL_WAIT_PROP_NAME << endlog();
2496  }
2497 
2498  // enforce constraints
2499  if (wait > totalWait)
2500  {
2501  wait = totalWait;
2502  log(Warning) << "Setting wait == totalWait" << endlog();
2503  }
2504 
2505  const long int wait_ns = wait * 1000000LL;
2506  TIME_SPEC ts;
2507  ts.tv_sec = wait_ns / 1000000000LL;
2508  ts.tv_nsec = wait_ns % 1000000000LL;
2509 
2510  // wait till done or timed out
2511  log(Debug) << "Waiting for deployment shutdown to complete ..." << endlog();
2512  int waited = 0;
2513  while ( ( (has_operation && RTT::SendNotReady == handle.collectIfDone() ) ||
2514  (has_program && peer->getProvider<Scripting>("scripting")->isProgramRunning(NAME)) )
2515  && (waited < totalWait) )
2516  {
2517  (void)rtos_nanosleep(&ts, NULL);
2518  waited += wait;
2519  }
2520  if (waited >= totalWait)
2521  {
2522  log(Error) << "Timed out waiting for deployment shutdown to complete." << endlog();
2523  }
2524  else
2525  {
2526  log(Debug) << "Deployment shutdown completed." << endlog();
2527  }
2528  }
2529  else
2530  {
2531  log(Error) << "Failed to start operation or scripting program: " << NAME << endlog();
2532  }
2533 
2534  }
2535  else
2536  {
2537  log(Info) << "No deployment shutdown function or program available." << endlog();
2538  }
2539  }
2540 
2541 }
RTT::Constant< int > lowest_Priority
static int got_signal
static std::set< string > valid_names
Property< T > & addProperty(const std::string &name, T &attr)
bool kickStart2(const std::string &configurationfile, const bool doStart, bool &loadOk, bool &configureOk, bool &startOk)
bool unloadComponent(const std::string &name)
#define ORO_str(s)
DataSourceType get() const
virtual bool setImplementation(boost::shared_ptr< base::DisposableInterface > impl, ExecutionEngine *caller=0)=0
bool createConnectionMapFromPortsTag(RTT::Property< RTT::PropertyBag > &comp, RTT::TaskContext *c, const bool ignoreNonexistentPorts)
iterator end()
bool updateProperty(PropertyBag &target, const PropertyBag &source, const std::string &name, const std::string &separator)
RTT::Constant< int > highest_Priority
bool configureComponentsGroup(const int group)
ServiceRequester::shared_ptr stringToServiceRequester(std::string const &names)
Property< T > * getPropertyType(const std::string &name) const
const RTT::FactoryMap & getFactories() const
bool updateProperties(PropertyBag &target, const PropertyBag &source)
Service::shared_ptr provides()
#define ORO_WAIT_ABS
bool setSlaveActivity(const std::string &comp_name, double period)
ActivityInterface * getActivity() const
RTT::Attribute< std::string > target
Service::shared_ptr stringToService(std::string const &names)
bool aliasPeer(const std::string &from, const std::string &target, const std::string &alias)
bool configure(const std::string &filename, bool all=true) const
bool createStream(const std::string &component, const std::string &port, ConnPolicy policy)
bool ready() const
int group
Group number this component belongs to.
DeploymentComponent(std::string name="Deployer", std::string siteFile="")
int rtos_nanosleep(const TIME_SPEC *rqtp, TIME_SPEC *rmtp)
static shared_ptr Instance()
virtual void componentUnloaded(RTT::TaskContext *c)
bool setActivityOnCPU(const std::string &comp_name, double period, int priority, int scheduler, unsigned int cpu_nr)
bool setActivity(const std::string &comp_name, double period, int priority, int scheduler)
bool waitForSignals(int *sigs, std::size_t sig_count)
bool connectPorts(const std::string &one, const std::string &other)
bool load(const std::string &filename) const
void set(T const &t)
RTT::Attribute< bool > validConfig
boost::shared_ptr< ServiceRequester > shared_ptr
const std::string & getName() const
bool setMasterSlaveActivity(const std::string &comp_name, const std::string &master_name)
int string_to_oro_sched(const std::string &sched)
virtual bool connectPeers(TaskContext *peer)
bool import(const std::string &package)
virtual void removePeer(const std::string &name)
RTT::Constant< int > sched_OTHER
const_reference_t rvalue() const
base::PortInterface * stringToPort(std::string const &names)
static boost::shared_ptr< ComponentLoader > Instance()
T const & get() const
virtual bool componentLoaded(RTT::TaskContext *c)
bool connectPeers(const std::string &one, const std::string &other)
RTT::Property< bool > autoUnload
std::vector< std::string > getComponentTypes() const
virtual bool isRunning() const
virtual bool configure()
bool setActivity(base::ActivityInterface *new_act)
std::map< std::string, ComponentLoaderSignature > FactoryMap
bool createDataPortConnections(const bool skipUnconnected)
reference_t value()
virtual TaskContext * getPeer(const std::string &peer_name) const
virtual bool deserialize(PropertyBag &v)
bool startComponent(RTT::TaskContext *instance)
boost::shared_ptr< Service > shared_ptr
bool stopComponentsGroup(const int group)
Critical
bool startComponentsGroup(const int group)
bool cleanupComponentsGroup(const int group)
virtual bool hasPeer(const std::string &peer_name) const
bool save(const std::string &filename, bool all=true) const
ServiceRequester::shared_ptr requires()
bool connectOperations(const std::string &required, const std::string &provided)
OperationCaller< bool(const std::string &)> isProgramRunning
const int HighestPriority
bool reloadLibrary(const std::string &filepath)
printstream cout
void deletePropertyBag(PropertyBag &target)
virtual void disconnect()
DataFlowInterface * ports()
bool addPeer(const std::string &from, const std::string &target)
base::PortInterface * getPort(const std::string &name) const
virtual PeerList getPeerList() const
bool setWaitPeriodPolicy(const std::string &comp_name, int policy)
base::PropertyBase * find(const std::string &name) const
bool loadConfiguration(const std::string &config_file)
void kickOut(const std::string &config_file)
bool kickStart(const std::string &file_name)
bool removeProperty(base::PropertyBase *p)
std::vector< std::string > PeerList
rt_allocator< U > other
bool setPeriodicActivity(const std::string &comp_name, double period, int priority, int scheduler)
Debug
bool loadLibrary(const std::string &name)
bool addAttribute(const std::string &name, T &attr)
bool unloadComponentsGroup(const int group)
Properties::const_iterator const_iterator
basic_ostreams & endl(basic_ostreams &s)
bool empty() const
virtual TaskState getTaskState() const
bool configureComponent(RTT::TaskContext *instance)
Error
bool configureFromFile(const std::string &name, const std::string &filename)
Info
base::PropertyBase * getProperty(const std::string &name) const
bool setSequentialActivity(const std::string &comp_name)
bool setFileDescriptorActivity(const std::string &comp_name, double timeout, int priority, int scheduler)
PropertyBag * properties()
bool loadService(const std::string &component, const std::string &service)
RTT::Constant< int > sched_RT
virtual os::ThreadInterface * thread()=0
Warning
OperationInterfacePart * getOperation(std::string name)
SendNotReady
bool loadComponent(const std::string &name, const std::string &type)
static Logger & log()
bool kickOutComponent(const std::string &comp_name)
bool connect(const std::string &one, const std::string &other, ConnPolicy policy)
virtual bool connectTo(PortInterface *other, ConnPolicy const &policy)=0
static ConnPolicy & Default()
const std::string & getName() const
bool setNamedActivity(const std::string &comp_name, const std::string &act_type, double period, int priority, int scheduler, const std::string &master_name="")
virtual bool connectPorts(TaskContext *peer)
static boost::shared_ptr< PluginLoader > Instance()
const int LowestPriority
#define ORO_SCHED_RT
virtual bool createStream(ConnPolicy const &policy)=0
bool kickOutGroup(const int group)
bool loadComponents(const std::string &config_file)
bool connectPorts(TaskContext *A, TaskContext *B)
Properties::iterator iterator
virtual bool connectServices(TaskContext *peer)
bool unloadComponentImpl(CompMap::iterator cit)
bool runScript(const std::string &file_name)
bool waitForSignal(int signumber)
virtual bool connected() const =0
bool stream(const std::string &port, ConnPolicy policy)
std::string name_id
virtual void setWaitPeriodPolicy(int p)=0
Operation< Signature > & addOperation(Operation< Signature > &op)
struct timespec TIME_SPEC
static Logger & log()
bool loadConfigurationString(const std::string &config_text)
bool ready() const
bool loadComponentsInGroup(const std::string &config_file, const int group)
ClientThread
bool stopComponent(RTT::TaskContext *instance)
#define ORO_SCHED_OTHER
const ExecutionEngine * engine() const
int nextGroup
Next group number.
bool connectServices(const std::string &one, const std::string &other)
static Logger::LogFunction endlog()
bool cleanupComponent(RTT::TaskContext *instance)
virtual bool addPeer(TaskContext *peer, std::string alias="")
base::ActivityInterface * getActivity()
virtual const std::string & getName() const
iterator begin()
void path(const std::string &path)
boost::shared_ptr< ServiceType > getProvider(const std::string &name)


ocl
Author(s): OCL Development Team
autogenerated on Wed Jun 26 2019 19:26:27