1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.codec.statemachine;
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.apache.mina.core.buffer.IoBuffer;
26 import org.apache.mina.core.filterchain.IoFilter.NextFilter;
27 import org.apache.mina.core.session.IoSession;
28 import org.apache.mina.filter.codec.ProtocolCodecFilter;
29 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public abstract class DecodingStateMachine implements DecodingState {
51 private final Logger log = LoggerFactory.getLogger(DecodingStateMachine.class);
52
53 private final List<Object> childProducts = new ArrayList<>();
54
55 private final ProtocolDecoderOutput childOutput = new ProtocolDecoderOutput() {
56
57
58
59 @Override
60 public void flush(NextFilter nextFilter, IoSession session) {
61
62 }
63
64
65
66
67 @Override
68 public void write(Object message) {
69 childProducts.add(message);
70 }
71 };
72
73 private DecodingState currentState;
74
75 private boolean initialized;
76
77
78
79
80
81
82
83 protected abstract DecodingState init() throws Exception;
84
85
86
87
88
89
90
91
92
93
94
95
96 protected abstract DecodingState finishDecode(List<Object> childProducts, ProtocolDecoderOutput out)
97 throws Exception;
98
99
100
101
102
103
104
105 protected abstract void destroy() throws Exception;
106
107
108
109
110 @Override
111 public DecodingState decode(IoBuffer in, ProtocolDecoderOutput out) throws Exception {
112 DecodingState state = getCurrentState();
113
114 final int limit = in.limit();
115 int pos = in.position();
116
117 try {
118 for (;;) {
119
120 if (pos == limit) {
121 break;
122 }
123
124 DecodingState oldState = state;
125 state = state.decode(in, childOutput);
126
127
128 if (state == null) {
129 return finishDecode(childProducts, out);
130 }
131
132 int newPos = in.position();
133
134
135 if (newPos == pos && oldState == state) {
136 break;
137 }
138 pos = newPos;
139 }
140
141 return this;
142 } catch (Exception e) {
143 state = null;
144 throw e;
145 } finally {
146 this.currentState = state;
147
148
149 if (state == null) {
150 cleanup();
151 }
152 }
153 }
154
155
156
157
158 @Override
159 public DecodingState finishDecode(ProtocolDecoderOutput out) throws Exception {
160 DecodingState nextState;
161 DecodingState state = getCurrentState();
162 try {
163 for (;;) {
164 DecodingState oldState = state;
165 state = state.finishDecode(childOutput);
166 if (state == null) {
167
168 break;
169 }
170
171
172 if (oldState == state) {
173 break;
174 }
175 }
176 } catch (Exception e) {
177 state = null;
178 log.debug("Ignoring the exception caused by a closed session.", e);
179 } finally {
180 this.currentState = state;
181 nextState = finishDecode(childProducts, out);
182 if (state == null) {
183 cleanup();
184 }
185 }
186 return nextState;
187 }
188
189 private void cleanup() {
190 if (!initialized) {
191 throw new IllegalStateException();
192 }
193
194 initialized = false;
195 childProducts.clear();
196 try {
197 destroy();
198 } catch (Exception e2) {
199 log.warn("Failed to destroy a decoding state machine.", e2);
200 }
201 }
202
203 private DecodingState getCurrentState() throws Exception {
204 DecodingState state = this.currentState;
205 if (state == null) {
206 state = init();
207 initialized = true;
208 }
209 return state;
210 }
211 }