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