예제 #1
0
Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectEventlessTransitions() {
	Arabica::XPath::NodeSet<std::string> enabledTransitions;

	NodeSet<std::string> states;
	for (unsigned int i = 0; i < _configuration.size(); i++) {
		if (isAtomic(_configuration[i]))
			states.push_back(_configuration[i]);
	}
	states.to_document_order();

#if 0
	std::cout << "Atomic States: ";
	for (int i = 0; i < atomicStates.size(); i++) {
		std::cout << ATTR(atomicStates[i], "id") << ", ";
	}
	std::cout << std::endl;
#endif

	unsigned int index = 0;
	while(states.size() > index) {
		bool foundTransition = false;
		NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", states[index]);
		for (unsigned int k = 0; k < transitions.size(); k++) {
			if (!HAS_ATTR(transitions[k], "event") && hasConditionMatch(transitions[k])) {
				enabledTransitions.push_back(transitions[k]);
				foundTransition = true;
				goto LOOP;
			}
		}
		if (!foundTransition) {
			Node<std::string> parent = states[index].getParentNode();
			if (parent) {
				states.push_back(parent);
			}
		}
LOOP:
		index++;
	}

#if 0
	std::cout << "Enabled eventless transitions: " << std::endl;
	for (int i = 0; i < enabledTransitions.size(); i++) {
		std::cout << enabledTransitions[i] << std::endl << "----" << std::endl;
	}
	std::cout << std::endl;
#endif

	enabledTransitions = filterPreempted(enabledTransitions);
	return enabledTransitions;
}
예제 #2
0
  void sort(const DOMNode& node, 
            NodeSet& nodes, 
            ExecutionContext<string_type, string_adaptor>& context) const
  {
    if(!sort_)
    {
      if(!nodes.forward())
        nodes.to_document_order();
      return;
    }

    sort_->set_context(node, context);
    std::stable_sort(nodes.begin(), nodes.end(), SortP(*sort_));
  } // sort
예제 #3
0
void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
	NodeSet<std::string> statesToEnter;
	NodeSet<std::string> statesForDefaultEntry;
	monIter_t monIter;

#if VERBOSE
	std::cout << _name << ": Enabled enter transitions: " << std::endl;
	for (int i = 0; i < enabledTransitions.size(); i++) {
		std::cout << "\t" << enabledTransitions[i] << std::endl;
	}
	std::cout << std::endl;
#endif

	for (int i = 0; i < enabledTransitions.size(); i++) {
		Element<std::string> transition = ((Element<std::string>)enabledTransitions[i]);
		if (!isTargetless(transition)) {
			std::string transitionType = (iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
			NodeSet<std::string> tStates = getTargetStates(transition);

#if VERBOSE
			std::cout << _name << ": Target States: ";
			for (int i = 0; i < tStates.size(); i++) {
				std::cout << ATTR(tStates[i], "id") << ", ";
			}
			std::cout << std::endl;
#endif

			Node<std::string> ancestor;
			Node<std::string> source = getSourceState(transition);
#if VERBOSE
			std::cout << _name << ": Source States: " << ATTR(source, "id") << std::endl;
#endif
			assert(source);

			bool allDescendants = true;
			for (int j = 0; j < tStates.size(); j++) {
				if (!isDescendant(tStates[j], source)) {
					allDescendants = false;
					break;
				}
			}
			if (iequals(transitionType, "internal") &&
			        isCompound(source) &&
			        allDescendants) {
				ancestor = source;
			} else {
				NodeSet<std::string> tmpStates;
				tmpStates.push_back(source);
				tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());

				ancestor = findLCCA(tmpStates);
			}

#if VERBOSE
			std::cout << _name << ": Ancestor: " << ATTR(ancestor, "id") << std::endl;
#endif

			for (int j = 0; j < tStates.size(); j++) {
				addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry);
			}

#if VERBOSE
			std::cout << _name << ": States to enter: ";
			for (int i = 0; i < statesToEnter.size(); i++) {
				std::cout << LOCALNAME(statesToEnter[i]) << ":" << ATTR(statesToEnter[i], "id") << ", ";
			}
			std::cout << std::endl;
#endif

			for (int j = 0; j < tStates.size(); j++) {
				NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor);

#if VERBOSE
				std::cout << _name << ": Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": ";
				for (int i = 0; i < ancestors.size(); i++) {
					std::cout << ATTR(ancestors[i], "id") << ", ";
				}
				std::cout << std::endl;
#endif

				for (int k = 0; k < ancestors.size(); k++) {
					statesToEnter.push_back(ancestors[k]);
					if(isParallel(ancestors[k])) {
						NodeSet<std::string> childs = getChildStates(ancestors[k]);
						for (int l = 0; l < childs.size(); l++) {
							bool someIsDescendant = false;
							for (int m = 0; m < statesToEnter.size(); m++) {
								if (isDescendant(statesToEnter[m], childs[l])) {
									someIsDescendant = true;
									break;
								}
							}
							if (!someIsDescendant) {
								addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry);
							}
						}
					}
				}
			}
		}
	}
	statesToEnter.to_document_order();

#if VERBOSE
	std::cout << _name << ": States to enter: ";
	for (int i = 0; i < statesToEnter.size(); i++) {
		std::cout << ATTR(statesToEnter[i], "id") << ", ";
	}
	std::cout << std::endl;
#endif

	for (int i = 0; i < statesToEnter.size(); i++) {
		Element<std::string> stateElem = (Element<std::string>)statesToEnter[i];

		// extension for flattened interpreters
		for (unsigned int k = 0; k < statesToEnter.size(); k++) {
			NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToEnter[k]);
			for (unsigned int j = 0; j < invokes.size(); j++) {
				if (HAS_ATTR(invokes[j], "persist") && DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) {
					invoke(invokes[j]);
				}
			}
		}

		// --- MONITOR: beforeEnteringState ------------------------------
		for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
			try {
				(*monIter)->beforeEnteringState(shared_from_this(), stateElem, (i + 1 < statesToEnter.size()));
			}
			USCXML_MONITOR_CATCH_BLOCK(beforeEnteringState)
		}

		// extension for flattened SCXML documents, we will need an explicit uninvoke element
		NodeSet<std::string> uninvokes = filterChildElements(_nsInfo.xmlNSPrefix + "uninvoke", statesToEnter[i]);
		for (int j = 0; j < uninvokes.size(); j++) {
			Element<std::string> uninvokeElem = (Element<std::string>)uninvokes[j];
			cancelInvoke(uninvokeElem);
		}

		_configuration.push_back(stateElem);
		_statesToInvoke.push_back(stateElem);

//		if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) {
		if (_binding == LATE && !isMember(stateElem, _alreadyEntered)) {
			NodeSet<std::string> dataModelElems = filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", stateElem);
			if(dataModelElems.size() > 0 && _dataModel) {
				Arabica::XPath::NodeSet<std::string> dataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", dataModelElems[0]);
				for (int j = 0; j < dataElems.size(); j++) {
					if (dataElems[j].getNodeType() == Node_base::ELEMENT_NODE)
						initializeData(Element<std::string>(dataElems[j]));
				}
			}
			_alreadyEntered.push_back(stateElem);
//			stateElem.setAttribute("isFirstEntry", "");
		}
		// execute onentry executable content
		NodeSet<std::string> onEntryElems = filterChildElements(_nsInfo.xmlNSPrefix + "onEntry", stateElem);
		executeContent(onEntryElems, false);

		// --- MONITOR: afterEnteringState ------------------------------
		for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
			try {
				(*monIter)->afterEnteringState(shared_from_this(), stateElem, (i + 1 < statesToEnter.size()));
			}
			USCXML_MONITOR_CATCH_BLOCK(afterEnteringState)
		}

		if (isMember(stateElem, statesForDefaultEntry)) {
			// execute initial transition content for compound states
			Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", stateElem).asNodeSet();
			for (int j = 0; j < transitions.size(); j++) {
				executeContent(transitions[j]);
			}
		}

		if (isFinal(stateElem)) {
			internalDoneSend(stateElem);
			Element<std::string> parent = (Element<std::string>)stateElem.getParentNode();

			if (isParallel(parent.getParentNode())) {
				Element<std::string> grandParent = (Element<std::string>)parent.getParentNode();

				Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent);
				bool inFinalState = true;
				for (int j = 0; j < childs.size(); j++) {
					if (!isInFinalState(childs[j])) {
						inFinalState = false;
						break;
					}
				}
				if (inFinalState) {
					internalDoneSend(parent);
				}
			}
		}
	}
	for (int i = 0; i < _configuration.size(); i++) {
		Element<std::string> stateElem = (Element<std::string>)_configuration[i];
		if (isFinal(stateElem) && parentIsScxmlState(stateElem)) {
			_running = false;
			_done = true;
		}
	}
}
예제 #4
0
void InterpreterDraft6::mainEventLoop() {
	monIter_t monIter;

	while(_running) {
		NodeSet<std::string> enabledTransitions;
		_stable = false;

		// Here we handle eventless transitions and transitions
		// triggered by internal events until machine is stable
		while(_running && !_stable) {
#if VERBOSE
			std::cout << "Configuration: ";
			for (int i = 0; i < _configuration.size(); i++) {
				std::cout << ATTR(_configuration[i], "id") << ", ";
			}
			std::cout << std::endl;
#endif

			enabledTransitions = selectEventlessTransitions();
			if (enabledTransitions.size() == 0) {
				if (_internalQueue.size() == 0) {
					_stable = true;
				} else {
					_currEvent = _internalQueue.front();
					_internalQueue.pop_front();
#if VERBOSE
					std::cout << "Received internal event " << _currEvent.name << std::endl;
#endif

					// --- MONITOR: beforeProcessingEvent ------------------------------
					for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
						try {
							(*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
						}
						USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
					}

					if (_dataModel)
						_dataModel.setEvent(_currEvent);
					enabledTransitions = selectTransitions(_currEvent.name);
				}
			}
			if (!enabledTransitions.empty()) {
				// test 403b
				enabledTransitions.to_document_order();
				microstep(enabledTransitions);
			}
		}

		for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
			NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]);
			for (unsigned int j = 0; j < invokes.size(); j++) {
				if (!HAS_ATTR(invokes[j], "persist") || !DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) {
					invoke(invokes[j]);
				}
			}
		}
		_statesToInvoke = NodeSet<std::string>();

		if (!_internalQueue.empty())
			continue;

		// assume that we have a legal configuration as soon as the internal queue is empty
		assert(hasLegalConfiguration());

		monIter = _monitors.begin();

		// --- MONITOR: onStableConfiguration ------------------------------
		for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
			try {
				(*monIter)->onStableConfiguration(shared_from_this());
			}
			USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
		}

		_mutex.unlock();
		
		// whenever we have a stable configuration, run the mainThread hooks with 200fps
		while(_externalQueue.isEmpty() && _thread == NULL) {
			runOnMainThread(200);
		}
		_mutex.lock();

		while(_externalQueue.isEmpty()) {
			_condVar.wait(_mutex);
		}
		_currEvent = _externalQueue.pop();
#if VERBOSE
		std::cout << "Received externalEvent event " << _currEvent.name << std::endl;
		if (_running && _currEvent.name == "unblock.and.die") {
			std::cout << "Still running " << this << std::endl;
		} else {
			std::cout << "Aborting " << this << std::endl;
		}
#endif
		_currEvent.eventType = Event::EXTERNAL; // make sure it is set to external
		if (!_running)
			goto EXIT_INTERPRETER;

		// --- MONITOR: beforeProcessingEvent ------------------------------
		for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
			try {
				(*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
			}
			USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
		}

		if (_dataModel && iequals(_currEvent.name, "cancel.invoke." + _sessionId))
			break;

		if (_dataModel) {
			try {
				_dataModel.setEvent(_currEvent);
			} catch (Event e) {
				LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent;
			}
		}
		for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin();
		        invokeIter != _invokers.end();
		        invokeIter++) {
			if (iequals(invokeIter->first, _currEvent.invokeid)) {
				Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeIter->second.getElement());
				for (int k = 0; k < finalizes.size(); k++) {
					Element<std::string> finalizeElem = Element<std::string>(finalizes[k]);
					executeContent(finalizeElem);
				}
			}
			if (HAS_ATTR(invokeIter->second.getElement(), "autoforward") && DOMUtils::attributeIsTrue(ATTR(invokeIter->second.getElement(), "autoforward"))) {
				try {
					// do not autoforward to invokers that send to #_parent from the SCXML IO Processor!
					// Yes do so, see test229!
					// if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"))
					invokeIter->second.send(_currEvent);
				} catch(...) {
					LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first;
				}
			}
		}
		enabledTransitions = selectTransitions(_currEvent.name);
		if (!enabledTransitions.empty()) {
			// test 403b
			enabledTransitions.to_document_order();
			microstep(enabledTransitions);
		}
	}

EXIT_INTERPRETER:
	// --- MONITOR: beforeCompletion ------------------------------
	for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
		try {
			(*monIter)->beforeCompletion(shared_from_this());
		}
		USCXML_MONITOR_CATCH_BLOCK(beforeCompletion)
	}

	exitInterpreter();
	if (_sendQueue) {
		std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin();
		while(sendIter != _sendIds.end()) {
			_sendQueue->cancelEvent(sendIter->first);
			sendIter++;
		}
	}

	// --- MONITOR: afterCompletion ------------------------------
	for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
		try {
			(*monIter)->afterCompletion(shared_from_this());
		}
		USCXML_MONITOR_CATCH_BLOCK(afterCompletion)
	}

}
예제 #5
0
// process transitions until we are in a stable configuration again
void InterpreterDraft6::stabilize() {

	monIter_t monIter;
	NodeSet<std::string> enabledTransitions;
	_stable = false;
	
	if (_configuration.size() == 0) {
		// goto initial configuration
		NodeSet<std::string> initialTransitions = getDocumentInitialTransitions();
		assert(initialTransitions.size() > 0);
		enterStates(initialTransitions);
	}
	
	do { // process microsteps for enabled transitions until there are no more left

		enabledTransitions = selectEventlessTransitions();
		
		if (enabledTransitions.size() == 0) {
			if (_internalQueue.size() == 0) {
				_stable = true;
			} else {
				_currEvent = _internalQueue.front();
				_internalQueue.pop_front();
#if VERBOSE
				std::cout << "Received internal event " << _currEvent.name << std::endl;
#endif
				
				// --- MONITOR: beforeProcessingEvent ------------------------------
				for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
					try {
						(*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
					}
					USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
				}
				
				if (_dataModel)
					_dataModel.setEvent(_currEvent);
				enabledTransitions = selectTransitions(_currEvent.name);
			}
		}
		
		if (!enabledTransitions.empty()) {
			// test 403b
			enabledTransitions.to_document_order();
			microstep(enabledTransitions);
		}
	} while(!_internalQueue.empty() || !_stable);
	
	monIter = _monitors.begin();
	
	// --- MONITOR: onStableConfiguration ------------------------------
	for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
		try {
			(*monIter)->onStableConfiguration(shared_from_this());
		}
		USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
	}

	// when we reach a stable configuration, invoke
	for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
		NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]);
		for (unsigned int j = 0; j < invokes.size(); j++) {
			if (!HAS_ATTR(invokes[j], "persist") || !DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) {
				invoke(invokes[j]);
			}
		}
	}
	_statesToInvoke = NodeSet<std::string>();

}
예제 #6
0
// a macrostep
InterpreterState InterpreterDraft6::step(bool blocking) {
	try {

		monIter_t monIter;
		NodeSet<std::string> enabledTransitions;
		
		// setup document and interpreter
		if (!_isInitialized)
			init();
		
		// if we failed return false
		if (!_isInitialized)
			return INIT_FAILED;
		
		// run initial transitions
		if (!_stable) {
			stabilize();
			// we might only need a single step
			if (!_running)
				goto EXIT_INTERPRETER;
			return INITIALIZED;
		}
		
		if (!_running)
			return FINISHED;
		
		// read an external event and react
		if (blocking) {
			// wait until an event becomes available
			while(_externalQueue.isEmpty()) {
				_condVar.wait(_mutex);
			}
		} else {
			// return immediately if external queue is empty
			if (_externalQueue.isEmpty())
				return NOTHING_TODO;
		}
		_currEvent = _externalQueue.pop();

	#if VERBOSE
		std::cout << "Received externalEvent event " << _currEvent.name << std::endl;
		if (_running && _currEvent.name == "unblock.and.die") {
			std::cout << "Still running " << this << std::endl;
		} else {
			std::cout << "Aborting " << this << std::endl;
		}
	#endif
		_currEvent.eventType = Event::EXTERNAL; // make sure it is set to external

		// when we were blocking on destructor invocation
		if (!_running) {
			goto EXIT_INTERPRETER;
			return INTERRUPTED;
		}
		// --- MONITOR: beforeProcessingEvent ------------------------------
		for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
			try {
				(*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
			}
			USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
		}
		
		if (iequals(_currEvent.name, "cancel.invoke." + _sessionId))
			return INTERRUPTED;
		
		try {
			_dataModel.setEvent(_currEvent);
		} catch (Event e) {
			LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent;
		}

		for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin();
				 invokeIter != _invokers.end();
				 invokeIter++) {
			if (iequals(invokeIter->first, _currEvent.invokeid)) {
				Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeIter->second.getElement());
				for (int k = 0; k < finalizes.size(); k++) {
					Element<std::string> finalizeElem = Element<std::string>(finalizes[k]);
					executeContent(finalizeElem);
				}
			}
			if (HAS_ATTR(invokeIter->second.getElement(), "autoforward") && DOMUtils::attributeIsTrue(ATTR(invokeIter->second.getElement(), "autoforward"))) {
				try {
					// do not autoforward to invokers that send to #_parent from the SCXML IO Processor!
					// Yes do so, see test229!
					// if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"))
					invokeIter->second.send(_currEvent);
				} catch(...) {
					LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first;
				}
			}
		}

		
		// run internal processing until we reach a stable configuration again
		enabledTransitions = selectTransitions(_currEvent.name);
		if (!enabledTransitions.empty()) {
			// test 403b
			enabledTransitions.to_document_order();
			microstep(enabledTransitions);
		}

		stabilize();
		return PROCESSED;
		
	EXIT_INTERPRETER:
		if (!_running) {
			// --- MONITOR: beforeCompletion ------------------------------
			for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
				try {
					(*monIter)->beforeCompletion(shared_from_this());
				}
				USCXML_MONITOR_CATCH_BLOCK(beforeCompletion)
			}
			
			exitInterpreter();
			if (_sendQueue) {
				std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin();
				while(sendIter != _sendIds.end()) {
					_sendQueue->cancelEvent(sendIter->first);
					sendIter++;
				}
			}
			
			// --- MONITOR: afterCompletion ------------------------------
			for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
				try {
					(*monIter)->afterCompletion(shared_from_this());
				}
				USCXML_MONITOR_CATCH_BLOCK(afterCompletion)
			}
			return FINISHED;
		}
		
		assert(hasLegalConfiguration());
		_mutex.unlock();

		// remove datamodel
		if(_dataModel)
			_dataModel = DataModel();

		return PROCESSED;
		
	} catch (boost::bad_weak_ptr e) {
		LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
		return INTERRUPTED;
	}
	
	// set datamodel to null from this thread
	if(_dataModel)
		_dataModel = DataModel();

}