State Transitions With Spring Integration – DZone Integration | xxxState Transitions With Spring Integration – DZone Integration – xxx
菜单

State Transitions With Spring Integration – DZone Integration

二月 29, 2020 - MorningStar

Over a million developers have joined DZone.

  • State Transitions With Spring Integration - DZone Integration

    {{node.title}}

    {{node.type}} · {{ node.urlSource.name }} by

    Download {{node.downloads}}

  • {{totalResults}} search results

{{announcement.body}}

{{announcement.title}}

Let’s be friends:

1024)” dc-slot=”ads.sl1.slot(articles[0], 0)” tags=”ads.sl1.tags(articles[0], 0)” size=”ads.sl1.size(articles[0], 0)” style=”border:0px;”>
1 && !articles[0].partner.isSponsoringArticle && (width > 1024)” dc-slot=”ads.sb2.slot(articles[0], 0)” tags=”ads.sb2.tags(articles[0], 0)” size=”ads.sb2.size(articles[0], 0)”>

State Transitions With Spring Integration

DZone ‘s Guide to

State Transitions With Spring Integration

In this article, look at how to implement a non-blocking state machine with the Spring Integration framework.

Apr. 07, 20 · Integration Zone ·

Free Resource

Join the DZone community and get the full member experience.

Join For Free

In a previous article, I presented a framework for a simple state machine. In a follow-up article, I customized the framework for non-blocking processes using callback functions. In this article, I propose an approach to implementing a non-blocking state machine with the Spring Integration framework. The Spring Integration framework provides many communication mechanisms between applications and components. I will be using just the Message Channels for my example. I’ll also use Spring Boot to drive the state transitions.  

Order Processing Example: State Transitions

I consider a simple order processing application where a customer creates an order and then pays for the order. The first step in implementing a state machine is to write the state transitions for the application. I will assume that the following are the allowable state transitions for the above order scenario.

Initial StatePre-EventProcessorPost-EventFinal State
DefaultcreateorderProcessor()orderCreatedPaymentPending
PaymentPendingpaypaymentProcessor()paymentErrorPaymentErrorEmailSent
PaymentErrorEmailSentretryPaypaymentProcessor()paymentSuccessPaymenSuccessEmailSent
PaymentPendingpaypaymentProcessor()paymentSuccessPaymenSuccessEmailSent

I’ll further assume that the  orderProcessor()  is a blocking process and the  paymentProcessor()  is a non-blocking process. 

Configuring States and Events

The next step is to configure the states and events identified above. I use Java enums to configure the states and events. 

The states are configured like:

Java

x

13

 

1

//ProcessState is a marker interface

2

public interface ProcessState {

3

}

4

5

public enum OrderState implements ProcessState {

6

    DEFAULT,

7

    PAYMENTPENDING,

8

    PAYINPROGRESS,

9

    PAYMENTERROREMAILSENT,

10

    REPAYINPROGRESS,

11

public interface ProcessState {

0

12

public interface ProcessState {

1

Note that I have added two additional states – PAYINPROGRESS and RETRYPAYINPROGRESS corresponding to the two pre-events PAY and RETRYPAY. This will help us in validating the pre-events that might arrive before the long running non-blocking process completes. 

The events are then configured like:

Java

public interface ProcessState {

2

1

162

 

1

public interface ProcessState {

3

2

public interface ProcessState {

4

3

public interface ProcessState {

5

4

public interface ProcessState {

6

5

public interface ProcessState {

7

6

public interface ProcessState {

8

7

public interface ProcessState {

9

8

}

0

9

}

1

10

}

2

11

}

3

12

}

4

13

}

5

14

}

6

15

}

7

16

}

8

17

}

9

18

0

19

1

20

2

21

3

22

4

23

5

24

6

25

7

26

8

27

9

28

public enum OrderState implements ProcessState {

0

29

public enum OrderState implements ProcessState {

1

30

public enum OrderState implements ProcessState {

2

31

public enum OrderState implements ProcessState {

3

32

public enum OrderState implements ProcessState {

4

33

public enum OrderState implements ProcessState {

5

34

public enum OrderState implements ProcessState {

6

35

public enum OrderState implements ProcessState {

7

36

public enum OrderState implements ProcessState {

8

37

public enum OrderState implements ProcessState {

9

38

    DEFAULT,

0

39

    DEFAULT,

1

40

    DEFAULT,

2

41

    DEFAULT,

3

42

    DEFAULT,

4

43

    DEFAULT,

5

44

    DEFAULT,

6

45

    DEFAULT,

7

46

    DEFAULT,

8

47

    DEFAULT,

9

48

    PAYMENTPENDING,

0

49

    PAYMENTPENDING,

1

50

    PAYMENTPENDING,

2

51

    PAYMENTPENDING,

3

52

    PAYMENTPENDING,

4

53

    PAYMENTPENDING,

5

54

    PAYMENTPENDING,

6

55

    PAYMENTPENDING,

7

56

    PAYMENTPENDING,

8

57

    PAYMENTPENDING,

9

58

    PAYINPROGRESS,

0

59

    PAYINPROGRESS,

1

60

    PAYINPROGRESS,

2

61

    PAYINPROGRESS,

3

62

    PAYINPROGRESS,

4

63

    PAYINPROGRESS,

5

64

    PAYINPROGRESS,

6

65

    PAYINPROGRESS,

7

66

    PAYINPROGRESS,

8

67

    PAYINPROGRESS,

9

68

    PAYMENTERROREMAILSENT,

0

69

    PAYMENTERROREMAILSENT,

1

70

    PAYMENTERROREMAILSENT,

2

71

    PAYMENTERROREMAILSENT,

3

72

    PAYMENTERROREMAILSENT,

4

73

    PAYMENTERROREMAILSENT,

5

74

    PAYMENTERROREMAILSENT,

6

75

    PAYMENTERROREMAILSENT,

7

76

    PAYMENTERROREMAILSENT,

8

77

    PAYMENTERROREMAILSENT,

9

78

    REPAYINPROGRESS,

0

79

    REPAYINPROGRESS,

1

80

    REPAYINPROGRESS,

2

81

    REPAYINPROGRESS,

3

82

    REPAYINPROGRESS,

4

83

    REPAYINPROGRESS,

5

84

    REPAYINPROGRESS,

6

85

    REPAYINPROGRESS,

7

86

    REPAYINPROGRESS,

8

87

    REPAYINPROGRESS,

9

88

public interface ProcessState {

00

89

public interface ProcessState {

01

90

public interface ProcessState {

02

91

public interface ProcessState {

03

92

public interface ProcessState {

04

93

public interface ProcessState {

05

94

public interface ProcessState {

06

95

public interface ProcessState {

07

96

public interface ProcessState {

08

97

public interface ProcessState {

09

98

public interface ProcessState {

10

99

public interface ProcessState {

11

100

public interface ProcessState {

12

101

public interface ProcessState {

13

102

public interface ProcessState {

14

103

public interface ProcessState {

15

104

public interface ProcessState {

16

105

public interface ProcessState {

17

106

public interface ProcessState {

18

107

public interface ProcessState {

19

108

public interface ProcessState {

20

109

public interface ProcessState {

21

110

public interface ProcessState {

22

111

public interface ProcessState {

23

112

public interface ProcessState {

24

113

public interface ProcessState {

25

114

public interface ProcessState {

26

115

public interface ProcessState {

27

116

public interface ProcessState {

28

117

public interface ProcessState {

29

118

public interface ProcessState {

30

119

public interface ProcessState {

31

120

public interface ProcessState {

32

121

public interface ProcessState {

33

122

public interface ProcessState {

34

123

public interface ProcessState {

35

124

public interface ProcessState {

36

125

public interface ProcessState {

37

126

public interface ProcessState {

38

127

public interface ProcessState {

39

128

public interface ProcessState {

40

129

public interface ProcessState {

41

130

public interface ProcessState {

42

131

public interface ProcessState {

43

132

public interface ProcessState {

44

133

public interface ProcessState {

45

134

public interface ProcessState {

46

135

public interface ProcessState {

47

136

public interface ProcessState {

48

137

public interface ProcessState {

49

138

public interface ProcessState {

50

139

public interface ProcessState {

51

140

public interface ProcessState {

52

141

public interface ProcessState {

53

142

public interface ProcessState {

54

143

public interface ProcessState {

55

144

public interface ProcessState {

56

145

public interface ProcessState {

57

146

public interface ProcessState {

58

147

public interface ProcessState {

59

148

public interface ProcessState {

60

149

public interface ProcessState {

61

150

public interface ProcessState {

62

151

public interface ProcessState {

63

152

public interface ProcessState {

64

153

public interface ProcessState {

65

154

public interface ProcessState {

66

155

public interface ProcessState {

67

156

public interface ProcessState {

68

157

public interface ProcessState {

69

158

public interface ProcessState {

70

159

public interface ProcessState {

71

160

public interface ProcessState {

72

161

public interface ProcessState {

73

Order Processing Components

The order processing components are shown in the following diagram…

State Transitions With Spring Integration - DZone Integration

…where I have also shown the message channels used. The Spring Integration framework provides Messaging Gateway components. However, the custom facade components shown above offer more flexibility for the state machine implementation. 

Persisting State

An in-memory H2 database is used to persist the order states with the following configuration:

Java

public interface ProcessState {

74

1

39

 

1

public interface ProcessState {

75

2

public interface ProcessState {

76

3

public interface ProcessState {

77

4

public interface ProcessState {

78

5

public interface ProcessState {

79

6

public interface ProcessState {

80

7

public interface ProcessState {

81

8

public interface ProcessState {

82

9

public interface ProcessState {

83

10

public interface ProcessState {

84

11

public interface ProcessState {

85

12

public interface ProcessState {

86

13

public interface ProcessState {

87

14

public interface ProcessState {

88

15

public interface ProcessState {

89

16

public interface ProcessState {

90

17

public interface ProcessState {

91

18

public interface ProcessState {

92

19

public interface ProcessState {

93

20

public interface ProcessState {

94

21

public interface ProcessState {

95

22

public interface ProcessState {

96

23

public interface ProcessState {

97

24

public interface ProcessState {

98

25

public interface ProcessState {

99

26

}

00

27

}

01

28

}

02

29

}

03

30

}

04

31

}

05

32

}

06

33

}

07

34

}

08

35

}

09

36

}

10

37

}

11

38

}

12

A schema.sql file is used to create the table:

Java

}

13

1

 

1

}

14

2

}

15

3

}

16

4

}

17

5

}

18

6

}

19

For brevity of discussion I am not tracking order state history.

Spring Integration Message Channels Configuration

The next step is to configure the message channels. I will be using the xml configuration option as suggested in the Spring Integration sample.

XML

}

20

1

48

 

1

}

21

2

}

22

3

}

23

4

}

24

5

}

25

6

}

26

7

}

27

8

}

28

9

}

29

10

}

30

11

}

31

12

}

32

13

}

33

14

}

34

15

}

35

16

}

36

17

}

37

18

}

38

19

}

39

20

}

40

21

}

41

22

}

42

23

}

43

24

}

44

25

}

45

26

}

46

27

}

47

28

}

48

29

}

49

30

}

50

31

}

51

32

}

52

33

}

53

34

}

54

35

}

55

36

}

56

37

}

57

38

}

58

39

}

59

40

}

60

41

}

61

42

}

62

43

}

63

44

}

64

45

}

65

46

}

66

47

}

67

 

OrderStateTransitionsMgrBlocking.java  — a facade class that handles all state transitions that need to be synchronous.

Java

}

68

1

53

 

1

}

69

2

}

70

3

}

71

4

}

72

5

}

73

6

}

74

7

}

75

8

}

76

9

}

77

10

}

78

11

}

79

12

}

80

13

}

81

14

}

82

15

}

83

16

}

84

17

}

85

18

}

86

19

}

87

20

}

88

21

}

89

22

}

90

23

}

91

24

}

92

25

}

93

26

}

94

27

}

95

28

}

96

29

}

97

30

}

98

31

}

99

32

00

33

01

34

02

35

03

36

04

37

05

38

06

39

07

40

08

41

09

42

10

43

11

44

12

45

13

46

14

47

15

48

16

49

17

50

18

51

19

52

20

Note that blocking is enabled in the above by setting the timeout < 0.

OrderStateTransitionsMgrNonBlocking.java — a facade class that handles all state transitions that need to be non-blocking.

Java

21

1

42

 

1

22

2

23

3

24

4

25

5

26

6

27

7

28

8

29

9

30

10

31

11

32

12

33

13

34

14

35

15

36

16

37

17

38

18

39

19

40

20

41

21

42

22

43

23

44

24

45

25

46

26

47

27

48

28

49

29

50

30

51

31

52

32

53

33

54

34

55

35

56

36

57

37

58

38

59

39

60

40

61

41

62

Note that non-blocking is enabled by setting timeout=0.

OrderProcessor.java:

Java

63

1

12

 

1

64

2

65

3

66

4

67

5

68

6

69

7

70

8

71

9

72

10

73

11

74

 

PaymentProcessor.java:

Java

75

1

22

 

1

76

2

77

3

78

4

79

5

80

6

81

7

82

8

83

9

84

10

85

11

86

12

87

13

88

14

89

15

90

16

91

17

92

18

93

19

94

20

95

21

96

 

PostEventHandler.java:

Java

97

1

16

 

1

98

2

99

3

public enum OrderState implements ProcessState {

00

4

public enum OrderState implements ProcessState {

01

5

public enum OrderState implements ProcessState {

02

6

public enum OrderState implements ProcessState {

03

7

public enum OrderState implements ProcessState {

04

8

public enum OrderState implements ProcessState {

05

9

public enum OrderState implements ProcessState {

06

10

public enum OrderState implements ProcessState {

07

11

public enum OrderState implements ProcessState {

08

12

public enum OrderState implements ProcessState {

09

13

public enum OrderState implements ProcessState {

10

14

public enum OrderState implements ProcessState {

11

15

public enum OrderState implements ProcessState {

12

 

OrderController.java  – generates pre-events for the state machine.

Java

public enum OrderState implements ProcessState {

13

1

67

 

1

public enum OrderState implements ProcessState {

14

2

public enum OrderState implements ProcessState {

15

3

public enum OrderState implements ProcessState {

16

4

public enum OrderState implements ProcessState {

17

5

public enum OrderState implements ProcessState {

18

6

7

public enum OrderState implements ProcessState {

19

8

public enum OrderState implements ProcessState {

20

9

public enum OrderState implements ProcessState {

21

10

public enum OrderState implements ProcessState {

22

11

public enum OrderState implements ProcessState {

23

12

public enum OrderState implements ProcessState {

24

13

public enum OrderState implements ProcessState {

25

14

public enum OrderState implements ProcessState {

26

15

public enum OrderState implements ProcessState {

27

16

public enum OrderState implements ProcessState {

28

17

public enum OrderState implements ProcessState {

29

18

19

public enum OrderState implements ProcessState {

30

20

public enum OrderState implements ProcessState {

31

21

public enum OrderState implements ProcessState {

32

22

public enum OrderState implements ProcessState {

33

23

public enum OrderState implements ProcessState {

34

24

public enum OrderState implements ProcessState {

35

25

public enum OrderState implements ProcessState {

36

26

public enum OrderState implements ProcessState {

37

27

public enum OrderState implements ProcessState {

38

28

public enum OrderState implements ProcessState {

39

29

public enum OrderState implements ProcessState {

40

30

public enum OrderState implements ProcessState {

41

31

public enum OrderState implements ProcessState {

42

32

33

public enum OrderState implements ProcessState {

43

34

public enum OrderState implements ProcessState {

44

35

public enum OrderState implements ProcessState {

45

36

public enum OrderState implements ProcessState {

46

37

public enum OrderState implements ProcessState {

47

38

public enum OrderState implements ProcessState {

48

39

public enum OrderState implements ProcessState {

49

40

public enum OrderState implements ProcessState {

50

41

public enum OrderState implements ProcessState {

51

42

public enum OrderState implements ProcessState {

52

43

public enum OrderState implements ProcessState {

53

44

public enum OrderState implements ProcessState {

54

45

public enum OrderState implements ProcessState {

55

46

public enum OrderState implements ProcessState {

56

47

public enum OrderState implements ProcessState {

57

48

public enum OrderState implements ProcessState {

58

49

public enum OrderState implements ProcessState {

59

50

public enum OrderState implements ProcessState {

60

51

public enum OrderState implements ProcessState {

61

52

public enum OrderState implements ProcessState {

62

53

public enum OrderState implements ProcessState {

63

54

public enum OrderState implements ProcessState {

64

55

public enum OrderState implements ProcessState {

65

56

public enum OrderState implements ProcessState {

66

57

public enum OrderState implements ProcessState {

67

58

public enum OrderState implements ProcessState {

68

59

60

public enum OrderState implements ProcessState {

69

61

public enum OrderState implements ProcessState {

70

62

public enum OrderState implements ProcessState {

71

63

public enum OrderState implements ProcessState {

72

64

public enum OrderState implements ProcessState {

73

65

public enum OrderState implements ProcessState {

74

Full source for this sample application is available on GitHub.

Testing the State Machine

Due to the delayed responses from the non-blocking processes, the requests should be made with appropriate delays. Otherwise, either "Invalid state" or "The PAY/RETRYPAY event is in progress" responses are sent to the customer. The following scenarios can be tested:

Scenario #1: Create Order and make a valid payment(amount>0.00) – Customer receives success email.

Scenario #2: Create an order, make an invalid payment(amount=0.00) and followed by a valid payment without delay – Customer receives "The PAY event is in progress".

Scenario #3: Create an order, make an invalid payment and followed by a valid retry-payment without delay – Customer receives "Invalid state" response.

Scenario #4: Create an order, make an invalid payment and followed by a valid retry-payment with a delay(> 1s) – Customer receives payment success email.

I have included a JMeter test plan file so interested readers can run the above scenarios. The logs display the state transitions.

Conclusions

A simple example for a state machine with blocking and non-blocking processes is presented. It is shown that pre-defined state transitions can be maintained to produce robust applications even when non-blocking processes are introduced. The use of the state machine is found to produce clean and maintainable code. The Spring Integration framework is found to be minimally invasive and enables loose coupling of application components with simple configuration. 

Topics:
java ,state machines ,spring integration ,non-blocking ,state transitions

Opinions expressed by DZone contributors are their own.

Integration Partner Resources

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.linkDescription }}

{{ parent.urlSource.name }}

by

CORE

· {{ parent.articleDate | date:’MMM. dd, yyyy’ }} {{ parent.linkDate | date:’MMM. dd, yyyy’ }}


Notice: Undefined variable: canUpdate in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 51