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.demux;
21
22 import org.apache.mina.core.buffer.IoBuffer;
23 import org.apache.mina.core.session.AttributeKey;
24 import org.apache.mina.core.session.IoSession;
25 import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
26 import org.apache.mina.filter.codec.ProtocolDecoder;
27 import org.apache.mina.filter.codec.ProtocolDecoderException;
28 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class DemuxingProtocolDecoder extends CumulativeProtocolDecoder {
74
75 private final AttributeKey STATE = new AttributeKey(getClass(), "state");
76
77 private MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0];
78 private static final Class<?>[] EMPTY_PARAMS = new Class[0];
79
80 public DemuxingProtocolDecoder() {
81
82 }
83
84 public void addMessageDecoder(Class<? extends MessageDecoder> decoderClass) {
85 if (decoderClass == null) {
86 throw new IllegalArgumentException("decoderClass");
87 }
88
89 try {
90 decoderClass.getConstructor(EMPTY_PARAMS);
91 } catch (NoSuchMethodException e) {
92 throw new IllegalArgumentException(
93 "The specified class doesn't have a public default constructor.");
94 }
95
96 boolean registered = false;
97 if (MessageDecoder.class.isAssignableFrom(decoderClass)) {
98 addMessageDecoder(new DefaultConstructorMessageDecoderFactory(decoderClass));
99 registered = true;
100 }
101
102 if (!registered) {
103 throw new IllegalArgumentException(
104 "Unregisterable type: " + decoderClass);
105 }
106 }
107
108 public void addMessageDecoder(MessageDecoder decoder) {
109 addMessageDecoder(new SingletonMessageDecoderFactory(decoder));
110 }
111
112 public void addMessageDecoder(MessageDecoderFactory factory) {
113 if (factory == null) {
114 throw new IllegalArgumentException("factory");
115 }
116 MessageDecoderFactory[] decoderFactories = this.decoderFactories;
117 MessageDecoderFactory[] newDecoderFactories = new MessageDecoderFactory[decoderFactories.length + 1];
118 System.arraycopy(decoderFactories, 0, newDecoderFactories, 0,
119 decoderFactories.length);
120 newDecoderFactories[decoderFactories.length] = factory;
121 this.decoderFactories = newDecoderFactories;
122 }
123
124
125
126
127 @Override
128 protected boolean doDecode(IoSession session, IoBuffer in,
129 ProtocolDecoderOutput out) throws Exception {
130 State state = getState(session);
131
132 if (state.currentDecoder == null) {
133 MessageDecoder[] decoders = state.decoders;
134 int undecodables = 0;
135
136 for (int i = decoders.length - 1; i >= 0; i--) {
137 MessageDecoder decoder = decoders[i];
138 int limit = in.limit();
139 int pos = in.position();
140
141 MessageDecoderResult result;
142
143 try {
144 result = decoder.decodable(session, in);
145 } finally {
146 in.position(pos);
147 in.limit(limit);
148 }
149
150 if (result == MessageDecoder.OK) {
151 state.currentDecoder = decoder;
152 break;
153 } else if (result == MessageDecoder.NOT_OK) {
154 undecodables++;
155 } else if (result != MessageDecoder.NEED_DATA) {
156 throw new IllegalStateException(
157 "Unexpected decode result (see your decodable()): "
158 + result);
159 }
160 }
161
162 if (undecodables == decoders.length) {
163
164 String dump = in.getHexDump();
165 in.position(in.limit());
166 ProtocolDecoderException e = new ProtocolDecoderException(
167 "No appropriate message decoder: " + dump);
168 e.setHexdump(dump);
169 throw e;
170 }
171
172 if (state.currentDecoder == null) {
173
174 return false;
175 }
176 }
177
178 try {
179 MessageDecoderResult result = state.currentDecoder.decode(session, in,
180 out);
181 if (result == MessageDecoder.OK) {
182 state.currentDecoder = null;
183 return true;
184 } else if (result == MessageDecoder.NEED_DATA) {
185 return false;
186 } else if (result == MessageDecoder.NOT_OK) {
187 state.currentDecoder = null;
188 throw new ProtocolDecoderException(
189 "Message decoder returned NOT_OK.");
190 } else {
191 state.currentDecoder = null;
192 throw new IllegalStateException(
193 "Unexpected decode result (see your decode()): "
194 + result);
195 }
196 } catch (Exception e) {
197 state.currentDecoder = null;
198 throw e;
199 }
200 }
201
202
203
204
205 @Override
206 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
207 throws Exception {
208 super.finishDecode(session, out);
209 State state = getState(session);
210 MessageDecoder currentDecoder = state.currentDecoder;
211 if (currentDecoder == null) {
212 return;
213 }
214
215 currentDecoder.finishDecode(session, out);
216 }
217
218
219
220
221 @Override
222 public void dispose(IoSession session) throws Exception {
223 super.dispose(session);
224 session.removeAttribute(STATE);
225 }
226
227 private State getState(IoSession session) throws Exception {
228 State state = (State) session.getAttribute(STATE);
229
230 if (state == null) {
231 state = new State();
232 State oldState = (State) session.setAttributeIfAbsent(STATE, state);
233
234 if (oldState != null) {
235 state = oldState;
236 }
237 }
238
239 return state;
240 }
241
242 private class State {
243 private final MessageDecoder[] decoders;
244 private MessageDecoder currentDecoder;
245
246 private State() throws Exception {
247 MessageDecoderFactory[] decoderFactories = DemuxingProtocolDecoder.this.decoderFactories;
248 decoders = new MessageDecoder[decoderFactories.length];
249 for (int i = decoderFactories.length - 1; i >= 0; i--) {
250 decoders[i] = decoderFactories[i].getDecoder();
251 }
252 }
253 }
254
255 private static class SingletonMessageDecoderFactory implements
256 MessageDecoderFactory {
257 private final MessageDecoder decoder;
258
259 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
260 if (decoder == null) {
261 throw new IllegalArgumentException("decoder");
262 }
263 this.decoder = decoder;
264 }
265
266 public MessageDecoder getDecoder() {
267 return decoder;
268 }
269 }
270
271 private static class DefaultConstructorMessageDecoderFactory implements
272 MessageDecoderFactory {
273 private final Class<?> decoderClass;
274
275 private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
276 if (decoderClass == null) {
277 throw new IllegalArgumentException("decoderClass");
278 }
279
280 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
281 throw new IllegalArgumentException(
282 "decoderClass is not assignable to MessageDecoder");
283 }
284 this.decoderClass = decoderClass;
285 }
286
287 public MessageDecoder getDecoder() throws Exception {
288 return (MessageDecoder) decoderClass.newInstance();
289 }
290 }
291 }