fipa_acl  1.4
statemachine_reader.cpp
Go to the documentation of this file.
1 #include "statemachine_reader.h"
2 
3 #include <iostream>
4 #include <algorithm>
5 #include <cstring>
6 #include <base-logging/Logging.hpp>
7 
8 #include <tinyxml.h>
9 #include <boost/filesystem/path.hpp>
10 
11 #include "transition.h"
12 
13 
14 namespace fipa {
15 namespace acl {
16 
17 const std::string StateMachineReader::transition = std::string("transition");
18 const std::string StateMachineReader::from = std::string("from");
19 const std::string StateMachineReader::to = std::string("to");
20 const std::string StateMachineReader::target = std::string("target");
21 const std::string StateMachineReader::id = std::string("id");
22 const std::string StateMachineReader::final = std::string("final");
23 const std::string StateMachineReader::performative = std::string("performative");
24 const std::string StateMachineReader::initial = std::string("initial");
25 const std::string StateMachineReader::subprotocol = std::string("subprotocol");
26 const std::string StateMachineReader::mapping = std::string("mapping");
27 const std::string StateMachineReader::name = std::string("name");
28 const std::string StateMachineReader::proxiedTo = std::string("proxied_to");
29 
30 StateMachine StateMachineReader::loadSpecification(const std::string& protocolSpec)
31 {
32  {
33  FILE* file = fopen(protocolSpec.c_str(), "r");
34  if(file)
35  {
36  fclose(file);
37  } else {
38  LOG_ERROR_S << "error loading the spec file: '" << protocolSpec << "'. File does not exist.";
39  throw std::runtime_error("Error loading the specification file: '" + protocolSpec + "' -- file does not exist");
40  }
41  }
42 
43  TiXmlDocument file = TiXmlDocument(protocolSpec.c_str());
44 
45  if (!file.LoadFile())
46  {
47  LOG_ERROR_S << "error loading the spec file: '" << protocolSpec << "'. Please use setProtocolResourceDir(const std::string&) instead to specify the location of your protocol files";
48  throw std::runtime_error("Error loading the specification file: '" + protocolSpec + "' -- tinyxml failed to load the file");
49  }
50 
51  LOG_DEBUG_S << "loadSpecification: specification file 'protocolSpec'";
52  TiXmlElement* statemachineElement = file.RootElement();
53 
54  StateMachine statemachine = parseStateMachineNode(statemachineElement);
55  // set protocol
56  boost::filesystem::path path(protocolSpec);
57  statemachine.setProtocol( path.filename().string());
58 
59  statemachine.generateDefaultTransitions();
60  statemachine.generateDefaultStates();
61  statemachine.updateRoles();
62  statemachine.validate();
63  statemachine.reset();
64  return statemachine;
65 }
66 
67 StateMachine StateMachineReader::parseStateMachineNode(TiXmlElement *statemachineElement)
68 {
69  StateMachine statemachine;
70 
71  const char *initialState;
72 
73  initialState = statemachineElement->Attribute(StateMachineReader::initial.c_str());
74  if (initialState)
75  {
76  statemachine.setInitialState(std::string(initialState));
77  } else {
78  throw std::runtime_error("Attribute of initial could not be retrieved");
79  }
80  LOG_DEBUG_S << "parseStateMachineNode: retrieved value of the \"initial\" state: " << std::string(initialState);
81 
82  TiXmlHandle handleSm = TiXmlHandle(statemachineElement);
83  TiXmlElement* stateElement = handleSm.FirstChild( "state" ).ToElement();
84  if (stateElement)
85  {
86  LOG_DEBUG_S << "parseStateMachineNode: found first state element";
87  } else {
88  LOG_WARN_S << "parseStateMachineNode: no state element found";
89  }
90 
91  // read states nodes
92  for (; stateElement != NULL; stateElement = stateElement->NextSiblingElement("state") )
93  {
94  State state = parseStateNode(stateElement);
95  LOG_DEBUG_S << "Adding state: " << state.toString();
96  statemachine.addState(state);
97  }
98 
99  return statemachine;
100 }
101 
102 State StateMachineReader::parseStateNode(TiXmlElement *stateElement)
103 {
104  State state;
105 
106  const char *stateId;
107  stateId = stateElement->Attribute(StateMachineReader::id.c_str());
108  if (stateId)
109  {
110  state.setId(std::string(stateId));
111  } else {
112  char buffer[512];
113  sprintf(buffer, "Attribute could not be retrieved %s", StateMachineReader::id.c_str());
114  throw std::runtime_error(std::string(buffer));
115  }
116 
117  const char* final = NULL;
118  final = stateElement->Attribute(StateMachineReader::final.c_str());
119  if (final)
120  {
121  std::string isFinal(final);
122  if (isFinal == "yes" || isFinal == "true" || isFinal == "1")
123  {
124  state.setFinal(true);
125  } else if (isFinal == "no" || isFinal == "false" || isFinal == "0")
126  {
127  state.setFinal(false);
128  } else {
129  char buffer[512];
130  sprintf(buffer, "Invalid value for attribute \"final\" of state node: %s", final);
131  throw std::runtime_error(std::string(buffer));
132  }
133  }
134 
135  // Read transitions
136  TiXmlHandle handleState = TiXmlHandle(stateElement);
137  TiXmlElement *transitionElement = handleState.FirstChildElement(StateMachineReader::transition).ToElement();
138  for (; transitionElement != NULL; transitionElement = transitionElement->NextSiblingElement(StateMachineReader::transition) )
139  {
140  Transition t = parseTransitionNode(transitionElement);
141  state.addTransition(t);
142 
143  LOG_DEBUG_S << "parseStateNode: state: " << state.getId() << " -> transition added: from (Role) " << t.getSenderRole().getId()
144  << ", to (Role) " << t.getReceiverRole().getId() << ", target state: " << t.getTargetStateId() << ", performative "
145  << t.getPerformativeRegExp();
146  }
147 
148  // TODO allow only 1 subProtocol per state? Throw otherwise.
149  // Also adapt the structs, etc.
150 
151  // Read subprotocols
152  TiXmlElement *subProtocolElement = handleState.FirstChildElement(StateMachineReader::subprotocol).ToElement();
153  for (; subProtocolElement != NULL; subProtocolElement = subProtocolElement->NextSiblingElement(StateMachineReader::subprotocol) )
154  {
156 
157  const std::string* name = subProtocolElement->Attribute(StateMachineReader::name);
158  if (name != NULL)
159  {
160  esm.name = *name;
161  } else {
162  throw new std::runtime_error("StateMachineReader::parseStateNode subprotocol is missing 'name' attribute");
163  }
164 
165  const std::string* from = subProtocolElement->Attribute(StateMachineReader::from);
166  if (from != NULL)
167  {
168  esm.from = *from;
169  esm.fromRole = Role( std::string(from->c_str()));
170  } else {
171  throw new std::runtime_error("StateMachineReader::parseStateNode mapping is missing 'from' attribute");
172  }
173 
174  const std::string* proxiedTo = subProtocolElement->Attribute(StateMachineReader::proxiedTo);
175  if (proxiedTo != NULL)
176  {
177  esm.proxiedTo = *proxiedTo;
178  esm.proxiedToRole = Role( std::string(proxiedTo->c_str()));
179  }
180 
181  state.addEmbeddedStateMachine(esm);
182  LOG_DEBUG_S << "parseStateNode: state: " << state.getId() << " -> subprotocol added:\n" << esm.toString();
183  }
184 
185  return state;
186 }
187 
188 Transition StateMachineReader::parseTransitionNode(TiXmlElement *transitionElement)
189 {
191  const char *from = NULL;
192  from = transitionElement->Attribute(StateMachineReader::from.c_str());
193  if ( from )
194  {
195  transition.setSenderRole( Role( std::string(from) ));
196  } else {
197  throw new std::runtime_error("StateMachineReader::parseTransitionsNode Transitions is missing 'from' attribute");
198  }
199 
200  const char* to = NULL;
201  to = transitionElement->Attribute(StateMachineReader::to.c_str());
202  if (to)
203  {
204  transition.setReceiverRole( Role( std::string(to) ) );
205  } else {
206  throw new std::runtime_error("StateMachineReader::parseTransitionsNode transition is missing 'to' attribute");
207  }
208 
209  const char* targetState = NULL;
210  targetState = transitionElement->Attribute(StateMachineReader::target.c_str());
211  if (targetState)
212  {
213  transition.setTargetState(std::string(targetState));
214  } else {
215  LOG_ERROR_S << "Could not retrieve attribute for target state: " << StateMachineReader::target;
216  throw std::runtime_error("Could not retrieve attribute for target state");
217  }
218 
219  const char* performative = NULL;
220  performative = transitionElement->Attribute(StateMachineReader::performative.c_str());
221  if (performative)
222  {
223  transition.setPerformativeRegExp( performative );
224  } else {
225  throw new std::runtime_error("StateMachineReader::parseTransitionsNode transition is missing 'performative' attribute");
226  }
227 
228  return transition;
229 }
230 
231 } //end of namespace acl
232 } //end of namespace fipa
State parseStateNode(TiXmlElement *stateElement)
method that parses the <state> element of the spec. file
describes the structure and operation of a transition of the state machine
static const std::string id
void setPerformativeRegExp(const std::string &performativeRegExp)
setter methods for various fields of the class
Definition: transition.h:85
void setProtocol(const fipa::acl::Protocol &protocol)
Definition: statemachine.h:140
void setSenderRole(const Role &role)
Definition: transition.h:106
void setReceiverRole(const Role &role)
Definition: transition.h:111
void addEmbeddedStateMachine(fipa::acl::EmbeddedStateMachine embeddedStateMachine)
Definition: state.cpp:357
implements a state of the StateMachine class
Definition: state.h:41
static const std::string name
static const std::string target
void setId(const StateId &id)
setter method for the uid field of the state NOTE: maybe should be taken out and name only be allowed...
Definition: state.h:176
void setInitialState(const StateId &stateId)
Definition: statemachine.h:79
std::string getId() const
getter method for the uid field of the class
Definition: state.h:181
Role getReceiverRole() const
Definition: transition.h:121
static const std::string to
void setFinal(bool final)
setter method for the final field of the class When changing the final state flag make sure you eithe...
Definition: state.h:97
An embedded state machine with mappings.
Definition: statemachine.h:200
Role getSenderRole() const
Definition: transition.h:116
std::string toString() const
Definition: state.cpp:362
RoleId getId() const
Definition: role.h:52
static const std::string transition
std::string toString() const
static const std::string performative
void addState(const State &state)
static const std::string subprotocol
static const std::string from
void setTargetState(const StateId &stateId)
Definition: transition.h:101
StateMachine parseStateMachineNode(TiXmlElement *statemachineElement)
static const std::string proxiedTo
static const std::string mapping
StateMachine loadSpecification(const std::string &file)
Transition parseTransitionNode(TiXmlElement *transitionElement)
method that parses <transition> element of the spec. file
static const std::string initial
StateId getTargetStateId() const
Definition: transition.h:138
Transition addTransition(const Transition &t)
Definition: state.cpp:45
std::string getPerformativeRegExp() const
getter methods for various fields of the class
Definition: transition.h:128
defines the StateMachineReader Class, used to generate a state macine from a spec. file
static const std::string final