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