From 341d57e48f84bb9de3988e387431744ed541ce48 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 13 Mar 2021 15:32:16 +0000 Subject: [PATCH] Add api sugar for mono gets mono - While this doesn't change underlying behaviour, add sendEventCollect method which takes a mono and returns a mono as list of results. - Add some notes to docs why this is like this, aka having regions returns multiple results. - Fixes #922 --- ...pendix-reactormigration-communicating.adoc | 4 ++- docs/src/reference/asciidoc/sm-triggers.adoc | 14 ++++++++++ .../ensemble/DistributedStateMachine.java | 8 +++++- .../statemachine/region/Region.java | 13 +++++++++- .../support/AbstractStateMachine.java | 5 ++++ .../statemachine/ReactiveTests.java | 26 ++++++++++++++++++- .../access/StateMachineAccessTests.java | 5 ++++ .../docs/DocsConfigurationSampleTests.java | 14 +++++++++- .../statemachine/docs/DocsMigrationTests.java | 6 ++++- .../StateContextExpressionMethodsTests.java | 9 ++++++- .../ZookeeperStateMachineEnsembleTests.java | 7 ++++- 11 files changed, 103 insertions(+), 8 deletions(-) diff --git a/docs/src/reference/asciidoc/appendix-reactormigration-communicating.adoc b/docs/src/reference/asciidoc/appendix-reactormigration-communicating.adoc index 44af6541..a8da6516 100644 --- a/docs/src/reference/asciidoc/appendix-reactormigration-communicating.adoc +++ b/docs/src/reference/asciidoc/appendix-reactormigration-communicating.adoc @@ -12,7 +12,9 @@ include::samples/DocsMigrationTests.java[tags=snippetA] We're now solely working on a spring `Message` and reactor `Mono` and `Flux` classes. You can send a `Mono` of a `Message` and receive back a `Flux` of `StateMachineEventResult`. Remember that nothing happens until you subscribe to this `Flux`. More about -this returned value, see <>. +this returned value, see <>. Method `sendEventCollect` +is just a syntactic sugar to pass in a `Mono` and get a `Mono` which wraps +results as a list. ==== [source,java,indent=0] diff --git a/docs/src/reference/asciidoc/sm-triggers.adoc b/docs/src/reference/asciidoc/sm-triggers.adoc index c31d9bf2..a9feaad8 100644 --- a/docs/src/reference/asciidoc/sm-triggers.adoc +++ b/docs/src/reference/asciidoc/sm-triggers.adoc @@ -20,6 +20,20 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetO] ---- ==== +Whether you send one event or multiple events, result is always a sequence +of results. This is so because in a presence multiple reqions, results will +come back from multiple machines in those regions. This is shown +with method `sendEventCollect` which gives a list of results. Method +itself is a just a syntactic sugar collecting `Flux` as list. If there is +just one region, this list contains one result. + +==== +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetO3] +---- +==== + IMPORTANT: Nothing happens until returned flux is subscribed. See more about it from <>. diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/ensemble/DistributedStateMachine.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/ensemble/DistributedStateMachine.java index 5ac769eb..bbc17b7b 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/ensemble/DistributedStateMachine.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/ensemble/DistributedStateMachine.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2020 the original author or authors. + * Copyright 2015-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.statemachine.ensemble; import java.util.Collection; +import java.util.List; import java.util.UUID; import java.util.function.Function; @@ -121,6 +122,11 @@ public class DistributedStateMachine extends LifecycleObjectSupport implem return delegate.sendEvent(event.map(addMachineIdentifier())); } + @Override + public Mono>> sendEventCollect(Mono> event) { + return delegate.sendEventCollect(event.map(addMachineIdentifier())); + } + @Override public Flux> sendEvents(Flux> events) { return delegate.sendEvents(events.map(addMachineIdentifier())); diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/region/Region.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/region/Region.java index 53165d16..28e69a4d 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/region/Region.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/region/Region.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 the original author or authors. + * Copyright 2015-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.statemachine.region; import java.util.Collection; +import java.util.List; import java.util.UUID; import org.springframework.messaging.Message; @@ -115,6 +116,16 @@ public interface Region extends StateMachineReactiveLifecycle { */ Flux> sendEvent(Mono> event); + /** + * Send a {@link Mono} of event and return a {@link Mono} of collected + * {@link StateMachineEventResult}s as a list. Events are consumed after + * returned results are consumed. + * + * @param event the event + * @return the event results + */ + Mono>> sendEventCollect(Mono> event); + /** * Gets the current {@link State}. * diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java index 94b89c59..5522e71b 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java @@ -249,6 +249,11 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo return event.flatMapMany(e -> handleEvent(e)); } + @Override + public Mono>> sendEventCollect(Mono> event) { + return event.flatMapMany(e -> handleEvent(e)).collectList(); + } + @Override protected void onInit() throws Exception { super.onInit(); diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/ReactiveTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/ReactiveTests.java index 259b9adf..a97a7672 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/ReactiveTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/ReactiveTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2019-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -254,6 +254,30 @@ public class ReactiveTests extends AbstractStateMachineTests { assertThat(machine.getState().getIds()).containsExactlyInAnyOrder(TestStates.S11, TestStates.S20); } + @SuppressWarnings("unchecked") + @Test + public void testRegionsAsCollect() { + context.register(Config4.class); + context.refresh(); + assertThat(context.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)).isTrue(); + StateMachine machine = + context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class); + assertThat(machine).isNotNull(); + verifyStart(machine); + assertThat(machine.getState().getIds()).containsExactlyInAnyOrder(TestStates.S10, TestStates.S20); + + StepVerifier.create(machine.sendEventCollect(asMono(TestEvents.E1))) + .assertNext(r -> { + assertThat(r).hasSize(2); + assertThat(r).filteredOnAssertions(er -> assertThat(er.getResultType()).isSameAs(ResultType.ACCEPTED)).hasSize(1); + assertThat(r).filteredOnAssertions(er -> assertThat(er.getResultType()).isSameAs(ResultType.DENIED)).hasSize(1); + }) + .expectComplete() + .verify(); + + assertThat(machine.getState().getIds()).containsExactlyInAnyOrder(TestStates.S11, TestStates.S20); + } + @Configuration @EnableStateMachine static class Config1 extends EnumStateMachineConfigurerAdapter { diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/access/StateMachineAccessTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/access/StateMachineAccessTests.java index 2e8e2728..011e1483 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/access/StateMachineAccessTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/access/StateMachineAccessTests.java @@ -152,6 +152,11 @@ public class StateMachineAccessTests { return null; } + @Override + public Mono>> sendEventCollect(Mono> event) { + return null; + } + @Override public Flux> sendEvents(Flux> events) { return null; diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java index 57523a2a..8598ef82 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java @@ -18,6 +18,7 @@ package org.springframework.statemachine.docs; import java.util.Arrays; import java.util.EnumSet; import java.util.HashSet; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.support.StaticListableBeanFactory; @@ -615,10 +616,21 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { stateMachine.sendEvents(Flux.just(message1, message2)); results.subscribe(); - // end::snippetO2[] } + void signalMachine3() { +// tag::snippetO3[] + Message message1 = MessageBuilder + .withPayload("E1") + .build(); + + Mono>> results = + stateMachine.sendEventCollect(Mono.just(message1)); + + results.subscribe(); +// end::snippetO3[] + } } // tag::snippetP[] diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsMigrationTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsMigrationTests.java index e59f00be..6f1c2e4d 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsMigrationTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsMigrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 the original author or authors. + * Copyright 2019-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ */ package org.springframework.statemachine.docs; +import java.util.List; + import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; import org.springframework.statemachine.StateMachine; @@ -33,6 +35,8 @@ public class DocsMigrationTests { Flux> sendEvent(Mono> event); Flux> sendEvents(Flux> events); + + Mono>> sendEventCollect(Mono> event); // end::snippetA[] } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/support/StateContextExpressionMethodsTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/support/StateContextExpressionMethodsTests.java index 8db848e9..7567b70b 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/support/StateContextExpressionMethodsTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/support/StateContextExpressionMethodsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2020 the original author or authors. + * Copyright 2015-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Function; @@ -203,6 +204,12 @@ public class StateContextExpressionMethodsTests { return null; } + @Override + public Mono>> sendEventCollect( + Mono> event) { + return null; + } + @Override public Flux> sendEvents(Flux> events) { return null; diff --git a/spring-statemachine-zookeeper/src/test/java/org/springframework/statemachine/zookeeper/ZookeeperStateMachineEnsembleTests.java b/spring-statemachine-zookeeper/src/test/java/org/springframework/statemachine/zookeeper/ZookeeperStateMachineEnsembleTests.java index e4445117..506d4ff0 100644 --- a/spring-statemachine-zookeeper/src/test/java/org/springframework/statemachine/zookeeper/ZookeeperStateMachineEnsembleTests.java +++ b/spring-statemachine-zookeeper/src/test/java/org/springframework/statemachine/zookeeper/ZookeeperStateMachineEnsembleTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2020 the original author or authors. + * Copyright 2015-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -739,6 +739,11 @@ public class ZookeeperStateMachineEnsembleTests extends AbstractZookeeperTests { return null; } + @Override + public Mono>> sendEventCollect(Mono> event) { + return null; + } + @Override public Flux> sendEvents(Flux> events) { return null;