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
74 public class DemuxingProtocolDecoder extends CumulativeProtocolDecoder {
75
76 private final AttributeKey STATE = new AttributeKey(getClass(), "state");
77
78 private MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0];
79 private static final Class<?>[] EMPTY_PARAMS = new Class[0];
80
81 public DemuxingProtocolDecoder() {
82 }
83
84 public void addMessageDecoder(Class<? extends MessageDecoder> decoderClass) {
85 if (decoderClass == null) {
86 throw new NullPointerException("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 NullPointerException("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 @Override
125 protected boolean doDecode(IoSession session, IoBuffer in,
126 ProtocolDecoderOutput out) throws Exception {
127 State state = getState(session);
128 if (state.currentDecoder == null) {
129 MessageDecoder[] decoders = state.decoders;
130 int undecodables = 0;
131 for (int i = decoders.length - 1; i >= 0; i--) {
132 MessageDecoder decoder = decoders[i];
133 int limit = in.limit();
134 int pos = in.position();
135
136 MessageDecoderResult result;
137 try {
138 result = decoder.decodable(session, in);
139 } finally {
140 in.position(pos);
141 in.limit(limit);
142 }
143
144 if (result == MessageDecoder.OK) {
145 state.currentDecoder = decoder;
146 break;
147 } else if (result == MessageDecoder.NOT_OK) {
148 undecodables++;
149 } else if (result != MessageDecoder.NEED_DATA) {
150 throw new IllegalStateException(
151 "Unexpected decode result (see your decodable()): "
152 + result);
153 }
154 }
155
156 if (undecodables == decoders.length) {
157
158 String dump = in.getHexDump();
159 in.position(in.limit());
160 ProtocolDecoderException e = new ProtocolDecoderException(
161 "No appropriate message decoder: " + dump);
162 e.setHexdump(dump);
163 throw e;
164 }
165
166 if (state.currentDecoder == null) {
167
168 return false;
169 }
170 }
171
172 MessageDecoderResult result = state.currentDecoder.decode(session, in,
173 out);
174 if (result == MessageDecoder.OK) {
175 state.currentDecoder = null;
176 return true;
177 } else if (result == MessageDecoder.NEED_DATA) {
178 return false;
179 } else if (result == MessageDecoder.NOT_OK) {
180 state.currentDecoder = null;
181 throw new ProtocolDecoderException(
182 "Message decoder returned NOT_OK.");
183 } else {
184 state.currentDecoder = null;
185 throw new IllegalStateException(
186 "Unexpected decode result (see your decode()): "
187 + result);
188 }
189 }
190
191 @Override
192 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
193 throws Exception {
194 super.finishDecode(session, out);
195 State state = getState(session);
196 MessageDecoder currentDecoder = state.currentDecoder;
197 if (currentDecoder == null) {
198 return;
199 }
200
201 currentDecoder.finishDecode(session, out);
202 }
203
204 @Override
205 public void dispose(IoSession session) throws Exception {
206 super.dispose(session);
207 session.removeAttribute(STATE);
208 }
209
210 private State getState(IoSession session) throws Exception {
211 State state = (State) session.getAttribute(STATE);
212 if (state == null) {
213 state = new State();
214 State oldState = (State) session.setAttributeIfAbsent(STATE, state);
215 if (oldState != null) {
216 state = oldState;
217 }
218 }
219 return state;
220 }
221
222 private class State {
223 private final MessageDecoder[] decoders;
224 private MessageDecoder currentDecoder;
225
226 private State() throws Exception {
227 MessageDecoderFactory[] decoderFactories = DemuxingProtocolDecoder.this.decoderFactories;
228 decoders = new MessageDecoder[decoderFactories.length];
229 for (int i = decoderFactories.length - 1; i >= 0; i--) {
230 decoders[i] = decoderFactories[i].getDecoder();
231 }
232 }
233 }
234
235 private static class SingletonMessageDecoderFactory implements
236 MessageDecoderFactory {
237 private final MessageDecoder decoder;
238
239 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
240 if (decoder == null) {
241 throw new NullPointerException("decoder");
242 }
243 this.decoder = decoder;
244 }
245
246 public MessageDecoder getDecoder() {
247 return decoder;
248 }
249 }
250
251 private static class DefaultConstructorMessageDecoderFactory implements
252 MessageDecoderFactory {
253 private final Class<?> decoderClass;
254
255 private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
256 if (decoderClass == null) {
257 throw new NullPointerException("decoderClass");
258 }
259
260 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
261 throw new IllegalArgumentException(
262 "decoderClass is not assignable to MessageDecoder");
263 }
264 this.decoderClass = decoderClass;
265 }
266
267 public MessageDecoder getDecoder() throws Exception {
268 return (MessageDecoder) decoderClass.newInstance();
269 }
270 }
271 }