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