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 MessageDecoderResult result = state.currentDecoder.decode(session, in,
179 out);
180 if (result == MessageDecoder.OK) {
181 state.currentDecoder = null;
182 return true;
183 } else if (result == MessageDecoder.NEED_DATA) {
184 return false;
185 } else if (result == MessageDecoder.NOT_OK) {
186 state.currentDecoder = null;
187 throw new ProtocolDecoderException(
188 "Message decoder returned NOT_OK.");
189 } else {
190 state.currentDecoder = null;
191 throw new IllegalStateException(
192 "Unexpected decode result (see your decode()): "
193 + result);
194 }
195 }
196
197
198
199
200 @Override
201 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
202 throws Exception {
203 super.finishDecode(session, out);
204 State state = getState(session);
205 MessageDecoder currentDecoder = state.currentDecoder;
206 if (currentDecoder == null) {
207 return;
208 }
209
210 currentDecoder.finishDecode(session, out);
211 }
212
213
214
215
216 @Override
217 public void dispose(IoSession session) throws Exception {
218 super.dispose(session);
219 session.removeAttribute(STATE);
220 }
221
222 private State getState(IoSession session) throws Exception {
223 State state = (State) session.getAttribute(STATE);
224
225 if (state == null) {
226 state = new State();
227 State oldState = (State) session.setAttributeIfAbsent(STATE, state);
228
229 if (oldState != null) {
230 state = oldState;
231 }
232 }
233
234 return state;
235 }
236
237 private class State {
238 private final MessageDecoder[] decoders;
239 private MessageDecoder currentDecoder;
240
241 private State() throws Exception {
242 MessageDecoderFactory[] decoderFactories = DemuxingProtocolDecoder.this.decoderFactories;
243 decoders = new MessageDecoder[decoderFactories.length];
244 for (int i = decoderFactories.length - 1; i >= 0; i--) {
245 decoders[i] = decoderFactories[i].getDecoder();
246 }
247 }
248 }
249
250 private static class SingletonMessageDecoderFactory implements
251 MessageDecoderFactory {
252 private final MessageDecoder decoder;
253
254 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
255 if (decoder == null) {
256 throw new IllegalArgumentException("decoder");
257 }
258 this.decoder = decoder;
259 }
260
261 public MessageDecoder getDecoder() {
262 return decoder;
263 }
264 }
265
266 private static class DefaultConstructorMessageDecoderFactory implements
267 MessageDecoderFactory {
268 private final Class<?> decoderClass;
269
270 private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
271 if (decoderClass == null) {
272 throw new IllegalArgumentException("decoderClass");
273 }
274
275 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
276 throw new IllegalArgumentException(
277 "decoderClass is not assignable to MessageDecoder");
278 }
279 this.decoderClass = decoderClass;
280 }
281
282 public MessageDecoder getDecoder() throws Exception {
283 return (MessageDecoder) decoderClass.newInstance();
284 }
285 }
286 }