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<Object>();
54
55 private final ProtocolDecoderOutput childOutput = new ProtocolDecoderOutput() {
56 public void flush(NextFilter nextFilter, IoSession session) {
57
58 }
59
60 public void write(Object message) {
61 childProducts.add(message);
62 }
63 };
64
65 private DecodingState currentState;
66
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, ProtocolDecoderOutput out)
87 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) throws Exception {
99 DecodingState state = getCurrentState();
100
101 final int limit = in.limit();
102 int pos = in.position();
103
104 try {
105 for (;;) {
106
107 if (pos == limit) {
108 break;
109 }
110
111 DecodingState oldState = state;
112 state = state.decode(in, childOutput);
113
114
115 if (state == null) {
116 return finishDecode(childProducts, out);
117 }
118
119 int newPos = in.position();
120
121
122 if (newPos == pos && oldState == state) {
123 break;
124 }
125 pos = newPos;
126 }
127
128 return this;
129 } catch (Exception e) {
130 state = null;
131 throw e;
132 } finally {
133 this.currentState = state;
134
135
136 if (state == null) {
137 cleanup();
138 }
139 }
140 }
141
142
143
144
145 public DecodingState finishDecode(ProtocolDecoderOutput out) 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("Ignoring the exception caused by a closed session.", e);
165 } finally {
166 this.currentState = state;
167 nextState = finishDecode(childProducts, out);
168 if (state == null) {
169 cleanup();
170 }
171 }
172 return nextState;
173 }
174
175 private void cleanup() {
176 if (!initialized) {
177 throw new IllegalStateException();
178 }
179
180 initialized = false;
181 childProducts.clear();
182 try {
183 destroy();
184 } catch (Exception e2) {
185 log.warn("Failed to destroy a decoding state machine.", e2);
186 }
187 }
188
189 private DecodingState getCurrentState() throws Exception {
190 DecodingState state = this.currentState;
191 if (state == null) {
192 state = init();
193 initialized = true;
194 }
195 return state;
196 }
197 }