Refactor region handling and persistence
- Make kryo in AbstractKryoStateMachineSerialisationService aware of same classloader most likely use in an app. This takes away some of those weird kryo errors you see with a web apps. - Add context references concept to StateMachineContext which can be used to store reference id and then individual running machines with regions can independently store their states. Whole machine state can then get restored more accurately. - Add new `region(String id)` to StateConfigurer which can be used to set region id. This is equivalent as setting region id with json based machine structure where you need to define region id's with orthogonal regions are in use. - Add new datajpamultipersist sample showing running regions and how those are persisted to a database. - Fixes #617 - Fixes #605 - Fixes #615
This commit is contained in:
@@ -128,6 +128,19 @@ project('spring-statemachine-samples-datajpa') {
|
||||
}
|
||||
}
|
||||
|
||||
project('spring-statemachine-samples-datajpamultipersist') {
|
||||
description = 'Spring State Machine Data Jpa Multi Persist Sample'
|
||||
dependencies {
|
||||
compile project(":spring-statemachine-autoconfigure")
|
||||
compile project(":spring-statemachine-data-common:spring-statemachine-data-jpa")
|
||||
compile("org.springframework.boot:spring-boot-starter-web")
|
||||
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
|
||||
compile("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
compile("org.springframework.boot:spring-boot-devtools")
|
||||
compile("com.h2database:h2")
|
||||
}
|
||||
}
|
||||
|
||||
project('spring-statemachine-samples-datapersist') {
|
||||
description = 'Spring State Machine Data Persist Sample'
|
||||
dependencies {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package demo.datajpamultipersist;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
//tag::snippetA[]
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
//end::snippetA[]
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package demo.datajpamultipersist;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineModelConfigurer;
|
||||
import org.springframework.statemachine.config.model.StateMachineModelFactory;
|
||||
import org.springframework.statemachine.data.RepositoryState;
|
||||
import org.springframework.statemachine.data.RepositoryStateMachineModelFactory;
|
||||
import org.springframework.statemachine.data.RepositoryTransition;
|
||||
import org.springframework.statemachine.data.StateRepository;
|
||||
import org.springframework.statemachine.data.TransitionRepository;
|
||||
import org.springframework.statemachine.data.jpa.JpaPersistingStateMachineInterceptor;
|
||||
import org.springframework.statemachine.data.jpa.JpaStateMachineRepository;
|
||||
import org.springframework.statemachine.data.support.StateMachineJackson2RepositoryPopulatorFactoryBean;
|
||||
import org.springframework.statemachine.persist.StateMachineRuntimePersister;
|
||||
import org.springframework.statemachine.service.DefaultStateMachineService;
|
||||
import org.springframework.statemachine.service.StateMachineService;
|
||||
|
||||
@Configuration
|
||||
public class StateMachineConfig {
|
||||
|
||||
@Bean
|
||||
public StateMachineRuntimePersister<String, String, String> stateMachineRuntimePersister(
|
||||
JpaStateMachineRepository jpaStateMachineRepository) {
|
||||
return new JpaPersistingStateMachineInterceptor<>(jpaStateMachineRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StateMachineService<String, String> stateMachineService(
|
||||
StateMachineFactory<String, String> stateMachineFactory,
|
||||
StateMachineRuntimePersister<String, String, String> stateMachineRuntimePersister) {
|
||||
return new DefaultStateMachineService<String, String>(stateMachineFactory, stateMachineRuntimePersister);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
|
||||
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
|
||||
factoryBean.setResources(new Resource[] { new ClassPathResource("data.json") });
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachineFactory
|
||||
public static class Config extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
@Autowired
|
||||
private StateRepository<? extends RepositoryState> stateRepository;
|
||||
|
||||
@Autowired
|
||||
private TransitionRepository<? extends RepositoryTransition> transitionRepository;
|
||||
|
||||
@Autowired
|
||||
private StateMachineRuntimePersister<String, String, String> stateMachineRuntimePersister;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<String, String> config)
|
||||
throws Exception {
|
||||
config
|
||||
.withPersistence()
|
||||
.runtimePersister(stateMachineRuntimePersister);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineModelConfigurer<String, String> model)
|
||||
throws Exception {
|
||||
model
|
||||
.withModel()
|
||||
.factory(modelFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StateMachineModelFactory<String, String> modelFactory() {
|
||||
return new RepositoryStateMachineModelFactory(stateRepository, transitionRepository);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package demo.datajpamultipersist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.StateMachineContext;
|
||||
import org.springframework.statemachine.StateMachinePersist;
|
||||
import org.springframework.statemachine.data.RepositoryTransition;
|
||||
import org.springframework.statemachine.data.TransitionRepository;
|
||||
import org.springframework.statemachine.service.StateMachineService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Controller
|
||||
public class StateMachineController {
|
||||
|
||||
public final static String MACHINE_ID_1 = "datajpamultipersist1";
|
||||
public final static String MACHINE_ID_2 = "datajpamultipersist2";
|
||||
public final static String MACHINE_ID_2R1 = "datajpamultipersist2#R1";
|
||||
public final static String MACHINE_ID_2R2 = "datajpamultipersist2#R2";
|
||||
private final static String[] MACHINES = new String[] { MACHINE_ID_1, MACHINE_ID_2 };
|
||||
private final StateMachineLogListener listener = new StateMachineLogListener();
|
||||
|
||||
@Autowired
|
||||
private StateMachineService<String, String> stateMachineService;
|
||||
|
||||
@Autowired
|
||||
private StateMachinePersist<String, String, String> stateMachinePersist;
|
||||
|
||||
@Autowired
|
||||
private TransitionRepository<? extends RepositoryTransition> transitionRepository;
|
||||
|
||||
private StateMachine<String, String> currentStateMachine;
|
||||
|
||||
@RequestMapping("/")
|
||||
public String home() {
|
||||
return "redirect:/state";
|
||||
}
|
||||
|
||||
@RequestMapping("/state")
|
||||
public String feedAndGetStates(
|
||||
@RequestParam(value = "events", required = false) List<String> events,
|
||||
@RequestParam(value = "machine", required = false, defaultValue = MACHINE_ID_1) String machine,
|
||||
Model model) throws Exception {
|
||||
|
||||
|
||||
StateMachine<String, String> stateMachine = getStateMachine(machine);
|
||||
if (events != null) {
|
||||
for (String event : events) {
|
||||
stateMachine.sendEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder contextBuf = new StringBuilder();
|
||||
|
||||
StateMachineContext<String, String> stateMachineContext = stateMachinePersist.read(machine);
|
||||
if (stateMachineContext != null) {
|
||||
contextBuf.append(stateMachineContext.toString());
|
||||
}
|
||||
if (ObjectUtils.nullSafeEquals(machine, MACHINE_ID_2)) {
|
||||
stateMachineContext = stateMachinePersist.read(MACHINE_ID_2R1);
|
||||
if (stateMachineContext != null) {
|
||||
contextBuf.append("\n---\n");
|
||||
contextBuf.append(stateMachineContext.toString());
|
||||
}
|
||||
stateMachineContext = stateMachinePersist.read(MACHINE_ID_2R2);
|
||||
if (stateMachineContext != null) {
|
||||
contextBuf.append("\n---\n");
|
||||
contextBuf.append(stateMachineContext.toString());
|
||||
}
|
||||
}
|
||||
|
||||
model.addAttribute("allMachines", MACHINES);
|
||||
model.addAttribute("machine", machine);
|
||||
model.addAttribute("currentMachine", currentStateMachine);
|
||||
model.addAttribute("allEvents", getEvents());
|
||||
model.addAttribute("messages", createMessages(listener.getMessages()));
|
||||
model.addAttribute("context", contextBuf.toString());
|
||||
return "states";
|
||||
}
|
||||
|
||||
private synchronized StateMachine<String, String> getStateMachine(String machineId) throws Exception {
|
||||
listener.resetMessages();
|
||||
if (currentStateMachine == null) {
|
||||
currentStateMachine = stateMachineService.acquireStateMachine(machineId, false);
|
||||
currentStateMachine.addStateListener(listener);
|
||||
currentStateMachine.start();
|
||||
} else if (!ObjectUtils.nullSafeEquals(currentStateMachine.getId(), machineId)) {
|
||||
stateMachineService.releaseStateMachine(currentStateMachine.getId());
|
||||
currentStateMachine.stop();
|
||||
currentStateMachine = stateMachineService.acquireStateMachine(machineId, false);
|
||||
currentStateMachine.addStateListener(listener);
|
||||
currentStateMachine.start();
|
||||
}
|
||||
return currentStateMachine;
|
||||
}
|
||||
|
||||
private String[] getEvents() {
|
||||
List<String> events = new ArrayList<>();
|
||||
for (RepositoryTransition t : transitionRepository.findAll()) {
|
||||
events.add(t.getEvent());
|
||||
}
|
||||
return events.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private String createMessages(List<String> messages) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (String message : messages) {
|
||||
buf.append(message);
|
||||
buf.append("\n");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package demo.datajpamultipersist;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateContext.Stage;
|
||||
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
|
||||
|
||||
public class StateMachineLogListener extends StateMachineListenerAdapter<String, String> {
|
||||
|
||||
private final LinkedList<String> messages = new LinkedList<String>();
|
||||
|
||||
public List<String> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public void resetMessages() {
|
||||
messages.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateContext(StateContext<String, String> stateContext) {
|
||||
if (stateContext.getStage() == Stage.STATE_ENTRY) {
|
||||
messages.addFirst("Enter " + stateContext.getTarget().getId());
|
||||
} else if (stateContext.getStage() == Stage.STATE_EXIT) {
|
||||
messages.addFirst("Exit " + stateContext.getSource().getId());
|
||||
} else if (stateContext.getStage() == Stage.STATEMACHINE_START) {
|
||||
messages.addLast("Machine started");
|
||||
} else if (stateContext.getStage() == Stage.STATEMACHINE_STOP) {
|
||||
messages.addFirst("Machine stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
logging:
|
||||
level:
|
||||
root: INFO
|
||||
org.springframework.statemachine: DEBUG
|
||||
security:
|
||||
basic:
|
||||
enabled: false
|
||||
@@ -0,0 +1,172 @@
|
||||
[
|
||||
{
|
||||
"@id": "100",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryAction",
|
||||
"spel": "T(System).out.println('hello exit S1')"
|
||||
},
|
||||
{
|
||||
"@id": "101",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryAction",
|
||||
"spel": "T(System).out.println('hello entry S2')"
|
||||
},
|
||||
{
|
||||
"@id": "102",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryAction",
|
||||
"spel": "T(System).out.println('hello state S3')"
|
||||
},
|
||||
{
|
||||
"@id": "103",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryAction",
|
||||
"spel": "T(System).out.println('hello')"
|
||||
},
|
||||
{
|
||||
"@id": "10",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist1",
|
||||
"initial": true,
|
||||
"state": "S1",
|
||||
"exitActions": ["100"]
|
||||
},
|
||||
{
|
||||
"@id": "11",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist1",
|
||||
"initial": false,
|
||||
"state": "S2",
|
||||
"entryActions": ["101"]
|
||||
},
|
||||
{
|
||||
"@id": "12",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist1",
|
||||
"initial": false,
|
||||
"state": "S3",
|
||||
"stateActions": ["102"]
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist1",
|
||||
"source": "10",
|
||||
"target": "11",
|
||||
"event": "E1",
|
||||
"kind": "EXTERNAL"
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist1",
|
||||
"source": "11",
|
||||
"target": "12",
|
||||
"event": "E2",
|
||||
"actions": ["103"]
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist1",
|
||||
"source": "12",
|
||||
"target": "11",
|
||||
"event": "E3",
|
||||
"actions": ["103"]
|
||||
},
|
||||
{
|
||||
"@id": "20",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"region": "R1",
|
||||
"initial": true,
|
||||
"state": "S10",
|
||||
"exitActions": ["100"]
|
||||
},
|
||||
{
|
||||
"@id": "21",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"region": "R1",
|
||||
"initial": false,
|
||||
"state": "S11",
|
||||
"entryActions": ["101"]
|
||||
},
|
||||
{
|
||||
"@id": "22",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"region": "R1",
|
||||
"initial": false,
|
||||
"state": "S12",
|
||||
"stateActions": ["102"]
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"source": "20",
|
||||
"target": "21",
|
||||
"event": "E10",
|
||||
"kind": "EXTERNAL"
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"source": "21",
|
||||
"target": "22",
|
||||
"event": "E11",
|
||||
"actions": ["103"]
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"source": "22",
|
||||
"target": "21",
|
||||
"event": "E12",
|
||||
"actions": ["103"]
|
||||
},
|
||||
{
|
||||
"@id": "30",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"region": "R2",
|
||||
"initial": true,
|
||||
"state": "S20",
|
||||
"exitActions": ["100"]
|
||||
},
|
||||
{
|
||||
"@id": "31",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"region": "R2",
|
||||
"initial": false,
|
||||
"state": "S21",
|
||||
"entryActions": ["101"]
|
||||
},
|
||||
{
|
||||
"@id": "32",
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"region": "R2",
|
||||
"initial": false,
|
||||
"state": "S22",
|
||||
"stateActions": ["102"]
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"source": "30",
|
||||
"target": "31",
|
||||
"event": "E20",
|
||||
"kind": "EXTERNAL"
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"source": "31",
|
||||
"target": "32",
|
||||
"event": "E21",
|
||||
"actions": ["103"]
|
||||
},
|
||||
{
|
||||
"_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition",
|
||||
"machineId": "datajpamultipersist2",
|
||||
"source": "32",
|
||||
"target": "31",
|
||||
"event": "E22",
|
||||
"actions": ["103"]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Spring Statemachine Demo</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<a href="/h2-console" target="_blank">h2 console</a>
|
||||
</div>
|
||||
|
||||
<form action="#" data-th-action="@{/state}" data-th-object="${model}" method="post">
|
||||
<div>
|
||||
<p th:text="'Choose machine'"/>
|
||||
<ul>
|
||||
<li th:each="ty : ${allMachines}">
|
||||
<input type="radio" name="machine" th:value="${ty}" th:checked="${ty} == ${machine}"/>
|
||||
<label th:text="${ty}">replaced</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p th:text="'Choose events'"/>
|
||||
<ul>
|
||||
<li th:each="ty : ${allEvents}">
|
||||
<input type="checkbox" name="events" th:value="${ty}" />
|
||||
<label th:text="${ty}">replaced</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="submit">Send Events</button>
|
||||
</form>
|
||||
<div>
|
||||
<h3>Events</h3>
|
||||
</div>
|
||||
<div>
|
||||
<textarea th:text="${messages}" rows="15" cols="100"/>
|
||||
</div>
|
||||
<div>
|
||||
<h3>StateMachineContext</h3>
|
||||
</div>
|
||||
<div>
|
||||
<textarea th:text="${context}" rows="15" cols="100"/>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Current Machine</h3>
|
||||
</div>
|
||||
<div>
|
||||
<textarea th:text="${currentMachine}" rows="10" cols="100"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package demo.datajpamultipersist;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import demo.datajpamultipersist.Application;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = { Application.class })
|
||||
@WebAppConfiguration
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
public class DataJpaMultiPersistTests {
|
||||
|
||||
private MockMvc mvc;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void testHome() throws Exception {
|
||||
mvc.
|
||||
perform(get("/state")).
|
||||
andExpect(status().isOk()).
|
||||
andExpect(content().string(allOf(
|
||||
containsString("Enter S1"),
|
||||
containsString("Machine started"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendEventE1WithMachine1() throws Exception {
|
||||
mvc.
|
||||
perform(get("/state")
|
||||
.param("events", "E1")
|
||||
.param("machine", StateMachineController.MACHINE_ID_1)).
|
||||
andExpect(status().isOk()).
|
||||
andExpect(content().string(allOf(
|
||||
containsString("Enter S1"),
|
||||
containsString("Exit S1"),
|
||||
containsString("Enter S2"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendEventsE1E2WithMachine1() throws Exception {
|
||||
mvc.
|
||||
perform(get("/state")
|
||||
.param("events", "E1")
|
||||
.param("events", "E2")
|
||||
.param("machine", StateMachineController.MACHINE_ID_1)).
|
||||
andExpect(status().isOk()).
|
||||
andExpect(content().string(allOf(
|
||||
containsString("Enter S1"),
|
||||
containsString("Exit S1"),
|
||||
containsString("Enter S2"),
|
||||
containsString("Exit S2"),
|
||||
containsString("Enter S3"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMachine2() throws Exception {
|
||||
mvc.
|
||||
perform(get("/state")
|
||||
.param("machine", StateMachineController.MACHINE_ID_2)).
|
||||
andExpect(status().isOk()).
|
||||
andExpect(content().string(allOf(
|
||||
containsString("Enter S10"),
|
||||
containsString("Enter S20"),
|
||||
containsString("Enter null"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendEventsE10E20WithMachine2() throws Exception {
|
||||
mvc.
|
||||
perform(get("/state")
|
||||
.param("events", "E10")
|
||||
.param("events", "E20")
|
||||
.param("machine", StateMachineController.MACHINE_ID_2)).
|
||||
andExpect(status().isOk()).
|
||||
andExpect(content().string(allOf(
|
||||
containsString("Enter S10"),
|
||||
containsString("Enter S20"),
|
||||
containsString("Enter S11"),
|
||||
containsString("Enter S21"),
|
||||
containsString("Enter null"))));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user