26 , sequenceFlow(nullptr)
27 , state(
State::CREATED)
30 , globals(const_cast<
SystemState*>(owner->systemState)->globals)
39 , sequenceFlow(nullptr)
41 , status(other->status)
43 , globals(const_cast<
SystemState*>(owner->systemState)->globals)
49 : owner(others.front()->owner)
51 , node(others.front()->node)
52 , sequenceFlow(nullptr)
53 , state(others.front()->state)
54 , status(mergeStatus(others))
56 , globals(const_cast<
SystemState*>(owner->systemState)->globals)
68 engine->commands.emplace_back(std::bind(&StateMachine::deleteTokensAwaitingBoundaryEvent,stateMachine,
this),
this);
72 systemState->tokenAssociatedToBoundaryEventToken.erase(
this);
80 systemState->tokenAwaitingCompensationActivity.erase(
this);
84 systemState->tokensAwaitingEvent.erase(
this);
87 systemState->tokenAtEventBasedGateway.erase(
this);
92 auto it = systemState->messageAwaitingDelivery.find(
this);
93 if ( it != systemState->messageAwaitingDelivery.end() ) {
94 auto message = it->second.lock();
101 systemState->messageAwaitingDelivery.erase(it);
107 auto tokenAtSequentialPerformer = getSequentialPerfomerToken();
108 if ( tokenAtSequentialPerformer && tokenAtSequentialPerformer->performing ==
this ) {
109 releaseSequentialPerformer();
113 if ( activity->loopCharacteristics.has_value() &&
114 !activity->isForCompensation
118 systemState->tokensAtActivityInstance.erase(
this);
119 systemState->exitStatusAtActivityInstance.erase(
this);
122 systemState->tokenAtMultiInstanceActivity.erase(
this);
124 systemState->tokenAwaitingMultiInstanceExit.erase(
this);
145 return extensionElements->attributeRegistry;
150 throw std::runtime_error(
"Token: cannot determine attribute registry");
158 size_t size = ( other.size() >=
status.size() ?
status.size() : other.size() );
159 std::copy(other.begin() + 1, other.begin() + (std::ptrdiff_t)size ,
status.begin()+1);
163 nlohmann::ordered_json jsonObject;
167 jsonObject[
"nodeId"] =
node->
id;
173 jsonObject[
"status"] = nlohmann::ordered_json::object();
176 for (
auto& [attributeName,attribute] : attributeRegistry.statusAttributes ) {
177 if ( attribute->index >=
status.size() ) {
183 if ( !statusValue.has_value() ) {
184 jsonObject[
"status"][attributeName] = nullptr ;
186 else if ( attribute->type ==
BOOLEAN) {
187 bool value = (bool)statusValue.value();
188 jsonObject[
"status"][attributeName] = value ;
190 else if ( attribute->type ==
INTEGER) {
191 int value = (int)statusValue.value();
192 jsonObject[
"status"][attributeName] = value ;
194 else if ( attribute->type ==
DECIMAL) {
195 double value = (double)statusValue.value();
196 jsonObject[
"status"][attributeName] = value ;
198 else if ( attribute->type ==
STRING) {
200 jsonObject[
"status"][attributeName] = value ;
204 jsonObject[
"status"][attributeName] = value ;
210 if (
data->size() ) {
211 jsonObject[
"data"] = nlohmann::ordered_json::object();
213 for (
auto& [attributeName,attribute] : attributeRegistry.dataAttributes ) {
214 if ( attribute->index >=
data->size() ) {
220 if ( !dataValue.has_value() ) {
221 jsonObject[
"data"][attributeName] = nullptr ;
223 else if ( attribute->type ==
BOOLEAN) {
224 bool value = (bool)dataValue.value();
225 jsonObject[
"data"][attributeName] = value ;
227 else if ( attribute->type ==
INTEGER) {
228 int value = (int)dataValue.value();
229 jsonObject[
"data"][attributeName] = value ;
231 else if ( attribute->type ==
DECIMAL) {
232 double value = (double)dataValue.value();
233 jsonObject[
"data"][attributeName] = value ;
235 else if ( attribute->type ==
STRING) {
237 jsonObject[
"data"][attributeName] = value ;
241 jsonObject[
"data"][attributeName] = value ;
247 jsonObject[
"globals"] = nlohmann::ordered_json::object();
249 for (
auto& [attributeName,attribute] : attributeRegistry.globalAttributes ) {
250 auto globalValue =
globals[attribute->index];
251 if ( !globalValue.has_value() ) {
252 jsonObject[
"globals"][attributeName] = nullptr ;
254 else if ( attribute->type ==
BOOLEAN) {
255 bool value = (bool)globalValue.value();
256 jsonObject[
"globals"][attributeName] = value ;
258 else if ( attribute->type ==
INTEGER) {
259 int value = (int)globalValue.value();
260 jsonObject[
"globals"][attributeName] = value ;
262 else if ( attribute->type ==
DECIMAL) {
263 double value = (double)globalValue.value();
264 jsonObject[
"globals"][attributeName] = value ;
266 else if ( attribute->type ==
STRING) {
268 jsonObject[
"globals"][attributeName] = value ;
272 jsonObject[
"globals"][attributeName] = value ;
281bool Token::entryIsFeasible()
const {
292bool Token::exitIsFeasible()
const {
303void Token::advanceFromCreated() {
320void Token::advanceToReady() {
323 throw std::runtime_error(
"Token: ready timestamp at node '" +
node->
id +
"' is larger than current time");
341 engine->
commands.emplace_back(std::bind(&StateMachine::createMultiInstanceActivityTokens,stateMachine,
this),
this);
354void Token::advanceToEntered() {
359 throw std::runtime_error(
"Token: entry timestamp at node '" +
node->
id +
"' is larger than current time");
362 throw std::runtime_error(
"Token: entry timestamp for process '" +
owner->
process->
id +
"' is larger than current time");
369 assert( extensionElements );
371 computeInitialValues( extensionElements );
376 assert( extensionElements );
379 activity->loopCharacteristics.has_value() &&
384 if ( extensionElements->
loopIndex.has_value() && extensionElements->
loopIndex.value()->expression ) {
386 auto attribute = extensionElements->
loopIndex.value()->expression->isAttribute();
387 if (
auto index = attributeRegistry.getValue( attribute,
status, *
data,
globals); index.has_value() ) {
389 attributeRegistry.setValue(attribute,
status, *
data,
globals, (
unsigned int)index.value() + 1);
396 else if ( extensionElements->
loopMaximum.has_value() ) {
397 throw std::runtime_error(
"Token: no attribute provided for loop index parameter of standard loop activity '" +
node->
id +
"' with loop maximum" );
401 computeInitialValues( extensionElements );
417 owned->registerRecipient();
428 engine->commands.emplace_back(std::bind(&StateMachine::initiateEventSubprocesses,stateMachine,
this),
this);
437 if ( !entryIsFeasible() ) {
438 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
443 engine->commands.emplace_back(std::bind(&Token::advanceToBusy,
this),
this);
451 if ( activity->boundaryEvents.size() ) {
452 engine->commands.emplace_back(std::bind(&StateMachine::initiateBoundaryEvents,stateMachine,
this),
this);
457 if ( !entryIsFeasible() ) {
458 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
463 engine->commands.emplace_back(std::bind(&Token::advanceToBusy,
this),
this);
470 engine->commands.emplace_back(std::bind(&Token::advanceToBusy,
this),
this);
475 engine->commands.emplace_back(std::bind(&Token::advanceToBusy,
this),
this);
478 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
485 engine->commands.emplace_back(std::bind(&StateMachine::handleEscalation,
const_cast<StateMachine*
>(
owner),
this),
this);
504 auto it = std::find_if(
505 context->compensableSubProcesses.begin(),
506 context->compensableSubProcesses.end(),
507 [&eventSubProcess](
const std::shared_ptr<StateMachine>& stateMachine) ->
bool {
509 return ( stateMachine->scope->compensationEventSubProcess == eventSubProcess );
512 context = ( it != context->compensableSubProcesses.end() ? it->get() :
nullptr );
517 if (
auto compensations = context->getCompensationTokens(compensateThrowEvent->activity);
521 engine->commands.emplace_back(std::bind(&Token::update,
this,
State::BUSY),
this);
522 context->compensate( std::move(compensations),
this );
532 engine->commands.emplace_back(std::bind(&Token::advanceToDone,
this),
this);
535 advanceToDeparting();
539void Token::advanceToBusy() {
549 extensionElements && extensionElements->
operators.size()
556 throw std::runtime_error(
"Token: timestamp at node '" +
node->
id +
"' is deleted");
560 throw std::runtime_error(
"Token: Operators for task '" +
node->
id +
"' attempt to modify timestamp");
577 if ( scope->startNodes.empty() ) {
579 engine->
commands.emplace_back(std::bind(&Token::advanceToCompleted,
this),
this);
582 if ( scope->startNodes.size() == 1 ) {
590 throw std::runtime_error(
"Token: process '" + scope->id +
"' has multiple start nodes");
597 if ( scope->startNodes.empty() ) {
599 engine->
commands.emplace_back(std::bind(&Token::advanceToCompleted,
this),
this);
610 if ( scope->startNodes.empty() ) {
613 engine->
commands.emplace_back(std::bind(&Token::advanceToCompleted,
this),
this);
616 if ( scope->startNodes.size() == 1 ) {
624 throw std::runtime_error(
"Token: subprocess '" + scope->id +
"' has multiple start nodes");
632 engine->
commands.emplace_back(std::bind(&Token::advanceToDeparting,
this),
this);
637 if (!trigger->expression) {
638 throw std::runtime_error(
"Token: no trigger given for node '" +
node->
id +
"'");
647 engine->
commands.emplace_back(std::bind(&Token::advanceToCompleted,
this),
this);
664 engine->
commands.emplace_back(std::bind(&Token::advanceToCompleted,
this),
this);
668 awaitMessageDelivery();
680 if ( sendTask->loopCharacteristics.has_value() ) {
682 if ( !extensionElements->
loopIndex.has_value() || !extensionElements->
loopIndex->get()->expression ) {
683 throw std::runtime_error(
"Token: send task '" + sendTask->id +
"' requires status attribute holding loop index");
685 auto attribute = extensionElements->
loopIndex->get()->expression->isAttribute();
686 if ( !
status[attribute->index].has_value() ) {
687 throw std::runtime_error(
"Token: cannot find loop index for send task '" + sendTask->id +
"'");
689 assert(
status[attribute->index].value() >= 1 );
690 sendMessage( (
size_t)(
int)
status[attribute->index].value()-1 );
699 awaitTaskCompletionEvent();
704 engine->
commands.emplace_back(std::bind(&Token::advanceToCompleted,
this),
this);
715void Token::advanceToCompleted() {
718 throw std::runtime_error(
"Token: completion timestamp at node '" +
node->
id +
"' is larger than current time");
721 throw std::runtime_error(
"Token: completion timestamp for process '" +
owner->
process->
id +
"' is larger than current time");
735 throw std::runtime_error(
"Token: Operators for task '" +
node->
id +
"' attempt to modify timestamp");
761 if ( !exitIsFeasible() ) {
763 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
769 if ( activity->compensatedBy ) {
770 if ( activity->isForCompensation ) {
771 throw std::runtime_error(
"Token: compensation activity '" + activity->id +
"' must not be compensated");
777 if ( activity->isForCompensation ) {
779 if ( !exitIsFeasible() ) {
780 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
785 engine->commands.emplace_back(std::bind(&StateMachine::completeCompensationActivity,stateMachine,
this),
this);
798 engine->commands.emplace_back(std::bind(&StateMachine::compensateActivity,
const_cast<StateMachine*
>(
owner),
this),
this);
806 if ( boundaryEvent->isInterrupting ) {
808 engine->commands.emplace_back(std::bind(&StateMachine::interruptActivity,stateMachine,tokenAtActivity), tokenAtActivity);
812 engine->commands.emplace_back(std::bind(&StateMachine::initiateBoundaryEvent,stateMachine,tokenAtActivity,
node), tokenAtActivity);
821 throw std::runtime_error(
"Token: typed start event must belong to event subprocess");
831 auto it = std::find_if(context->pendingEventSubProcesses.begin(), context->pendingEventSubProcesses.end(), [
this](std::shared_ptr<StateMachine>& eventSubProcess) {
832 auto pendingToken = eventSubProcess->tokens.front();
833 return pendingToken.get() == this;
836 assert( it != context->pendingEventSubProcesses.end() );
838 if ( startEvent->isInterrupting ) {
842 context->interruptingEventSubProcess = std::move(*it);
843 context->pendingEventSubProcesses.erase(it);
846 for (
auto eventSubProcess : context->pendingEventSubProcesses ) {
847 eventSubProcess->clearObsoleteTokens();
849 context->pendingEventSubProcesses.clear();
852 for (
auto eventSubProcess : context->nonInterruptingEventSubProcesses ) {
853 eventSubProcess->clearObsoleteTokens();
855 context->nonInterruptingEventSubProcesses.clear();
858 context->clearObsoleteTokens();
863 std::shared_ptr pendingEventSubProcess = std::make_shared<StateMachine>(it->get());
866 context->nonInterruptingEventSubProcesses.push_back(std::move(*it));
869 *it = pendingEventSubProcess;
874 auto eventSubProcess = context->pendingEventSubProcesses.back().get();
885 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
888 engine->commands.emplace_back(std::bind(&Token::advanceToExiting,
this),
this);
897 engine->commands.emplace_back(std::bind(&StateMachine::handleEventBasedGatewayActivation,
const_cast<StateMachine*
>(
owner),
this),
this);
904 engine->commands.emplace_back(std::bind(&Token::advanceToDone,
this),
this);
908 advanceToDeparting();
911void Token::advanceToExiting() {
916 throw std::runtime_error(
"Token: exit timestamp at node '" +
node->
id +
"' is larger than current time");
922 if ( !eventSubProcess ) {
923 throw std::runtime_error(
"Token: typed start event must belong to event subprocess");
927 throw std::runtime_error(
"Token: Operators for event-subprocess '" +
node->
parent->
id +
"' attempt to modify timestamp");
948 assert(eventSubProcess);
951 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
954 engine->commands.emplace_back(std::bind(&Token::advanceToDone,
this),
this);
957 advanceToDeparting();
963 if ( !exitIsFeasible() ) {
964 engine->commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
970 if ( extensionElements && ( extensionElements->
attributes.size() || extensionElements->
data.size() ) ) {
985 auto LOOP = [&]() ->
bool {
988 assert( value.has_value() );
989 if ( !value.value() ) {
997 assert( extensionElements->
loopIndex.value()->expression );
998 auto indexAttribute = extensionElements->
loopIndex.value()->expression->isAttribute();
999 assert( indexAttribute );
1000 auto index = attributeRegistry.getValue( indexAttribute,
status, *
data,
globals).value();
1002 if ( index >= maximum ) {
1017 if ( extensionElements && extensionElements->
attributes.size() ) {
1026 engine->commands.emplace_back(std::bind(&StateMachine::deleteMultiInstanceActivityToken,stateMachine,
this),
this);
1032 if ( !activity->boundaryEvents.empty() ) {
1034 engine->commands.emplace_back( std::bind(&StateMachine::deleteTokensAwaitingBoundaryEvent,stateMachine,
this), stateMachine );
1048 engine->commands.emplace_back(std::bind(&Token::advanceToDone,
this),
this);
1051 advanceToDeparting();
1054void Token::advanceToDone() {
1061 engine->commands.emplace_back(std::bind(&StateMachine::deleteAdHocSubProcessToken,stateMachine,
this),
this);
1067void Token::advanceToDeparting() {
1072 engine->
commands.emplace_back(std::bind(&Token::advanceToDeparted,
this,
node->
outgoing.front()),
this);
1077 throw std::runtime_error(
"Token: implicit split at node '" +
node->
id +
"'");
1092 throw std::logic_error(
"Token: no gatekeeper provided for sequence flow '" +
sequenceFlow->
id +
"'");
1098 if ( exclusiveGateway->defaultFlow ) {
1100 engine->
commands.emplace_back(std::bind(&Token::advanceToDeparted,
this,exclusiveGateway->defaultFlow),
this);
1104 engine->
commands.emplace_back(std::bind(&Token::advanceToFailed,
this),
this);
1110 engine->
commands.emplace_back(std::bind(&StateMachine::handleDivergingGateway,
const_cast<StateMachine*
>(
owner),
this),
this);
1119 engine->commands.emplace_back(std::bind(&Token::advanceToArrived,
this),
this);
1122void Token::advanceToArrived() {
1129 throw std::runtime_error(
"Token: implicit join at node '" +
node->
id +
"'");
1133 awaitGatewayActivation();
1146 engine->
commands.emplace_back(std::bind(&Token::advanceToEntered,
this),
this);
1150void Token::advanceToFailed() {
1170 engine->commands.emplace_back(std::bind(&Token::terminate,
this),
this);
1175 engine->commands.emplace_back(std::bind(&StateMachine::handleFailure,
const_cast<StateMachine*
>(
owner),
this),
this);
1178void Token::terminate() {
1184 owned->clearObsoleteTokens();
1198 engine->commands.emplace_back(std::bind(&StateMachine::handleFailure,
const_cast<StateMachine*
>(
owner),
this),
this);
1202void Token::awaitCompensation() {
1204 if (
auto compensationActivity = activity->compensatedBy->represents<
BPMN::Activity>();
1205 compensationActivity &&
1208 throw std::runtime_error(
"Token: compensation activities must have the same loop characteristics as the compensated activity '" +
node->
id +
"'");
1218 engine->commands.emplace_back( std::bind(&StateMachine::createCompensationEventSubProcess,stateMachine,subProcess->compensationEventSubProcess,
status), stateMachine );
1222 auto it = std::find_if(activity->boundaryEvents.begin(), activity->boundaryEvents.end(), [](
BPMN::FlowNode* boundaryEvent) {
1223 return ( boundaryEvent->represents<BPMN::CompensateBoundaryEvent>() );
1225 if ( it != activity->boundaryEvents.end() ) {
1227 engine->commands.emplace_back( std::bind(&StateMachine::createCompensationTokenForBoundaryEvent,stateMachine,*it,
status), stateMachine );
1232void Token::awaitReadyEvent() {
1238void Token::awaitEntryEvent() {
1243 auto tokenAtSequentialPerformer = getSequentialPerfomerToken();
1245 tokenAtSequentialPerformer->pendingSequentialEntries.emplace_back(weak_from_this());
1247 if ( tokenAtSequentialPerformer->performing ) {
1255 systemState->pendingEntryDecisions.emplace_back( weak_from_this(),
decisionRequest );
1260void Token::awaitChoiceEvent() {
1264 systemState->pendingChoiceDecisions.emplace_back( weak_from_this(),
decisionRequest );
1268void Token::awaitTaskCompletionEvent() {
1271 systemState->tokensAwaitingCompletionEvent.emplace(time,weak_from_this());
1274void Token::awaitExitEvent() {
1279 systemState->pendingExitDecisions.emplace_back( weak_from_this(),
decisionRequest );
1283void Token::awaitMessageDelivery() {
1288 systemState->pendingMessageDeliveryDecisions.emplace_back( weak_from_this(),
decisionRequest );
1306void Token::awaitGatewayActivation() {
1311 auto gatewayIt = systemState->tokensAwaitingGatewayActivation[stateMachine].find(
node);
1312 if (gatewayIt == systemState->tokensAwaitingGatewayActivation[stateMachine].end()) {
1314 gatewayIt = systemState->tokensAwaitingGatewayActivation[stateMachine].insert({
node,{}}).first;
1317 auto& [key,tokens] = *gatewayIt;
1318 tokens.emplace_back(
this);
1321template<
typename DecisionType,
typename... Args>
1322std::shared_ptr<DecisionType> Token::createDecisionRequest(Args&&... args) {
1324 auto event = std::make_shared<DecisionType>(
this, std::forward<Args>(args)...);
1330void Token::withdraw() {
1337void Token::emitSignal() {
1342 auto& waitingTokens = systemState->tokensAwaitingSignal[signalDefinition->name];
1343 if ( !waitingTokens.empty() ) {
1345 VariedValueMap contentValueMap = getSignalContent(signalDefinition->contentMap);
1347 for (
auto& [token_ptr] : waitingTokens ) {
1348 auto token = token_ptr.lock();
1351 token->setSignalContent(contentValueMap);
1355 engine->
commands.emplace_back(std::bind(&Token::advanceToCompleted,token.get()), token.get());
1357 waitingTokens.clear();
1364 for (
auto& [key,contentDefinition] : contentMap) {
1365 if (
status[contentDefinition->attribute->index].has_value() ) {
1366 contentValueMap.emplace( key, attributeRegistry.getValue(contentDefinition->attribute,
status,*
data,
globals) );
1369 contentValueMap.emplace( key, std::nullopt );
1372 return contentValueMap;
1381 for (
auto& [key,contentValue] : sourceMap) {
1382 if (
auto it = signalDefinition->contentMap.find(key); it != signalDefinition->contentMap.end() ) {
1383 auto& [_,definition] = *it;
1384 auto attribute = definition->attribute;
1386 if ( std::holds_alternative< std::optional<number> >(contentValue) && std::get< std::optional<number> >(contentValue).has_value() ) {
1388 attributeRegistry.setValue(attribute,
status, *
data,
globals, std::get< std::optional<number> >(contentValue).value() );
1390 else if (std::holds_alternative<std::string>(contentValue)) {
1392 Value value = std::get< std::string >(contentValue);
1405 if ( signalDefinition->contentMap.size() > sourceMap.size() - counter ) {
1407 for (
auto& [key,definition] : signalDefinition->contentMap) {
1408 if ( !sourceMap.contains(key) ) {
1410 attributeRegistry.setValue(definition->attribute,
status, *
data,
globals, std::nullopt );
1420void Token::sendMessage(
size_t index) {
1422 systemState->
messages.emplace_back(std::make_shared<Message>(
this,index));
1423 auto& message = systemState->messages.back();
1425 if ( message->recipient.has_value() ) {
1427 auto it = systemState->archive.find((
long unsigned int)message->recipient.value());
1428 if ( it == systemState->archive.end() ) {
1431 systemState->unsent[(
long unsigned int)message->recipient.value()].emplace_back(message->weak_from_this());
1433 else if (
auto stateMachine = it->second.lock() ) {
1435 systemState->inbox[stateMachine.get()].emplace_back(message->weak_from_this());
1436 systemState->outbox[
node].emplace_back(message->weak_from_this());
1441 systemState->outbox[
node].emplace_back(message->weak_from_this());
1445 systemState->messageAwaitingDelivery[
this] = message->weak_from_this();
1453Token* Token::getSequentialPerfomerToken()
const {
1458 while (sequentialPerfomerToken->
node && sequentialPerfomerToken->
node != activity->performer) {
1461 return sequentialPerfomerToken;
1464void Token::occupySequentialPerformer() {
1465 auto tokenAtSequentialPerformer = getSequentialPerfomerToken();
1467 assert( !tokenAtSequentialPerformer->performing );
1468 tokenAtSequentialPerformer->pendingSequentialEntries.remove(
this);
1471 tokenAtSequentialPerformer->performing =
this;
1474 for (
auto& [ token_ptr ] : tokenAtSequentialPerformer->pendingSequentialEntries ) {
1475 if (
auto activityToken = token_ptr.lock() ) {
1478 assert( activityToken->decisionRequest );
1480 activityToken->decisionRequest.reset();
1485void Token::releaseSequentialPerformer() {
1487 auto tokenAtSequentialPerformer = getSequentialPerfomerToken();
1489 assert( tokenAtSequentialPerformer->performing );
1492 tokenAtSequentialPerformer->performing =
nullptr;
1495 for (
auto& [ token_ptr ] : tokenAtSequentialPerformer->pendingSequentialEntries ) {
1496 if (
auto activityToken = token_ptr.lock() ) {
1499 assert( !activityToken->decisionRequest );
1502 systemState->pendingEntryDecisions.emplace_back(activityToken,activityToken->decisionRequest);
1509void Token::update(State newState) {
1510 assert(
status.size() >= 1 );
1511 assert(
data->size() >= 1 );
1530 throw std::runtime_error(
"Token: timestamp at node '" +
node->
id +
"' is larger than current time");
1535void Token::notify()
const {
std::list< Command > commands
List of commands to be executed.
void notify(const Observable *observable) const
Represents a state machine for BPMN execution of a scope in the model.
const BPMN::Scope * scope
Pointer to the current scope.
StateMachines pendingEventSubProcesses
Container with state machines of all inactive event subprocesses that may be triggered.
const SystemState * systemState
const BPMN::Process * process
Pointer to the top-level process.
StateMachines nonInterruptingEventSubProcesses
Container with state machines of all active event subprocesses that are not interrupting.
const StateMachine * root
Pointer to the root state machine.
std::shared_ptr< StateMachine > interruptingEventSubProcess
State machines representing an active event subprocess that is interrupting.
void run(Values status)
Create initial token and advance it.
std::optional< BPMNOS::number > instance
Numeric representation of instance id (TODO: can we const this?)
Tokens tokens
Container with all tokens within the scope of the state machine.
Tokens compensationTokens
Container with all tokens created for a compensation activity.
SharedValues data
Container holding references to all data attributes.
A class representing the state that the execution or simulation of a given scenario is in.
BPMNOS::number currentTime
Timestamp holding the point in time that the engine is in (this is usually representing now).
std::unordered_map< BPMNOS::number, auto_list< std::weak_ptr< Token > > > tokensAwaitingSignal
Map holding a container of all tokens at a signal event awaiting a signal with a given name.
BPMNOS::number getTime() const
Function returning the assumed time time if available or the current time otherwise.
Messages messages
Container holding all messages created by a throwing message event.
std::unordered_map< Token *, std::vector< Token * > > tokensAwaitingBoundaryEvent
Map holding a container of all tokens at a boundary event awaiting to be triggered for each token at ...
auto_list< std::weak_ptr< Token > > tokensAwaitingReadyEvent
Container holding all tokens awaiting a ready event.
auto_set< BPMNOS::number, std::weak_ptr< Token > > tokensAwaitingTimer
Sorted container holding holding all tokens awaiting a timer event.
std::unordered_map< BPMNOS::number, auto_list< std::weak_ptr< Token > > > tokensAwaitingCondition
Map holding a container of all tokens at a conditional event belonginge to a process instance.
Represents a token running through a (sub)process.
const BPMN::FlowNode * node
Token * performing
Pointer to the activity token currently performed (only applies if node is a performer referenced by ...
const BPMNOS::Model::AttributeRegistry & getAttributeRegistry() const
const StateMachine * owner
State machine owning the token.
std::shared_ptr< StateMachine > owned
State machine owned by the token.
void setStatus(const BPMNOS::Values &other)
Copies all elements except the instance id from other to status
SharedValues * data
Pointer to the data of the owner or owned state machine subprocesses)
std::shared_ptr< DecisionRequest > decisionRequest
const BPMN::SequenceFlow * sequenceFlow
static std::string stateName[]
Token(const StateMachine *owner, const BPMN::FlowNode *node, const Values &status)
nlohmann::ordered_json jsonify() const
std::map< std::string, Attribute * > statusAttributes
Class holding extension elements representing conditions for sequence flows and conditional events.
Class representing a task in which one or more choices have to be made.
Class holding extension elements representing execution data for nodes.
std::vector< std::unique_ptr< Operator > > operators
std::vector< std::unique_ptr< Attribute > > attributes
Vector containing new status attributes declared for the node.
void computeInitialValues(BPMNOS::number currentTime, BPMNOS::Values &status, DataType &data, BPMNOS::Values &globals) const
bool fullScopeRestrictionsSatisfied(const BPMNOS::Values &status, const DataType &data, const BPMNOS::Values &globals) const
struct BPMNOS::Model::ExtensionElements::@0 dataUpdate
Struct containing data attributes that are modified through operators and a flag indicating whether a...
bool isInstantaneous
Boolean indicating whether operators may modify timestamp.
bool feasibleEntry(const BPMNOS::Values &status, const DataType &data, const BPMNOS::Values &globals) const
BPMNOS::number getContributionToObjective(const BPMNOS::Values &status, const DataType &data, const BPMNOS::Values &globals) const
Returns the contribution to the objective by the attributes declared for the node.
std::optional< std::unique_ptr< Parameter > > loopIndex
Attribute holding the automatically generated loop index.
std::optional< std::unique_ptr< Parameter > > loopCondition
Boolean attribute indicating whether an exit condition holds.
void applyOperators(BPMNOS::Values &status, DataType &data, BPMNOS::Values &globals) const
AttributeRegistry attributeRegistry
Registry allowing to look up all status and data attributes by their names.
std::vector< std::unique_ptr< Attribute > > data
Vector containing data attributes declared for data objects within the node's scope.
std::optional< std::unique_ptr< Parameter > > loopMaximum
Maximum number of iterations of a standard loop (requires loopIndex).
Class holding extension elements representing gatekeeper conditions for sequence flows.
Class representing adhoc subprocesses with sequential ordering.
Class holding extension elements representing the definition of signal events.
BPMNOS::number name
Signal name.
Class holding extension elements representing the trigger of timer events.
std::vector< BoundaryEvent * > boundaryEvents
std::optional< LoopCharacteristics > loopCharacteristics
@ MultiInstanceSequential
std::unique_ptr< ExtensionElements > extensionElements
std::string id
Id of element.
Base class for all boundary events attached to an Activity.
Scope * parent
Reference to the parent node.
T * as()
Casts the element to the specified type T.
T * represents()
Attempts to cast the element to the specified type T.
TypedStartEvent * startEvent
std::vector< std::reference_wrapper< T > > get()
Returns a vector of elements of type T embedded within a container of type T.
Base class for BPMN elements that may contain incoming and outgoing sequence flows.
std::vector< SequenceFlow * > incoming
Vector containing all incoming sequence flows of the node.
std::vector< SequenceFlow * > outgoing
Vector containing all outgoing sequence flows of the node.
Base class for BPMN elements that may contain a ChildNode elements.
EventSubProcess * compensationEventSubProcess
Pointer to compensation event subprocess of the scope.
The SequenceFlow class encapsulates the information and relationships associated with a sequence flow...
FlowNode * target
Reference to the target node of the sequence flow.
Base class for all start events with an event definition.
void erase_ptr(std::vector< std::unique_ptr< T > > &container, const T *elementPtr)
Erase a specific element from a vector of unique pointers.
std::unordered_map< std::string, std::unique_ptr< Content > > ContentMap
std::unordered_map< std::string, std::variant< std::optional< number >, std::string > > VariedValueMap
std::string to_string(number numericValue, const ValueType &type)
Converts a number to a string.
number to_number(const std::string &valueString, const ValueType &type)
Converts a string to a number.
BPMNOS_NUMBER_TYPE number
std::variant< bool, int, double, std::string > Value
@ SequentialPerformerUpdate
static constexpr size_t Instance
static constexpr size_t Timestamp