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