forked from SysMLinJavaModeler/SysMLinJava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSysMLState.java
More file actions
272 lines (261 loc) · 9.97 KB
/
Copy pathSysMLState.java
File metadata and controls
272 lines (261 loc) · 9.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
package sysmlinjava.statemachine;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Optional;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import sysmlinjava.blocks.SysMLBlock;
/**
* The SysMLinJava representation of the state in SysML's state machine.
* {@code SysMLState} should be used as the type of all states in the state
* machine and should not be extended for further specialization.
* {@code SysMLState} contains the enter, do, and exit activities. In lieu of
* the do activity, the state can contain sub-state machines. As a vertex, the
* {@code SysMLState} includes state transitions which are added by
* {@code SysMLTransition} initializers. An example follows.
*
* <pre>
:
@State
public SysMLState ice;
@State
public SysMLState liquid;
@State
public SysMLState gas;
@State
public SysMLState decomposed;
:
@Override
protected void createStates()
{
super.createStates();
ice = new SysMLState(contextBlock, "Ice");
liquid = new SysMLState(contextBlock, "Liquid");
gas = new SysMLState(contextBlock, "Gas");
decomposed = new SysMLState(contextBlock, Optional.of(decomposedOnEnterActivity), Optional.empty(), Optional.empty(), "Decomposed");
}
* </pre>
*
*
* @author ModelerOne
*
*/
public class SysMLState extends SysMLVertex
{
/**
* Optional activity to be performed upon entry into the state.
*/
public Optional<SysMLOnEnterActivity> onEnterActivity;
/**
* Optional activity to be performed while in the state. If set, the
* {@code doActivity} is executed in lieu of the {@code subStateMachines}.
*/
public Optional<SysMLDoActivity> doActivity;
/**
* Optional activity to be performed upon exiting from the state.
*/
public Optional<SysMLOnExitActivity> onExitActivity;
/**
* List collection of state machines to be executed while in the (composite)
* state. Multiple sub-state machines are executed in parallel, i.e. as
* concurrent state machines within the context of the current state. The
* {@code subStateMachines} execute in lieu of the {@code doActivity}, if set.
*/
public List<? extends SysMLStateMachine> subStateMachines;
/**
* List collection of IDs of sub-state machines that have submitted
* {@code StateMachineCompletionEvent}s to be executed while in the (composite)
* state. Used to determine when all sub-state machines have completed, i.e.
* have transitioned to their final states.
*/
public List<Long> completedSubStateMachineIDs;
/**
* Optional state machine that contains this state. The
* {@code containingStateMachine} is required if there are any
* {@code subStateMachines} and the {@code stateMachine} of {@code contextBlock}
* will be used by default, but this value can be set to another stateMachine as
* needed.
*/
public Optional<SysMLStateMachine> containingStateMachine;
/**
* Optional Future for the {@code doActivity} which runs in a separate thread
* while in the current state. This future is used to stop the
* {@code doActivity} if/when exit out of the current state is triggered.
*/
public Optional<Future<?>> doActivityFuture;
/**
* Optional {@code ScheduledThreadPoolExecutor} for the {@code doActivity} which
* runs the separate thread while in the current state.
*/
public Optional<ScheduledThreadPoolExecutor> doActivityExecutor;
/**
* Constructor for specifying enter, do, exit activities of the state.
*
* @param contextBlock Optional SysMLBlock based context in which the state
* must operate.
* @param onEnterFunction Optional activity to be performed upon entry into the
* state.
* @param doActivity Optional activity to be performed while in the state.
* @param onExitFunction Optional activity to be performed upon exit from the
* state.
* @param name Optional name of the state.
*/
public SysMLState(Optional<? extends SysMLBlock> contextBlock, Optional<SysMLOnEnterActivity> onEnterFunction, Optional<SysMLDoActivity> doActivity, Optional<SysMLOnExitActivity> onExitFunction, String name)
{
super(contextBlock, name);
this.transitions = new ArrayList<>();
this.onEnterActivity = onEnterFunction;
this.doActivity = doActivity;
this.onExitActivity = onExitFunction;
if (doActivity.isPresent())
{
if (!contextBlock.isPresent())
doActivityExecutor = Optional.of(new ScheduledThreadPoolExecutor(1));
}
this.doActivityFuture = Optional.empty();
this.subStateMachines = new ArrayList<>();
this.completedSubStateMachineIDs = new ArrayList<>();
this.containingStateMachine = Optional.empty();
}
/**
* Constructor for specifying enter and exit activities of the state as well as
* a list of sub-state machines that are to execute while in the state.
*
* @param contextBlock Optional SysMLBlock based context in which the state
* must operate.
* @param onEnterFunction Optional activity to be performed upon entry into the
* state.
* @param subStateMachines List of behaviors (state machines) to be executed
* while in the state.
* @param onExitFunction Optional activity to be performed upon exit from the
* state.
* @param name Optional name of the state.
*/
public SysMLState(SysMLBlock contextBlock, Optional<SysMLOnEnterActivity> onEnterFunction, List<? extends SysMLStateMachine> subStateMachines, Optional<SysMLOnExitActivity> onExitFunction, String name)
{
super(Optional.of(contextBlock), name);
this.transitions = new ArrayList<>();
this.onEnterActivity = onEnterFunction;
this.doActivity = Optional.empty();
this.onExitActivity = onExitFunction;
this.doActivityFuture = Optional.empty();
this.subStateMachines = subStateMachines;
this.completedSubStateMachineIDs = new ArrayList<>();
this.containingStateMachine = Optional.empty();
}
/**
* Constructor for specifying state with no enter, do, exit activities and no
* sub-state machines.
*
* @param contextBlock Optional {@code SysMLBlock}-based context in which the
* state must operate.
* @param name Name of the state.
*/
public SysMLState(Optional<? extends SysMLBlock> contextBlock, String name)
{
this(contextBlock, Optional.empty(), Optional.empty(), Optional.empty(), name);
}
/**
* Returns whether or not receipt of the specified completion event means that
* all sub-state machines have now completed.
*
* @param completionEvent completion event presumably just received from one of
* the sub-state machines
* @return true if all sub-state machines are now completed, false otherwise
*/
public boolean subStateMachinesCompleted(StateMachineCompletionEvent completionEvent)
{
completedSubStateMachineIDs.add(Long.valueOf(completionEvent.id));
boolean allCompleted = true;
if (!subStateMachines.isEmpty())
{
ListIterator<? extends SysMLStateMachine> iterator = subStateMachines.listIterator();
while (iterator.hasNext() && allCompleted)
{
SysMLStateMachine nextSM = iterator.next();
boolean smCompleted = completedSubStateMachineIDs.contains(nextSM.id);
boolean smFinal = nextSM.currentState.isPresent() && nextSM.currentState.get() == nextSM.finalState;
if (!smCompleted || !smFinal)
allCompleted = false;
}
if (allCompleted)
completedSubStateMachineIDs.clear();
}
else
allCompleted = false;
return allCompleted;
}
/**
* Operation called upon entry into the state. {@code onEnter()} invokes the
* specified ({@code onEnterActivity}, if provided, and, if present, all
* sub-state machines are executed (started)
*/
public void onEnter()
{
if (onEnterActivity.isPresent())
onEnterActivity.get().perform(contextBlock);
if (!subStateMachines.isEmpty())
executeSubStateMachines();
}
/**
* Activity to be performed while in the state. {@code doWhileInState()} invokes
* the specified {@code doActivity}, if provided, performing the activity in a
* separate thread of execution.
*/
public void doWhileInState()
{
if (doActivity.isPresent())
{
Runnable runner = new Runnable()
{
public void run()
{
doActivity.get().perform(contextBlock);
}
};
if (contextBlock.isPresent())
doActivityFuture = Optional.of(contextBlock.get().concurrentExecutionThreads.submit(runner));
else
doActivityFuture = Optional.of(doActivityExecutor.get().submit(runner));
}
}
/**
* Operation called upon exit from the state. {@code onExit()} invokes the
* specified {@code onExitActivity}, if provided, but only after it terminates
* the {@code doActivity}, if present and started, or terminates the sub-state
* machines, if present.
*/
public void onExit()
{
if (!subStateMachines.isEmpty())
terminateSubStateMachines();
else if (doActivityFuture.isPresent() && !doActivityFuture.get().isDone())
doActivityFuture.get().cancel(true);
if (onExitActivity.isPresent())
onExitActivity.get().perform(contextBlock);
}
/**
* Executes (starts) all of the sub-state machines that have been added to this
* state
*/
private void executeSubStateMachines()
{
completedSubStateMachineIDs.clear();
subStateMachines.forEach(subStateMachine ->
{
if (containingStateMachine.isEmpty() && contextBlock.isPresent())
containingStateMachine = Optional.of(contextBlock.get().stateMachine.get());
subStateMachine.containingStateMachine = containingStateMachine;
subStateMachine.start();
});
}
/**
* Terminates (stops) all of the sub-state machines that have been added to this
* state.
*/
private void terminateSubStateMachines()
{
subStateMachines.forEach(subStateMachine -> subStateMachine.stop());
};
}