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 java.util.IdentityHashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.apache.mina.common.ByteBuffer;
28 import org.apache.mina.common.IoSession;
29 import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
30 import org.apache.mina.filter.codec.ProtocolCodecFactory;
31 import org.apache.mina.filter.codec.ProtocolDecoder;
32 import org.apache.mina.filter.codec.ProtocolDecoderException;
33 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
34 import org.apache.mina.filter.codec.ProtocolEncoder;
35 import org.apache.mina.filter.codec.ProtocolEncoderException;
36 import org.apache.mina.filter.codec.ProtocolEncoderOutput;
37 import org.apache.mina.util.IdentityHashSet;
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 public class DemuxingProtocolCodecFactory implements ProtocolCodecFactory {
64 private MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0];
65
66 private MessageEncoderFactory[] encoderFactories = new MessageEncoderFactory[0];
67
68 private static final Class[] EMPTY_PARAMS = new Class[0];
69
70 public DemuxingProtocolCodecFactory() {
71 }
72
73 public void register(Class encoderOrDecoderClass) {
74 if (encoderOrDecoderClass == null) {
75 throw new NullPointerException("encoderOrDecoderClass");
76 }
77
78 try {
79 encoderOrDecoderClass.getConstructor(EMPTY_PARAMS);
80 } catch (NoSuchMethodException e) {
81 throw new IllegalArgumentException(
82 "The specifiec class doesn't have a public default constructor.");
83 }
84
85 boolean registered = false;
86 if (MessageEncoder.class.isAssignableFrom(encoderOrDecoderClass)) {
87 register(new DefaultConstructorMessageEncoderFactory(
88 encoderOrDecoderClass));
89 registered = true;
90 }
91
92 if (MessageDecoder.class.isAssignableFrom(encoderOrDecoderClass)) {
93 register(new DefaultConstructorMessageDecoderFactory(
94 encoderOrDecoderClass));
95 registered = true;
96 }
97
98 if (!registered) {
99 throw new IllegalArgumentException("Unregisterable type: "
100 + encoderOrDecoderClass);
101 }
102 }
103
104 public void register(MessageEncoder encoder) {
105 register(new SingletonMessageEncoderFactory(encoder));
106 }
107
108 public void register(MessageEncoderFactory factory) {
109 if (factory == null) {
110 throw new NullPointerException("factory");
111 }
112 MessageEncoderFactory[] encoderFactories = this.encoderFactories;
113 MessageEncoderFactory[] newEncoderFactories = new MessageEncoderFactory[encoderFactories.length + 1];
114 System.arraycopy(encoderFactories, 0, newEncoderFactories, 0,
115 encoderFactories.length);
116 newEncoderFactories[encoderFactories.length] = factory;
117 this.encoderFactories = newEncoderFactories;
118 }
119
120 public void register(MessageDecoder decoder) {
121 register(new SingletonMessageDecoderFactory(decoder));
122 }
123
124 public void register(MessageDecoderFactory factory) {
125 if (factory == null) {
126 throw new NullPointerException("factory");
127 }
128 MessageDecoderFactory[] decoderFactories = this.decoderFactories;
129 MessageDecoderFactory[] newDecoderFactories = new MessageDecoderFactory[decoderFactories.length + 1];
130 System.arraycopy(decoderFactories, 0, newDecoderFactories, 0,
131 decoderFactories.length);
132 newDecoderFactories[decoderFactories.length] = factory;
133 this.decoderFactories = newDecoderFactories;
134 }
135
136 public ProtocolEncoder getEncoder() throws Exception {
137 return new ProtocolEncoderImpl();
138 }
139
140 public ProtocolDecoder getDecoder() throws Exception {
141 return new ProtocolDecoderImpl();
142 }
143
144
145
146
147
148
149
150
151 protected void disposeCodecResources(IoSession session) {
152
153
154
155 session.getTransportType();
156 }
157
158 private class ProtocolEncoderImpl implements ProtocolEncoder {
159 private final Map encoders = new IdentityHashMap();
160
161 private ProtocolEncoderImpl() throws Exception {
162 MessageEncoderFactory[] encoderFactories = DemuxingProtocolCodecFactory.this.encoderFactories;
163 for (int i = encoderFactories.length - 1; i >= 0; i--) {
164 MessageEncoder encoder = encoderFactories[i].getEncoder();
165 Set messageTypes = encoder.getMessageTypes();
166 if (messageTypes == null) {
167 throw new IllegalStateException(encoder.getClass()
168 .getName()
169 + "#getMessageTypes() may not return null.");
170 }
171
172 Iterator it = messageTypes.iterator();
173 while (it.hasNext()) {
174 Class type = (Class) it.next();
175 encoders.put(type, encoder);
176 }
177 }
178 }
179
180 public void encode(IoSession session, Object message,
181 ProtocolEncoderOutput out) throws Exception {
182 Class type = message.getClass();
183 MessageEncoder encoder = findEncoder(type);
184 if (encoder == null) {
185 throw new ProtocolEncoderException("Unexpected message type: "
186 + type);
187 }
188
189 encoder.encode(session, message, out);
190 }
191
192 private MessageEncoder findEncoder(Class type) {
193 MessageEncoder encoder = (MessageEncoder) encoders.get(type);
194 if (encoder == null) {
195 encoder = findEncoder(type, new IdentityHashSet());
196 }
197
198 return encoder;
199 }
200
201 private MessageEncoder findEncoder(Class type, Set triedClasses) {
202 MessageEncoder encoder;
203
204 if (triedClasses.contains(type))
205 return null;
206 triedClasses.add(type);
207
208 encoder = (MessageEncoder) encoders.get(type);
209 if (encoder == null) {
210 encoder = findEncoder(type, triedClasses);
211 if (encoder != null)
212 return encoder;
213
214 Class[] interfaces = type.getInterfaces();
215 for (int i = 0; i < interfaces.length; i++) {
216 encoder = findEncoder(interfaces[i], triedClasses);
217 if (encoder != null)
218 return encoder;
219 }
220
221 return null;
222 } else
223 return encoder;
224 }
225
226 public void dispose(IoSession session) throws Exception {
227 DemuxingProtocolCodecFactory.this.disposeCodecResources(session);
228 }
229 }
230
231 private class ProtocolDecoderImpl extends CumulativeProtocolDecoder {
232 private final MessageDecoder[] decoders;
233
234 private MessageDecoder currentDecoder;
235
236 protected ProtocolDecoderImpl() throws Exception {
237 MessageDecoderFactory[] decoderFactories = DemuxingProtocolCodecFactory.this.decoderFactories;
238 decoders = new MessageDecoder[decoderFactories.length];
239 for (int i = decoderFactories.length - 1; i >= 0; i--) {
240 decoders[i] = decoderFactories[i].getDecoder();
241 }
242 }
243
244 protected boolean doDecode(IoSession session, ByteBuffer in,
245 ProtocolDecoderOutput out) throws Exception {
246 if (currentDecoder == null) {
247 MessageDecoder[] decoders = this.decoders;
248 int undecodables = 0;
249 for (int i = decoders.length - 1; i >= 0; i--) {
250 MessageDecoder decoder = decoders[i];
251 int limit = in.limit();
252 int pos = in.position();
253
254 MessageDecoderResult result;
255 try {
256 result = decoder.decodable(session, in);
257 } finally {
258 in.position(pos);
259 in.limit(limit);
260 }
261
262 if (result == MessageDecoder.OK) {
263 currentDecoder = decoder;
264 break;
265 } else if (result == MessageDecoder.NOT_OK) {
266 undecodables++;
267 } else if (result != MessageDecoder.NEED_DATA) {
268 throw new IllegalStateException(
269 "Unexpected decode result (see your decodable()): "
270 + result);
271 }
272 }
273
274 if (undecodables == decoders.length) {
275
276 String dump = in.getHexDump();
277 in.position(in.limit());
278 ProtocolDecoderException e = new ProtocolDecoderException(
279 "No appropriate message decoder: " + dump);
280 e.setHexdump(dump);
281 throw e;
282 }
283
284 if (currentDecoder == null) {
285
286 return false;
287 }
288 }
289
290 MessageDecoderResult result = currentDecoder.decode(session, in,
291 out);
292 if (result == MessageDecoder.OK) {
293 currentDecoder = null;
294 return true;
295 } else if (result == MessageDecoder.NEED_DATA) {
296 return false;
297 } else if (result == MessageDecoder.NOT_OK) {
298 currentDecoder = null;
299 throw new ProtocolDecoderException(
300 "Message decoder returned NOT_OK.");
301 } else {
302 currentDecoder = null;
303 throw new IllegalStateException(
304 "Unexpected decode result (see your decode()): "
305 + result);
306 }
307 }
308
309 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
310 throws Exception {
311 if (currentDecoder == null) {
312 return;
313 }
314
315 currentDecoder.finishDecode(session, out);
316 }
317
318 public void dispose(IoSession session) throws Exception {
319 super.dispose(session);
320
321
322
323 }
324 }
325
326 private static class SingletonMessageEncoderFactory implements
327 MessageEncoderFactory {
328 private final MessageEncoder encoder;
329
330 private SingletonMessageEncoderFactory(MessageEncoder encoder) {
331 if (encoder == null) {
332 throw new NullPointerException("encoder");
333 }
334 this.encoder = encoder;
335 }
336
337 public MessageEncoder getEncoder() {
338 return encoder;
339 }
340 }
341
342 private static class SingletonMessageDecoderFactory implements
343 MessageDecoderFactory {
344 private final MessageDecoder decoder;
345
346 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
347 if (decoder == null) {
348 throw new NullPointerException("decoder");
349 }
350 this.decoder = decoder;
351 }
352
353 public MessageDecoder getDecoder() {
354 return decoder;
355 }
356 }
357
358 private static class DefaultConstructorMessageEncoderFactory implements
359 MessageEncoderFactory {
360 private final Class encoderClass;
361
362 private DefaultConstructorMessageEncoderFactory(Class encoderClass) {
363 if (encoderClass == null) {
364 throw new NullPointerException("encoderClass");
365 }
366
367 if (!MessageEncoder.class.isAssignableFrom(encoderClass)) {
368 throw new IllegalArgumentException(
369 "encoderClass is not assignable to MessageEncoder");
370 }
371 this.encoderClass = encoderClass;
372 }
373
374 public MessageEncoder getEncoder() throws Exception {
375 return (MessageEncoder) encoderClass.newInstance();
376 }
377 }
378
379 private static class DefaultConstructorMessageDecoderFactory implements
380 MessageDecoderFactory {
381 private final Class decoderClass;
382
383 private DefaultConstructorMessageDecoderFactory(Class decoderClass) {
384 if (decoderClass == null) {
385 throw new NullPointerException("decoderClass");
386 }
387
388 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
389 throw new IllegalArgumentException(
390 "decoderClass is not assignable to MessageDecoder");
391 }
392 this.decoderClass = decoderClass;
393 }
394
395 public MessageDecoder getDecoder() throws Exception {
396 return (MessageDecoder) decoderClass.newInstance();
397 }
398 }
399 }