Orocos Real-Time Toolkit  2.8.3
ScriptingService.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Mon Jun 26 13:25:57 CEST 2006 ScriptingService.cxx
3 
4  ScriptingService.cxx - description
5  -------------------
6  begin : Mon June 26 2006
7  copyright : (C) 2006 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 General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 
40 #include "ScriptingService.hpp"
41 #include "../Logger.hpp"
42 #include "../TaskContext.hpp"
43 #include <algorithm>
44 #include <functional>
45 #include <fstream>
46 #include <iterator>
48 #include "ProgramExceptions.hpp"
49 #include "StatementProcessor.hpp"
50 #include "../Service.hpp"
51 #include "Parser.hpp"
52 #include "parse_exception.hpp"
53 #include "../OperationCaller.hpp"
54 #include "../internal/mystd.hpp"
55 #include "../plugin/ServicePlugin.hpp"
56 #include "../internal/GlobalEngine.hpp"
57 
59 
60 
61 namespace RTT {
62  using namespace detail;
63  using namespace std;
64 
65  ScriptingService::shared_ptr ScriptingService::Create(TaskContext* parent){
66  shared_ptr sp(new ScriptingService(parent));
67  parent->provides()->addService( sp );
68  return sp;
69  }
70 
71  ScriptingService::ScriptingService( TaskContext* parent )
72  : Service("scripting", parent),
73  sproc(0)
74  {
75  this->doc("Orocos Scripting service. Use this service in order to load or query programs or state machines.");
76  this->createInterface();
77  ZeroPeriodWarning = true;
78  this->addProperty("ZeroPeriodWarning",ZeroPeriodWarning)
79  .doc("If this is set to false, the warning log when loading a program or a state machine into a Component"
80  " with a null period will not be printed. Be sure you have something else triggering periodically"
81  " your Component activity unless your script may not work.");
82  }
83 
85  {
86  // since we are refcounted, we don't need to inform the owner
87  // that we're being deleted.
88  this->clear();
89  delete sproc;
90  }
91 
93  while ( !states.empty() ) {
94  // try to unload all
95  Logger::log() << Logger::Info << "ScriptingService unloads StateMachine "<< states.begin()->first << "..."<<Logger::endl;
96 #ifndef ORO_EMBEDDED
97  try {
98  this->unloadStateMachine( states.begin()->first );
99  }
100  catch ( program_load_exception& ple) {
101  Logger::log() << Logger::Error << ple.what() <<Logger::endl;
102  states.erase( states.begin() ); // plainly remove it to avoid endless loop.
103  }
104 #else
105  if (this->unloadStateMachine( states.begin()->first ) == false) {
106  Logger::log() << Logger::Error << "Error during unload !" <<Logger::endl;
107  states.erase( states.begin() ); // plainly remove it to avoid endless loop.
108  }
109 #endif
110  }
111  while ( !programs.empty() ) {
112  // try to unload all
113  Logger::log() << Logger::Info << "ScriptingService unloads Program "<< programs.begin()->first << "..."<<Logger::endl;
114 #ifndef ORO_EMBEDDED
115  try {
116  this->unloadProgram( programs.begin()->first );
117  }
118  catch ( program_load_exception& ple) {
119  Logger::log() << Logger::Error << ple.what() <<Logger::endl;
120  programs.erase( programs.begin() ); // plainly remove it to avoid endless loop.
121  }
122 #else
123  if (this->unloadProgram( programs.begin()->first ) == false) {
124  Logger::log(Error) << "Error during unload !" <<Logger::endl;
125  programs.erase( programs.begin() ); // plainly remove it to avoid endless loop.
126  }
127 #endif
128  }
129  Service::clear();
130  }
131 
133  {
134  StateMapIt it = states.find(name);
135  if ( it != states.end() ) {
136  return it->second->getStatus();
137  }
139  }
140 
141  string ScriptingService::getStateMachineStatusStr(const string& name) const
142  {
143  switch ( getStateMachineStatus( name ))
144  {
146  return "inactive";
147  break;
149  return "stopping";
150  break;
152  return "stopped";
153  break;
155  return "requesting";
156  break;
158  return "running";
159  break;
161  return "paused";
162  break;
164  return "active";
165  break;
167  return "activating";
168  break;
170  return "deactivating";
171  break;
173  return "resetting";
174  break;
176  return "error";
177  break;
179  return "unloaded";
180  break;
181  }
182  return "na";
183  }
184 
186  {
187  // test if parent ...
188  if ( sc->getParent() ) {
189  string error(
190  "Could not register StateMachine \"" + sc->getName() +
191  "\" in the ScriptingService. It is not a root StateMachine." );
192  ORO_THROW_OR_RETURN( program_load_exception( error ) , false);
193  }
194 
195  if (this->recursiveCheckLoadStateMachine( sc ) == false)
196  return false; // throws load_exception
197 
198  if ( getOwner()->getPeriod() == 0 && ZeroPeriodWarning) {
199  log(Warning) << "Loading StateMachine "<< sc->getName()
200  << " in a TaskContext with getPeriod() == 0."
201  << " Use setPeriod(period) in order to setup execution of scripts."
202  << " If you know what you are doing, you may disable this warning using scripting.ZeroPeriodWarning=false"
203  <<endlog();
204  }
205 
206  this->recursiveLoadStateMachine( sc );
207  return true;
208  }
209 
211  {
212  // test if already present..., this cannot detect corrupt
213  // trees with double names...
214  if ( states.find(sc->getName()) != states.end() ) {
215  string error(
216  "Could not register StateMachine \"" + sc->getName() +
217  "\" in the ScriptingService. A StateMachine with that name is already present." );
218  ORO_THROW_OR_RETURN( program_load_exception( error ), false );
219 
220  vector<StateMachinePtr>::const_iterator it2;
221  for (it2 = sc->getChildren().begin(); it2 != sc->getChildren().end(); ++it2)
222  {
223  if ( this->recursiveCheckLoadStateMachine( *it2 ) == false)
224  return false;
225  }
226  }
227  return true;
228  }
229 
231  {
232  vector<StateMachinePtr>::const_iterator it;
233 
234  // first load parent.
235  states[sc->getName()] = sc;
236  mowner->engine()->runFunction( sc.get() );
237 
238  // then load children.
239  for (it = sc->getChildren().begin(); it != sc->getChildren().end(); ++it)
240  {
241  this->recursiveLoadStateMachine( *it );
242  }
243 
244  }
245 
246  bool ScriptingService::unloadStateMachine( const string& name )
247  {
248  StateMapIt it = states.find(name);
249 
250  if ( it != states.end() ) {
251  // test if parent ...
252  if ( it->second->getParent() ) {
253  string error(
254  "Could not unload StateMachine \"" + it->first +
255  "\" in the ScriptingService. It is not a root StateMachine." );
257  }
258  if (recursiveCheckUnloadStateMachine( it->second ) == false)
259  return false;
260  recursiveUnloadStateMachine( it->second );
261  return true;
262  }
263  return false;
264  }
265 
267  {
268  // check children
269  vector<StateMachinePtr>::const_iterator it2;
270  for (it2 = si->getChildren().begin();
271  it2 != si->getChildren().end();
272  ++it2)
273  {
274  StateMapIt it = states.find( (*it2)->getName() );
275  if ( it == states.end() ) {
276  string error(
277  "Could not unload StateMachine \"" + si->getName() +
278  "\" in the ScriptingService. It contains not loaded child "+ (*it2)->getName() );
280  }
281  // all is ok, check child :
282  if ( this->recursiveCheckUnloadStateMachine( it->second ) == false)
283  return false;
284  }
285  return true;
286  }
287 
289  // first erase children
290  for (vector<StateMachinePtr>::const_iterator it = sc->getChildren().begin();
291  it != sc->getChildren().end(); ++it)
292  {
293  this->recursiveUnloadStateMachine( *it );
294  }
295 
296  // erase this sc :
297  StateMap::iterator it = states.find( sc->getName() );
298 
299  assert( it != states.end() ); // we checked that this is possible
300 
301  // lastly, unload the parent.
302  states.erase(it);
303  mowner->engine()->removeFunction( sc.get() );
304  }
305 
306  bool ScriptingService::deleteStateMachine(const string& name)
307  {
308  return this->unloadStateMachine(name);
309  }
310 
311  const StateMachinePtr ScriptingService::getStateMachine(const string& name) const
312  {
313  StateMapIt it = states.find(name);
314  return it == states.end() ? StateMachinePtr() : it->second;
315  }
316 
318  {
319  StateMapIt it = states.find(name);
320  return it == states.end() ? StateMachinePtr() : it->second;
321  }
322 
324  {
325  return keys(states);
326  }
327 
329  {
330  ProgMapIt it = programs.find(name);
331 
332  if ( it != programs.end() )
333  return it->second->getStatus();
334  return ProgramStatus::unknown;
335  }
336 
337  string ScriptingService::getProgramStatusStr(const string& name) const
338  {
339  switch ( getProgramStatus( name ))
340  {
342  return "unknown";
343  break;
345  return "stopped";
346  break;
348  return "running";
349  break;
351  return "paused";
352  break;
354  return "error";
355  break;
356  }
357  return "na";
358  }
359 
361  {
362  if ( programs.find(pi->getName()) != programs.end() ) {
363  log(Error) << "Could not load Program "<< pi->getName() << " in ScriptingService: name already in use."<<endlog();
364  return false;
365  }
366  if ( getOwner()->getPeriod() == 0 && ZeroPeriodWarning ) {
367  log(Warning) << "Loading program " << pi->getName()
368  << " in a TaskContext with getPeriod() == 0."
369  << " Use setPeriod(period) in order to setup execution of scripts."
370  << " If you know what you are doing, you may disable this warning using scripting.ZeroPeriodWarning=false"
371  << endlog();
372  }
373  programs[pi->getName()] = pi;
374  pi->reset();
375  if ( mowner->engine()->runFunction( pi.get() ) == false) {
376  programs.erase(pi->getName());
377  log(Error) << "Could not load Program "<< pi->getName() << " in ExecutionEngine."<<endlog();
378  return false;
379  }
380  return true;
381  }
382 
383  bool ScriptingService::unloadProgram(const string& name)
384  {
385  ProgMap::iterator it = programs.find(name);
386 
387  if ( it != programs.end() )
388  {
389  mowner->engine()->removeFunction( it->second.get() );
390  programs.erase( it );
391  return true;
392  }
393  string error("Could not unload Program \"" + name +
394  "\" in the ScriptingService. It does not exist." );
396  }
397 
398  vector<string> ScriptingService::getProgramList() const
399  {
400  return keys(programs);
401  }
402 
403  const ProgramInterfacePtr ScriptingService::getProgram(const string& name) const
404  {
405  ProgMapIt it = programs.find(name);
406  return it == programs.end() ? ProgramInterfacePtr() : it->second;
407  }
408 
410  {
411  ProgMapIt it = programs.find(name);
412  return it == programs.end() ? ProgramInterfacePtr() : it->second;
413  }
414 
415 
416  bool ScriptingService::doExecute(const string& code)
417  {
418  return this->execute(code) >= 0;
419  }
420 
421  bool ScriptingService::doLoadPrograms( const string& filename )
422  {
423  return this->loadPrograms(filename, false);
424  }
425 
426  bool ScriptingService::doLoadProgramText( const string& code )
427  {
428  return this->loadPrograms(code, "string", false);
429  }
430  bool ScriptingService::doUnloadProgram( const string& name )
431  {
432  return this->unloadProgram(name, false);
433  }
434 
435  bool ScriptingService::doLoadStateMachines( const string& filename )
436  {
437  return this->loadStateMachines(filename, false);
438  }
439  bool ScriptingService::doLoadStateMachineText( const string& code )
440  {
441  return this->loadStateMachines(code, "string", false);
442  }
443  bool ScriptingService::doUnloadStateMachine( const string& name )
444  {
445  return this->unloadStateMachine(name, false);
446  }
447 
449  {
450  // OperationCallers for loading and executing scripts
451  addOperation("eval", &ScriptingService::eval, this).doc("Evaluate then script in the argument").arg("Code", "Statements, functions, program definitions etc.");
452  addOperation("runScript", &ScriptingService::runScript, this).doc("Run a script from a given file.").arg("Filename", "The filename of the script.");
453 
454  addOperation("execute", &ScriptingService::execute, this).doc("Execute a line of code (DEPRECATED).").arg("Code", "A single statement.");
455  // OperationCallers for loading programs
456  addOperation("loadPrograms", &ScriptingService::doLoadPrograms, this).doc("Load a program from a given file (DEPRECATED).").arg("Filename", "The filename of the script.");
457  addOperation("loadProgramText", &ScriptingService::doLoadProgramText, this).doc("Load a program from a string (DEPRECATED).").arg("Code", "A string containing one or more program scripts.");
458  addOperation("unloadProgram", &ScriptingService::doUnloadProgram, this).doc("Remove a loaded program.").arg("Name", "The name of the loaded Program");
459 
460  // Query OperationCallers for programs
461  addOperation("getProgramList", &ScriptingService::getProgramList, this).doc("Get a list of all loaded program scripts.");
462  addOperation("getProgramStatus", &ScriptingService::getProgramStatus, this).doc("Get the status of a program?").arg("Name", "The Name of the loaded Program");
463  addOperation("getProgramStatusStr", &ScriptingService::getProgramStatusStr, this).doc("Get the status of a program as a human readable string.").arg("Name", "The Name of the loaded Program");
464  addOperation("getProgramLine", &ScriptingService::getProgramLine, this).doc("Get the current line of execution of a program?").arg("Name", "The Name of the loaded Program");
465  addOperation("getProgramText", &ScriptingService::getProgramText, this).doc("Get the script of a program.").arg("Name", "The Name of the loaded Program");
466 
467  // OperationCallers for loading state machines
468  addOperation("loadStateMachines", &ScriptingService::doLoadStateMachines, this).doc("Load a state machine from a given file (DEPRECATED).").arg("Filename", "The filename of the script.");
469  addOperation("loadStateMachineText", &ScriptingService::doLoadStateMachineText, this).doc("Load a state machine from a string (DEPRECATED).").arg("Code", "A string containing one or more state machine scripts.");
470  addOperation("unloadStateMachine", &ScriptingService::doUnloadStateMachine, this).doc("Remove a loaded state machine.").arg("Name", "The name of the loaded State Machine");
471 
472  // Query OperationCallers for state machines
473  addOperation("getStateMachineList", &ScriptingService::getStateMachineList, this).doc("Get a list of all loaded state machines");
474  addOperation("getStateMachineStatus", &ScriptingService::getStateMachineStatus, this).doc("Get the status of a state machine?").arg("Name", "The Name of the loaded State Machine");
475  addOperation("getStateMachineStatusStr", &ScriptingService::getStateMachineStatusStr, this).doc("Get the status of a state machine as a human readable string.");
476  addOperation("getStateMachineLine", &ScriptingService::getStateMachineLine, this).doc("Get the current line of execution of a state machine?").arg("Name", "The Name of the loaded State Machine");
477  addOperation("getStateMachineText", &ScriptingService::getStateMachineText, this).doc("Get the script of a StateMachine.").arg("Name", "The Name of the loaded StateMachine");
478 
479  // Query OperationCallers for programs
480  addOperation("hasProgram", &ScriptingService::hasProgram, this).doc("Is a program loaded?").arg("Name", "The Name of the loaded Program");
481  addOperation("isProgramRunning", &ScriptingService::isProgramRunning, this).doc("Is a program running ?").arg("Name", "The Name of the Loaded Program");
482  addOperation("isProgramPaused", &ScriptingService::isProgramPaused, this).doc("Is a program paused ?").arg("Name", "The Name of the Loaded Program");
483  addOperation("inProgramError", &ScriptingService::inProgramError, this).doc("Is a program in error ?").arg("Name", "The Name of the Loaded Program");
484 
485  // Query OperationCallers for state machines
486  addOperation("hasStateMachine", &ScriptingService::hasStateMachine, this).doc("Is a state machine loaded?").arg("Name", "The Name of the loaded State Machine");
487  addOperation("isStateMachineActive", &ScriptingService::isStateMachineActive, this).doc("Is a state machine active ?").arg("Name", "The Name of the Loaded StateMachine");
488  addOperation("isStateMachineRunning", &ScriptingService::isStateMachineRunning, this).doc("Is a state machine running ?").arg("Name", "The Name of the Loaded StateMachine");
489  addOperation("isStateMachinePaused", &ScriptingService::isStateMachinePaused, this).doc("Is a state machine paused ?").arg("Name", "The Name of the Loaded StateMachine");
490  addOperation("inStateMachineError", &ScriptingService::inStateMachineError, this).doc("Is a state machine in error ?").arg("Name", "The Name of the Loaded StateMachine");
491  addOperation("inStateMachineState", &ScriptingService::inStateMachineState, this).doc("Is a state machine in a given state ?").arg("Name", "The Name of the Loaded StateMachine").arg("State", "The name of the state in which it could be.");
492  addOperation("getStateMachineState", &ScriptingService::getStateMachineState, this).doc("Get the current state name of a state machine.").arg("Name", "The Name of the Loaded StateMachine");
493 
494  // OperationCallers for programs
495  addOperation("startProgram", &ScriptingService::startProgram, this).doc("Start a program").arg("Name", "The Name of the Loaded Program");
496  addOperation("stopProgram", &ScriptingService::stopProgram , this).doc("Stop a program").arg("Name", "The Name of the Started Program");
497 
498  addOperation("stepProgram", &ScriptingService::stepProgram , this).doc("Step a single program instruction").arg("Name", "The Name of the Paused Program");
499  addOperation("pauseProgram", &ScriptingService::pauseProgram , this).doc("Pause a program").arg("Name", "The Name of the Started Program");
500 
501  // OperationCallers for state machines
502  // Activate/deactivate:
503  addOperation("activateStateMachine", &ScriptingService::activateStateMachine , this).doc("Activate a StateMachine").arg("Name", "The Name of the Loaded StateMachine");
504  addOperation("deactivateStateMachine", &ScriptingService::deactivateStateMachine , this).doc("Deactivate a StateMachine").arg("Name", "The Name of the Stopped StateMachine");
505 
506  // start/stop/pause:
507  addOperation("startStateMachine", &ScriptingService::startStateMachine , this).doc("Start a StateMachine").arg("Name", "The Name of the Activated/Paused StateMachine");
508  addOperation("pauseStateMachine", &ScriptingService::pauseStateMachine , this).doc("Pause a StateMachine").arg("Name", "The Name of a Started StateMachine");
509  addOperation("stopStateMachine", &ScriptingService::stopStateMachine , this).doc("Stop a StateMachine").arg("Name", "The Name of the Started/Paused StateMachine");
510  addOperation("resetStateMachine", &ScriptingService::resetStateMachine , this).doc("Reset a StateMachine").arg("Name", "The Name of the Stopped StateMachine");
511 
512  // request states
513  addOperation("requestStateMachineState", &ScriptingService::requestStateMachineState , this).doc("Request a State change").arg("Name", "The Name of the StateMachine").arg("StateName", "The Name of the State to change to");
514  }
515 
516  int ScriptingService::execute(const string& code ){
517  if (sproc == 0)
519  return sproc->execute( code );
520  }
521 
522  ScriptingService::Functions ScriptingService::loadFunctions( const string& file, bool do_throw/* = false*/ )
523  {
524  ifstream inputfile(file.c_str());
525  if ( !inputfile ) {
526  Logger::In in("ScriptingService::loadFunctions");
527  Logger::log() << Logger::Error << "Script "+file+" does not exist." << Logger::endl;
528  return Functions();
529  }
530  string text;
531  inputfile.unsetf( ios_base::skipws );
532  istream_iterator<char> streambegin( inputfile );
533  istream_iterator<char> streamend;
534  std::copy( streambegin, streamend, back_inserter( text ) );
535  return this->loadFunctions( text, file, do_throw );
536  }
537 
538  ScriptingService::Functions ScriptingService::loadFunctions( const string& code, const string& filename, bool mrethrow )
539  {
540 
541  Logger::In in("ScriptingService::loadFunctions");
542  Parser p(mowner->engine());
543  Functions exec;
544  Functions ret;
545  try {
546  Logger::log() << Logger::Info << "Parsing file "<<filename << Logger::endl;
547  ret = p.parseFunction(code, mowner, filename);
548  }
549  catch( const file_parse_exception& exc )
550  {
551 #ifndef ORO_EMBEDDED
552  Logger::log() << Logger::Error << filename<<" :"<< exc.what() << Logger::endl;
553  if ( mrethrow )
554  throw;
555 #endif
556  return Functions();
557  }
558  if ( ret.empty() )
559  {
560  Logger::log() << Logger::Debug << "No Functions executed from "<< filename << Logger::endl;
561  Logger::log() << Logger::Info << filename <<" : Successfully parsed." << Logger::endl;
562  return Functions();
563  } else {
564  // Load all listed functions in the TaskContext's Processor:
565  for( Parser::ParsedFunctions::iterator it = ret.begin(); it != ret.end(); ++it) {
566  Logger::log() << "Queueing Function "<< (*it)->getName() << Logger::endl;
567  if ( mowner->engine()->runFunction( it->get() ) == false) {
568  Logger::log() << Logger::Error << "Could not run Function '"<< (*it)->getName() <<"' :" << Logger::nl;
569  Logger::log() << "Processor not accepting or function queue is full." << Logger::endl;
570  } else
571  exec.push_back( *it ); // is being executed.
572  }
573  }
574  return exec;
575 
576  }
577 
578  bool ScriptingService::runScript( const string& file )
579  {
580  ifstream inputfile(file.c_str());
581  if ( !inputfile ) {
582  Logger::In in("ScriptingService::runScript");
583  Logger::log() << Logger::Error << "Script "+file+" does not exist." << Logger::endl;
584  return false;
585  }
586  string text;
587  inputfile.unsetf( ios_base::skipws );
588  istream_iterator<char> streambegin( inputfile );
589  istream_iterator<char> streamend;
590  std::copy( streambegin, streamend, back_inserter( text ) );
591 
592  log(Info) << "Running Script "<< file <<" ..." << Logger::endl;
593  return evalInternal( file, text );
594  }
595 
596  bool ScriptingService::eval(const string& code) {
597  return evalInternal("eval()", code);
598  }
599 
600  bool ScriptingService::evalInternal(const string& filename, const string& code )
601  {
602  Logger::In in("ScriptingService");
603  Parser parser( GlobalEngine::Instance() );
604  try {
605  parser.runScript(code, mowner, this, filename );
606  }
607  catch( const file_parse_exception& exc )
608  {
609  log(Error) <<filename<<" :"<< exc.what() << endlog();
610  return false;
611  }
612  return true;
613  }
614 
615  bool ScriptingService::loadPrograms( const string& file, bool do_throw /*= false*/ )
616  {
617  ifstream inputfile(file.c_str());
618  if ( !inputfile ) {
619  Logger::In in("ScriptingService::loadProgram");
620  Logger::log() << Logger::Error << "Script "+file+" does not exist." << Logger::endl;
621  return false;
622  }
623  string text;
624  inputfile.unsetf( ios_base::skipws );
625  istream_iterator<char> streambegin( inputfile );
626  istream_iterator<char> streamend;
627  std::copy( streambegin, streamend, back_inserter( text ) );
628  return this->loadPrograms( text, file, do_throw );
629  }
630 
631  bool ScriptingService::loadPrograms( const string& code, const string& filename, bool mrethrow ){
632 
633  Logger::In in("ProgramLoader::loadProgram");
634  Parser parser(mowner->engine());
635  Parser::ParsedPrograms pg_list;
636  try {
637  Logger::log() << Logger::Info << "Parsing file "<<filename << Logger::endl;
638  pg_list = parser.parseProgram(code, mowner, filename );
639  }
640  catch( const file_parse_exception& exc )
641  {
642 #ifndef ORO_EMBEDDED
643  Logger::log() << Logger::Error <<filename<<" :"<< exc.what() << Logger::endl;
644  if ( mrethrow )
645  throw;
646 #endif
647  return false;
648  }
649  if ( pg_list.empty() )
650  {
651  Logger::log() << Logger::Info << filename <<" : Successfully parsed." << Logger::endl;
652  return true;
653  } else {
654  // Load all listed programs in the TaskContext's Processor:
655  bool error = false;
656  string errors;
657  for( Parser::ParsedPrograms::iterator it = pg_list.begin(); it != pg_list.end(); ++it) {
658  try {
659  Logger::log() << Logger::Info << "Loading Program '"<< (*it)->getName() <<"'" <<Logger::endl;
660  if (this->loadProgram( *it ) == false)
661  error = true;
662  } catch (program_load_exception& e ) {
663  Logger::log() << Logger::Error << "Could not load Program '"<< (*it)->getName() <<"' :" << Logger::nl;
664 #ifndef ORO_EMBEDDED
665  Logger::log() << e.what() << Logger::endl;
666  if ( mrethrow )
667  errors += "Could not load Program '"+ (*it)->getName() +"' :\n"+e.what()+'\n';
668 #endif
669  error = true;
670  }
671  }
672 #ifndef ORO_EMBEDDED
673  if (error && mrethrow )
674  throw program_load_exception( errors );
675 #endif
676  return !error;
677  }
678  // never reached
679  }
680 
681  bool ScriptingService::unloadProgram( const string& name, bool do_throw ){
682  Logger::In in("ScriptingService::unloadProgram");
683  try {
684  Logger::log() << Logger::Info << "Unloading Program '"<< name <<"'"<< Logger::endl;
685  if (this->unloadProgram(name) == false)
686  return false;
687  } catch (program_unload_exception& e ) {
688  Logger::log() << Logger::Error << "Could not unload Program '"<< name <<"' :" << Logger::nl;
689 #ifndef ORO_EMBEDDED
690  Logger::log() << e.what() << Logger::endl;
691  if ( do_throw )
692  throw;
693 #endif
694  return false;
695  }
696  return true;
697  }
698 
699 
700  bool ScriptingService::loadStateMachines( const string& file, bool do_throw /*= false*/ )
701  {
702  ifstream inputfile(file.c_str());
703  if ( !inputfile ) {
704  Logger::In in("ScriptingService::loadStateMachine");
705  Logger::log() << Logger::Error << "Script "+file+" does not exist." << Logger::endl;
706  return false;
707  }
708  string text;
709  inputfile.unsetf( ios_base::skipws );
710  istream_iterator<char> streambegin( inputfile );
711  istream_iterator<char> streamend;
712  std::copy( streambegin, streamend, back_inserter( text ) );
713  return this->loadStateMachines( text, file, do_throw );
714  }
715 
716  bool ScriptingService::loadStateMachines( const string& code, const string& filename, bool mrethrow )
717  {
718  Logger::In in("ScriptingService::loadStateMachine");
719  Parser parser(mowner->engine());
721  try {
722  Logger::log() << Logger::Info << "Parsing file "<<filename << Logger::endl;
723  pg_list = parser.parseStateMachine( code, mowner, filename );
724  }
725  catch( const file_parse_exception& exc )
726  {
727 #ifndef ORO_EMBEDDED
728  Logger::log() << Logger::Error <<filename<<" :"<< exc.what() << Logger::endl;
729  if ( mrethrow )
730  throw;
731 #endif
732  return false;
733  }
734  if ( pg_list.empty() )
735  {
736  Logger::log() << Logger::Error << "No StateMachines instantiated in "<< filename << Logger::endl;
737  return false;
738  } else {
739  bool error = false;
740  string errors;
741  // Load all listed stateMachines in the TaskContext's Processor:
742  for( Parser::ParsedStateMachines::iterator it = pg_list.begin(); it != pg_list.end(); ++it) {
743  try {
744  Logger::log() << Logger::Info << "Loading StateMachine '"<< (*it)->getName()<<"'" << Logger::endl;
745  if (this->loadStateMachine( *it ) == false)
746  return false;
747  } catch (program_load_exception& e ) {
748  Logger::log() << Logger::Error << "Could not load StateMachine '"<< (*it)->getName()<<"' :" << Logger::nl;
749 #ifndef ORO_EMBEDDED
750  Logger::log() << e.what() << Logger::endl;
751  if ( mrethrow )
752  errors += "Could not load Program '"+ (*it)->getName() +"' :\n"+e.what()+'\n';
753 #endif
754  error = true;
755  }
756  }
757 #ifndef ORO_EMBEDDED
758  if ( error && mrethrow )
759  throw program_load_exception( errors );
760 #endif
761  return !error;
762  }
763  // never reached
764  return false;
765  }
766 
767  bool ScriptingService::unloadStateMachine( const string& name, bool do_throw ) {
768  Logger::In in("ScriptingService::unloadStateMachine");
769  try {
770  Logger::log() << Logger::Info << "Unloading StateMachine '"<< name <<"'"<< Logger::endl;
771  if (this->unloadStateMachine(name) == false)
772  return false;
773  } catch (program_unload_exception& e ) {
774  Logger::log() << Logger::Error << "Could not unload StateMachine '"<< name <<"' :" << Logger::nl;
775 #ifndef ORO_EMBEDDED
776  Logger::log() << e.what() << Logger::endl;
777  if ( do_throw )
778  throw;
779 #endif
780  return false;
781  }
782  return true;
783  }
784 
785  bool ScriptingService::hasProgram(const string& name) const {
786  return programs.find(name) != programs.end();
787  }
788 
789  int ScriptingService::getProgramLine(const string& name) const {
790  const ProgramInterfacePtr pi = getProgram(name);
791  return pi ? pi->getLineNumber() : -1;
792  }
793 
794  string ScriptingService::getProgramText(const string& name ) const {
795  const ProgramInterfacePtr pi = getProgram(name);
796  return pi ? pi->getText() : "";
797  }
798 
799  bool ScriptingService::hasStateMachine(const string& name) const {
800  return states.find(name) != states.end();
801  }
802 
803  string ScriptingService::getStateMachineText(const string& name ) const {
804  const StateMachinePtr sm = getStateMachine(name);
805  return sm ? sm->getText() : "";
806  }
807 
808  int ScriptingService::getStateMachineLine(const string& name ) const {
809  const StateMachinePtr sm = getStateMachine(name);
810  return sm ? sm->getLineNumber() : -1;
811  }
812 
813  bool ScriptingService::startProgram(const string& name)
814  {
815  ProgramInterfacePtr pi = getProgram(name);
816  if (pi)
817  return pi->start();
818  return false;
819  }
820 
821  bool ScriptingService::isProgramRunning(const string& name) const
822  {
823  ProgramInterfacePtr pi = getProgram(name);
824  if (pi)
825  return pi->isRunning();
826  return false;
827  }
828 
829  bool ScriptingService::isProgramPaused(const string& name) const
830  {
831  ProgramInterfacePtr pi = getProgram(name);
832  if (pi)
833  return pi->isPaused();
834  return false;
835  }
836 
837  bool ScriptingService::inProgramError(const string& name) const
838  {
839  ProgramInterfacePtr pi = getProgram(name);
840  if (pi)
841  return pi->inError();
842  return false;
843  }
844 
845  bool ScriptingService::stopProgram(const string& name)
846  {
847  ProgramInterfacePtr pi = getProgram(name);
848  if (pi)
849  return pi->stop();
850  return false;
851  }
852 
853  bool ScriptingService::pauseProgram(const string& name)
854  {
855  ProgramInterfacePtr pi = getProgram(name);
856  if (pi)
857  return pi->pause();
858  return false;
859  }
860 
861  bool ScriptingService::stepProgram(const string& name)
862  {
863  ProgramInterfacePtr pi = getProgram(name);
864  if (pi)
865  return pi->step();
866  return false;
867  }
868 
869  bool ScriptingService::activateStateMachine(const string& name)
870  {
871  StateMachinePtr sm = getStateMachine(name);
872  if (sm)
873  return sm->activate();
874  return false;
875  }
876 
878  {
879  StateMachinePtr sm = getStateMachine(name);
880  if (sm)
881  return sm->deactivate();
882  return false;
883  }
884 
885  bool ScriptingService::startStateMachine(const string& name)
886  {
887  StateMachinePtr sm = getStateMachine(name);
888  if (sm)
889  return sm->start();
890  return false;
891  }
892 
893  bool ScriptingService::pauseStateMachine(const string& name)
894  {
895  StateMachinePtr sm = getStateMachine(name);
896  if (sm)
897  return sm->pause();
898  return false;
899  }
900 
901  bool ScriptingService::stopStateMachine(const string& name)
902  {
903  StateMachinePtr sm = getStateMachine(name);
904  if (sm)
905  return sm->stop();
906  return false;
907  }
908 
909  bool ScriptingService::isStateMachinePaused(const string& name) const
910  {
911  StateMachinePtr sm = getStateMachine(name);
912  if (sm)
913  return sm->isPaused();
914  return false;
915  }
916 
917  bool ScriptingService::isStateMachineActive(const string& name) const
918  {
919  StateMachinePtr sm = getStateMachine(name);
920  if (sm)
921  return sm->isActive();
922  return false;
923  }
924 
925  bool ScriptingService::isStateMachineRunning(const string& name) const
926  {
927  StateMachinePtr sm = getStateMachine(name);
928  if (sm)
929  return sm->isAutomatic();
930  return false;
931  }
932 
933  bool ScriptingService::inStateMachineError(const string& name) const
934  {
935  StateMachinePtr sm = getStateMachine(name);
936  if (sm)
937  return sm->inError();
938  return false;
939  }
940 
941  string ScriptingService::getStateMachineState(const string& name) const
942  {
943  StateMachinePtr sm = getStateMachine(name);
944  if (sm)
945  return sm->getCurrentStateName();
946  return "";
947  }
948 
949  bool ScriptingService::requestStateMachineState(const string& name, const string& state)
950  {
951  StateMachinePtr sm = getStateMachine(name);
952  if (sm)
953  return sm->requestState(state);
954  return false;
955  }
956 
957  bool ScriptingService::inStateMachineState(const string& name, const string& state) const
958  {
959  StateMachinePtr sm = getStateMachine(name);
960  if (sm)
961  return sm->inState(state);
962  return false;
963  }
964 
965  bool ScriptingService::resetStateMachine(const string& name)
966  {
967  StateMachinePtr sm = getStateMachine(name);
968  if (sm)
969  return sm->reset();
970  return false;
971  }
972 
973 }
bool doLoadStateMachineText(const std::string &code)
const std::string what() const
bool unloadStateMachine(const std::string &name)
Unload a deactivated State Machine and all its children.
This exception is thrown when a program or state machine could not be unloaded into a ProgramProcesso...
TaskContext * getOwner() const
The owner is the top-level TaskContext owning this service (indirectly).
Definition: Service.hpp:185
boost::shared_ptr< ScriptingService > shared_ptr
bool unloadProgram(const std::string &name)
Unload a program from this processor.
virtual bool loadPrograms(const std::string &filename, bool do_throw)
Load a set of programs into the Program Processor for execution.
bool doExecute(const std::string &code)
virtual Functions loadFunctions(const std::string &filename, bool do_throw)
Load and execute a set of functions into the Program Processor for execution.
Service::shared_ptr provides()
Returns this Service.
virtual bool hasStateMachine(const std::string &name) const
Check if a state machine is loaded.
virtual bool removeFunction(base::ExecutableInterface *f)
Remove a running function added with runFunction.
StateMachineStatus::StateMachineStatus getStateMachineStatus(const std::string &name) const
Return the status of a StateMachine.
StateMap::const_iterator StateMapIt
bool eval(const std::string &code)
Evaluate and run all statements in code.
virtual int getProgramLine(const std::string &name) const
Get the current line of execution of a loaded program script.
ProgramStatus
Enumerates the statuses of a ProgramInterface.
bool startProgram(const std::string &name)
Start a Program.
bool stepProgram(const std::string &name)
Steps a single instruction of a paused program.
bool isStateMachineActive(const std::string &name) const
Returns true if the state machine has been activated.
This class parses and executes a single scripting statement.
const StateMachinePtr getStateMachine(const std::string &name) const
Get a pointer to a loaded StateMachine.
#define ORO_THROW_OR_RETURN(x, rv)
Definition: Exceptions.hpp:53
virtual std::string getStateMachineText(const std::string &name) const
Get the original script description of a loaded state machine.
void clear()
Stop and unload all program scripts.
static std::ostream & nl(std::ostream &__os)
Insert a newline &#39; &#39; in the ostream.
Definition: Logger.cpp:373
STL namespace.
#define ORO_SERVICE_NAMED_PLUGIN(SERVICE, NAME)
You can use this macro to make any Service available as a plugin.
bool isProgramRunning(const std::string &name) const
Inspect if a loaded program is in the running state.
Operation< Signature > & addOperation(Operation< Signature > &op)
Add an operation object to the interface.
Definition: Service.hpp:341
bool inProgramError(const std::string &name) const
Inspect if a loaded program is in the error state.
bool doLoadPrograms(const std::string &filename)
bool loadProgram(ProgramInterfacePtr pi)
Load a new Program.
bool loadStateMachine(StateMachinePtr sc)
Load a new State Machine and all its children.
ProgMap::const_iterator ProgMapIt
boost::shared_ptr< ProgramInterface > ProgramInterfacePtr
This is an exception class that keeps a parse_exception pointer along with the location in the file a...
void runScript(std::string const &code, TaskContext *mowner, ScriptingService *service, std::string const &filename)
Runs all statements in code.
Definition: Parser.cpp:62
This class allows storage and retrieval of operations, ports, attributes and properties provided by a...
Definition: Service.hpp:93
bool isStateMachineRunning(const std::string &name) const
Returns true if the state machine was successfully started.
ProgramStatus::ProgramStatus getProgramStatus(const std::string &name) const
Return the status of a Program.
bool deleteStateMachine(const std::string &name)
Delete a deactivated State Machine and all its children.
bool doLoadProgramText(const std::string &code)
std::vector< std::string > getStateMachineList() const
Get a list of all loaded StateMachines and their children.
virtual int getStateMachineLine(const std::string &name) const
Get the current line of execution of a loaded state machine script.
const ProgramInterfacePtr getProgram(const std::string &name) const
Get a pointer to a loaded Program.
bool isProgramPaused(const std::string &name) const
Inspect if a loaded program is in the paused state.
bool doUnloadStateMachine(const std::string &name)
bool pauseProgram(const std::string &name)
Pauses the execution of a running program.
static RTT_API ExecutionEngine * Instance()
This is an overloaded member function, provided for convenience. It differs from the above function o...
const std::string & doc() const
Returns a descriptive text for this service.
Definition: Service.hpp:144
std::vector< ProgramInterfacePtr > ParsedPrograms
List of parsed programs.
Definition: Parser.hpp:101
std::string getStateMachineStatusStr(const std::string &name) const
Return the status of a StateMachine as a human readable string.
static std::ostream & endl(std::ostream &__os)
Definition: Logger.cpp:383
bool requestStateMachineState(const std::string &name, const std::string &state)
Request a state change in a state machine.
The program was running but is now paused.
This class is the public interface to the Orocos Program Parser Framework.
Definition: Parser.hpp:65
bool inStateMachineError(const std::string &name) const
Returns true if the state machine is in error.
bool pauseStateMachine(const std::string &name)
Pause a previously activated StateMachine.
boost::shared_ptr< StateMachine > StateMachinePtr
bool resetStateMachine(const std::string &name)
Resets the execution of a scripting::StateMachine and enters the Initial_State.
void recursiveUnloadStateMachine(StateMachinePtr sc)
bool recursiveCheckLoadStateMachine(StateMachinePtr sc)
TaskContext * mowner
Definition: Service.hpp:572
Property< T > & addProperty(const std::string &name, T &prop)
Adds a variable of any type as a property to the configuration interface.
std::string getStateMachineState(const std::string &name) const
Get the current state of a state machine.
int execute(const std::string &code)
Parse and execute a statement.
std::vector< typename MapT::key_type > keys(const MapT &map)
Definition: mystd.hpp:151
std::vector< ProgramInterfacePtr > Functions
List of executed functions.
std::string getProgramStatusStr(const std::string &name) const
Return the status of a Program as a human readable string.
This program is currently not loaded in an ExecutionEngine.
bool activateStateMachine(const std::string &name)
Activate a previously loaded StateMachine.
Notify the Logger in which &#39;module&#39; the message occured.
Definition: Logger.hpp:159
This exception is thrown when a program or state machine could not be loaded into a ProgramProcessor ...
bool inStateMachineState(const std::string &name, const std::string &state) const
Check if a state machine is in a given state.
static Logger & log()
As Instance(), but more userfriendly.
Definition: Logger.cpp:117
bool stopStateMachine(const std::string &name)
Stops the execution of a scripting::StateMachine and enters the Final_State.
The TaskContext is the C++ representation of an Orocos component.
Definition: TaskContext.hpp:93
std::vector< ParsedStateMachinePtr > ParsedStateMachines
List of parsed State Machines.
Definition: Parser.hpp:113
bool evalInternal(const std::string &filename, const std::string &code)
void recursiveLoadStateMachine(StateMachinePtr sc)
std::vector< std::string > getProgramList() const
Get a list of all loaded Programs.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:51
This interface allows to load program scripts and state machines and allows execution of code...
bool stopProgram(const std::string &name)
Stops the execution of a program.
bool isStateMachinePaused(const std::string &name) const
Returns true if the state machine is paused.
bool ZeroPeriodWarning
This is a property of the Scripting service It is true by default If this is set to false...
int execute(const std::string &code)
Execute a script statement.
virtual bool runFunction(base::ExecutableInterface *f)
Run a given function in step() or loop().
bool runScript(const std::string &filename)
Run a script which is stored in a file.
bool doUnloadProgram(const std::string &name)
bool startStateMachine(const std::string &name)
Start a previously activated StateMachine.
bool deactivateStateMachine(const std::string &name)
Deactivate a stopped StateMachine.
bool doLoadStateMachines(const std::string &filename)
virtual bool loadStateMachines(const std::string &filename, bool do_throw)
Load a set of state machines into the StateMachineProcessor for execution.
const ExecutionEngine * engine() const
Get a const pointer to the ExecutionEngine of this Task.
Definition: TaskCore.hpp:327
virtual std::string getProgramText(const std::string &name) const
Get the original script description of a loaded program.
bool recursiveCheckUnloadStateMachine(StateMachinePtr si)
void clear()
Clear all added operations, properties and sub-services from this Service.
Definition: Service.cpp:217
virtual bool hasProgram(const std::string &name) const
Check if a program is loaded.