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