18
18
import com .fasterxml .jackson .databind .JsonNode ;
19
19
import com .fasterxml .jackson .databind .node .ArrayNode ;
20
20
import io .cloudevents .CloudEvent ;
21
+ import io .serverlessworkflow .api .types .AllEventConsumptionStrategy ;
22
+ import io .serverlessworkflow .api .types .AnyEventConsumptionStrategy ;
23
+ import io .serverlessworkflow .api .types .EventConsumptionStrategy ;
21
24
import io .serverlessworkflow .api .types .EventFilter ;
22
25
import io .serverlessworkflow .api .types .ListenTask ;
23
26
import io .serverlessworkflow .api .types .ListenTaskConfiguration ;
24
27
import io .serverlessworkflow .api .types .ListenTaskConfiguration .ListenAndReadAs ;
25
28
import io .serverlessworkflow .api .types .ListenTo ;
29
+ import io .serverlessworkflow .api .types .OneEventConsumptionStrategy ;
26
30
import io .serverlessworkflow .api .types .SubscriptionIterator ;
31
+ import io .serverlessworkflow .api .types .Until ;
27
32
import io .serverlessworkflow .api .types .Workflow ;
28
33
import io .serverlessworkflow .impl .TaskContext ;
29
34
import io .serverlessworkflow .impl .WorkflowApplication ;
30
35
import io .serverlessworkflow .impl .WorkflowContext ;
31
36
import io .serverlessworkflow .impl .WorkflowFilter ;
32
37
import io .serverlessworkflow .impl .WorkflowPosition ;
38
+ import io .serverlessworkflow .impl .WorkflowUtils ;
33
39
import io .serverlessworkflow .impl .events .CloudEventUtils ;
40
+ import io .serverlessworkflow .impl .events .EventConsumer ;
34
41
import io .serverlessworkflow .impl .events .EventRegistration ;
35
42
import io .serverlessworkflow .impl .events .EventRegistrationBuilder ;
36
43
import io .serverlessworkflow .impl .json .JsonUtils ;
40
47
import java .util .List ;
41
48
import java .util .Optional ;
42
49
import java .util .concurrent .CompletableFuture ;
43
- import java .util .function .Consumer ;
50
+ import java .util .concurrent .atomic .AtomicBoolean ;
51
+ import java .util .function .BiConsumer ;
44
52
import java .util .function .Function ;
45
53
import java .util .stream .Collectors ;
46
54
47
55
public abstract class ListenExecutor extends RegularTaskExecutor <ListenTask > {
48
56
49
- protected final Collection <EventRegistrationBuilder > regBuilders ;
57
+ protected final EventRegistrationBuilderCollection regBuilders ;
58
+ protected final EventRegistrationBuilderCollection untilRegBuilders ;
50
59
protected final Optional <WorkflowFilter > until ;
51
60
protected final Optional <TaskExecutor <?>> loop ;
52
61
protected final Function <CloudEvent , JsonNode > converter ;
62
+ protected final EventConsumer eventConsumer ;
63
+ protected final AtomicBoolean untilEvent = new AtomicBoolean (true );
64
+
65
+ private static record EventRegistrationBuilderCollection (
66
+ Collection <EventRegistrationBuilder > registrations , boolean isAnd ) {}
53
67
54
68
public static class ListenExecutorBuilder extends RegularTaskExecutorBuilder <ListenTask > {
55
69
56
- private Collection < EventRegistrationBuilder > registrations ;
70
+ private EventRegistrationBuilderCollection registrations ;
57
71
private WorkflowFilter until ;
72
+ private EventRegistrationBuilderCollection untilRegistrations ;
58
73
private TaskExecutor <?> loop ;
59
74
private Function <CloudEvent , JsonNode > converter = this ::defaultCEConverter ;
60
- private boolean isAnd ;
75
+
76
+ private EventRegistrationBuilderCollection allEvents (AllEventConsumptionStrategy allStrategy ) {
77
+ return new EventRegistrationBuilderCollection (from (allStrategy .getAll ()), true );
78
+ }
79
+
80
+ private EventRegistrationBuilderCollection anyEvents (AnyEventConsumptionStrategy anyStrategy ) {
81
+ List <EventFilter > eventFilters = anyStrategy .getAny ();
82
+ return new EventRegistrationBuilderCollection (
83
+ eventFilters .isEmpty () ? registerToAll () : from (eventFilters ), false );
84
+ }
85
+
86
+ private EventRegistrationBuilderCollection oneEvent (OneEventConsumptionStrategy oneStrategy ) {
87
+ return new EventRegistrationBuilderCollection (List .of (from (oneStrategy .getOne ())), false );
88
+ }
61
89
62
90
protected ListenExecutorBuilder (
63
91
WorkflowPosition position ,
@@ -69,15 +97,29 @@ protected ListenExecutorBuilder(
69
97
ListenTaskConfiguration listen = task .getListen ();
70
98
ListenTo to = listen .getTo ();
71
99
if (to .getAllEventConsumptionStrategy () != null ) {
72
- isAnd = true ;
73
- registrations = from (to .getAllEventConsumptionStrategy ().getAll ());
100
+ registrations = allEvents (to .getAllEventConsumptionStrategy ());
74
101
} else if (to .getAnyEventConsumptionStrategy () != null ) {
75
- isAnd = false ;
76
- List <EventFilter > eventFilters = to .getAnyEventConsumptionStrategy ().getAny ();
77
- registrations = eventFilters .isEmpty () ? registerToAll () : from (eventFilters );
102
+ AnyEventConsumptionStrategy any = to .getAnyEventConsumptionStrategy ();
103
+ registrations = anyEvents (any );
104
+ Until untilDesc = any .getUntil ();
105
+ if (untilDesc != null ) {
106
+ if (untilDesc .getAnyEventUntilCondition () != null ) {
107
+ until =
108
+ WorkflowUtils .buildWorkflowFilter (
109
+ application .expressionFactory (), untilDesc .getAnyEventUntilCondition ());
110
+ } else if (untilDesc .getAnyEventUntilConsumed () != null ) {
111
+ EventConsumptionStrategy strategy = untilDesc .getAnyEventUntilConsumed ();
112
+ if (strategy .getAllEventConsumptionStrategy () != null ) {
113
+ untilRegistrations = allEvents (strategy .getAllEventConsumptionStrategy ());
114
+ } else if (strategy .getAnyEventConsumptionStrategy () != null ) {
115
+ untilRegistrations = anyEvents (strategy .getAnyEventConsumptionStrategy ());
116
+ } else if (strategy .getOneEventConsumptionStrategy () != null ) {
117
+ untilRegistrations = oneEvent (strategy .getOneEventConsumptionStrategy ());
118
+ }
119
+ }
120
+ }
78
121
} else if (to .getOneEventConsumptionStrategy () != null ) {
79
- isAnd = false ;
80
- registrations = List .of (from (to .getOneEventConsumptionStrategy ().getOne ()));
122
+ registrations = oneEvent (to .getOneEventConsumptionStrategy ());
81
123
}
82
124
SubscriptionIterator forEach = task .getForeach ();
83
125
if (forEach != null ) {
@@ -116,7 +158,7 @@ private EventRegistrationBuilder from(EventFilter filter) {
116
158
117
159
@ Override
118
160
public TaskExecutor <ListenTask > buildInstance () {
119
- return isAnd ? new AndListenExecutor (this ) : new OrListenExecutor (this );
161
+ return registrations . isAnd () ? new AndListenExecutor (this ) : new OrListenExecutor (this );
120
162
}
121
163
}
122
164
@@ -160,8 +202,11 @@ protected void internalProcessCe(
160
202
TaskContext taskContext ,
161
203
CompletableFuture <JsonNode > future ) {
162
204
arrayNode .add (node );
163
- if (until .isEmpty ()
164
- || until .filter (u -> u .apply (workflow , taskContext , arrayNode ).asBoolean ()).isPresent ()) {
205
+ if ((until .isEmpty ()
206
+ || until
207
+ .filter (u -> u .apply (workflow , taskContext , arrayNode ).asBoolean ())
208
+ .isPresent ())
209
+ && untilEvent .get ()) {
165
210
future .complete (arrayNode );
166
211
}
167
212
}
@@ -176,6 +221,65 @@ protected abstract void internalProcessCe(
176
221
TaskContext taskContext ,
177
222
CompletableFuture <JsonNode > future );
178
223
224
+ @ Override
225
+ protected CompletableFuture <JsonNode > internalExecute (
226
+ WorkflowContext workflow , TaskContext taskContext ) {
227
+ ArrayNode output = JsonUtils .mapper ().createArrayNode ();
228
+ Collection <EventRegistration > registrations = new ArrayList <>();
229
+ if (untilRegBuilders != null ) {
230
+ untilEvent .set (false );
231
+ }
232
+ CompletableFuture <?> combinedFuture =
233
+ combine (
234
+ toCompletables (
235
+ regBuilders ,
236
+ registrations ,
237
+ (ce , future ) ->
238
+ processCe (converter .apply (ce ), output , workflow , taskContext , future )));
239
+ CompletableFuture <JsonNode > resultFuture =
240
+ combinedFuture .thenApply (
241
+ v -> {
242
+ registrations .forEach (reg -> eventConsumer .unregister (reg ));
243
+ return output ;
244
+ });
245
+ if (untilRegBuilders != null ) {
246
+ Collection <EventRegistration > untilRegistrations = new ArrayList <>();
247
+ CompletableFuture <?>[] futures =
248
+ toCompletables (
249
+ untilRegBuilders , untilRegistrations , (ce , future ) -> future .complete (null ));
250
+ CompletableFuture <?> untilFuture =
251
+ untilRegBuilders .isAnd ()
252
+ ? CompletableFuture .allOf (futures )
253
+ : CompletableFuture .anyOf (futures );
254
+ untilFuture .thenAccept (
255
+ v -> {
256
+ untilEvent .set (true );
257
+ combinedFuture .complete (null );
258
+ untilRegistrations .forEach (reg -> eventConsumer .unregister (reg ));
259
+ });
260
+ }
261
+ return resultFuture ;
262
+ }
263
+
264
+ private <T > CompletableFuture <T >[] toCompletables (
265
+ EventRegistrationBuilderCollection regCollection ,
266
+ Collection <EventRegistration > registrations ,
267
+ BiConsumer <CloudEvent , CompletableFuture <T >> consumer ) {
268
+ return regCollection .registrations ().stream ()
269
+ .map (reg -> toCompletable (reg , registrations , consumer ))
270
+ .toArray (size -> new CompletableFuture [size ]);
271
+ }
272
+
273
+ private <T > CompletableFuture <T > toCompletable (
274
+ EventRegistrationBuilder regBuilder ,
275
+ Collection <EventRegistration > registrations ,
276
+ BiConsumer <CloudEvent , CompletableFuture <T >> ceConsumer ) {
277
+ final CompletableFuture <T > future = new CompletableFuture <>();
278
+ registrations .add (
279
+ eventConsumer .register (regBuilder , ce -> ceConsumer .accept ((CloudEvent ) ce , future )));
280
+ return future ;
281
+ }
282
+
179
283
private void processCe (
180
284
JsonNode node ,
181
285
ArrayNode arrayNode ,
@@ -199,48 +303,13 @@ private void processCe(
199
303
() -> internalProcessCe (node , arrayNode , workflow , taskContext , future ));
200
304
}
201
305
202
- protected CompletableFuture <JsonNode > toCompletable (
203
- WorkflowContext workflow ,
204
- TaskContext taskContext ,
205
- EventRegistrationBuilder regBuilder ,
206
- Collection <EventRegistration > registrations ,
207
- ArrayNode arrayNode ) {
208
- final CompletableFuture <JsonNode > future = new CompletableFuture <>();
209
- registrations .add (
210
- workflow
211
- .definition ()
212
- .application ()
213
- .eventConsumer ()
214
- .register (
215
- regBuilder ,
216
- (Consumer <CloudEvent >)
217
- (ce ->
218
- processCe (converter .apply (ce ), arrayNode , workflow , taskContext , future ))));
219
- return future ;
220
- }
221
-
222
- @ Override
223
- protected CompletableFuture <JsonNode > internalExecute (
224
- WorkflowContext workflow , TaskContext taskContext ) {
225
- ArrayNode output = JsonUtils .mapper ().createArrayNode ();
226
- Collection <EventRegistration > registrations = new ArrayList <>();
227
- return combine (
228
- regBuilders .stream ()
229
- .map (reg -> toCompletable (workflow , taskContext , reg , registrations , output ))
230
- .toArray (size -> new CompletableFuture [size ]))
231
- .thenApply (
232
- v -> {
233
- registrations .forEach (
234
- reg -> workflow .definition ().application ().eventConsumer ().unregister (reg ));
235
- return output ;
236
- });
237
- }
238
-
239
306
protected ListenExecutor (ListenExecutorBuilder builder ) {
240
307
super (builder );
308
+ this .eventConsumer = builder .application .eventConsumer ();
241
309
this .regBuilders = builder .registrations ;
242
310
this .until = Optional .ofNullable (builder .until );
243
311
this .loop = Optional .ofNullable (builder .loop );
244
312
this .converter = builder .converter ;
313
+ this .untilRegBuilders = builder .untilRegistrations ;
245
314
}
246
315
}
0 commit comments