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 static final Logger LOGGER = LoggerFactory.getLogger(DecodingStateMachine.class);
52
53 private final List<Object> childProducts = new ArrayList<>();
54
55 private final ProtocolDecoderOutputerOutput.html#ProtocolDecoderOutput">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
179 if (LOGGER.isDebugEnabled()) {
180 LOGGER.debug("Ignoring the exception caused by a closed session.", e);
181 }
182 } finally {
183 this.currentState = state;
184 nextState = finishDecode(childProducts, out);
185 if (state == null) {
186 cleanup();
187 }
188 }
189 return nextState;
190 }
191
192 private void cleanup() {
193 if (!initialized) {
194 throw new IllegalStateException();
195 }
196
197 initialized = false;
198 childProducts.clear();
199 try {
200 destroy();
201 } catch (Exception e2) {
202 if (LOGGER.isDebugEnabled()) {
203 LOGGER.warn("Failed to destroy a decoding state machine.", e2);
204 }
205 }
206 }
207
208 private DecodingState getCurrentState() throws Exception {
209 DecodingState state = this.currentState;
210 if (state == null) {
211 state = init();
212 initialized = true;
213 }
214 return state;
215 }
216 }