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<Class<?>, MessageEncoder> encoders = new IdentityHashMap<Class<?>, MessageEncoder>();
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<Class<?>> 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<Class<?>> it = messageTypes.iterator();
173 while (it.hasNext()) {
174 Class<?> type = 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 = encoders.get(type);
194 if (encoder == null) {
195 encoder = findEncoder(type, new IdentityHashSet<Class<?>>());
196 }
197
198 return encoder;
199 }
200
201 private MessageEncoder findEncoder(Class<?> type,
202 Set<Class<?>> triedClasses) {
203 MessageEncoder encoder;
204
205 if (triedClasses.contains(type))
206 return null;
207 triedClasses.add(type);
208
209 encoder = encoders.get(type);
210 if (encoder == null) {
211 encoder = findEncoder(type, triedClasses);
212 if (encoder != null)
213 return encoder;
214
215 Class<?>[] interfaces = type.getInterfaces();
216 for (int i = 0; i < interfaces.length; i++) {
217 encoder = findEncoder(interfaces[i], triedClasses);
218 if (encoder != null)
219 return encoder;
220 }
221
222 return null;
223 } else
224 return encoder;
225 }
226
227 public void dispose(IoSession session) throws Exception {
228 DemuxingProtocolCodecFactory.this.disposeCodecResources(session);
229 }
230 }
231
232 private class ProtocolDecoderImpl extends CumulativeProtocolDecoder {
233 private final MessageDecoder[] decoders;
234
235 private MessageDecoder currentDecoder;
236
237 protected ProtocolDecoderImpl() throws Exception {
238 MessageDecoderFactory[] decoderFactories = DemuxingProtocolCodecFactory.this.decoderFactories;
239 decoders = new MessageDecoder[decoderFactories.length];
240 for (int i = decoderFactories.length - 1; i >= 0; i--) {
241 decoders[i] = decoderFactories[i].getDecoder();
242 }
243 }
244
245 @Override
246 protected boolean doDecode(IoSession session, ByteBuffer in,
247 ProtocolDecoderOutput out) throws Exception {
248 if (currentDecoder == null) {
249 MessageDecoder[] decoders = this.decoders;
250 int undecodables = 0;
251 for (int i = decoders.length - 1; i >= 0; i--) {
252 MessageDecoder decoder = decoders[i];
253 int limit = in.limit();
254 int pos = in.position();
255
256 MessageDecoderResult result;
257 try {
258 result = decoder.decodable(session, in);
259 } finally {
260 in.position(pos);
261 in.limit(limit);
262 }
263
264 if (result == MessageDecoder.OK) {
265 currentDecoder = decoder;
266 break;
267 } else if (result == MessageDecoder.NOT_OK) {
268 undecodables++;
269 } else if (result != MessageDecoder.NEED_DATA) {
270 throw new IllegalStateException(
271 "Unexpected decode result (see your decodable()): "
272 + result);
273 }
274 }
275
276 if (undecodables == decoders.length) {
277
278 String dump = in.getHexDump();
279 in.position(in.limit());
280 ProtocolDecoderException e = new ProtocolDecoderException(
281 "No appropriate message decoder: " + dump);
282 e.setHexdump(dump);
283 throw e;
284 }
285
286 if (currentDecoder == null) {
287
288 return false;
289 }
290 }
291
292 MessageDecoderResult result = currentDecoder.decode(session, in,
293 out);
294 if (result == MessageDecoder.OK) {
295 currentDecoder = null;
296 return true;
297 } else if (result == MessageDecoder.NEED_DATA) {
298 return false;
299 } else if (result == MessageDecoder.NOT_OK) {
300 currentDecoder = null;
301 throw new ProtocolDecoderException(
302 "Message decoder returned NOT_OK.");
303 } else {
304 currentDecoder = null;
305 throw new IllegalStateException(
306 "Unexpected decode result (see your decode()): "
307 + result);
308 }
309 }
310
311 @Override
312 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
313 throws Exception {
314 if (currentDecoder == null) {
315 return;
316 }
317
318 currentDecoder.finishDecode(session, out);
319 }
320
321 @Override
322 public void dispose(IoSession session) throws Exception {
323 super.dispose(session);
324
325
326
327 }
328 }
329
330 private static class SingletonMessageEncoderFactory implements
331 MessageEncoderFactory {
332 private final MessageEncoder encoder;
333
334 private SingletonMessageEncoderFactory(MessageEncoder encoder) {
335 if (encoder == null) {
336 throw new NullPointerException("encoder");
337 }
338 this.encoder = encoder;
339 }
340
341 public MessageEncoder getEncoder() {
342 return encoder;
343 }
344 }
345
346 private static class SingletonMessageDecoderFactory implements
347 MessageDecoderFactory {
348 private final MessageDecoder decoder;
349
350 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
351 if (decoder == null) {
352 throw new NullPointerException("decoder");
353 }
354 this.decoder = decoder;
355 }
356
357 public MessageDecoder getDecoder() {
358 return decoder;
359 }
360 }
361
362 private static class DefaultConstructorMessageEncoderFactory implements
363 MessageEncoderFactory {
364 private final Class<?> encoderClass;
365
366 private DefaultConstructorMessageEncoderFactory(Class<?> encoderClass) {
367 if (encoderClass == null) {
368 throw new NullPointerException("encoderClass");
369 }
370
371 if (!MessageEncoder.class.isAssignableFrom(encoderClass)) {
372 throw new IllegalArgumentException(
373 "encoderClass is not assignable to MessageEncoder");
374 }
375 this.encoderClass = encoderClass;
376 }
377
378 public MessageEncoder getEncoder() throws Exception {
379 return (MessageEncoder) encoderClass.newInstance();
380 }
381 }
382
383 private static class DefaultConstructorMessageDecoderFactory implements
384 MessageDecoderFactory {
385 private final Class<?> decoderClass;
386
387 private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
388 if (decoderClass == null) {
389 throw new NullPointerException("decoderClass");
390 }
391
392 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
393 throw new IllegalArgumentException(
394 "decoderClass is not assignable to MessageDecoder");
395 }
396 this.decoderClass = decoderClass;
397 }
398
399 public MessageDecoder getDecoder() throws Exception {
400 return (MessageDecoder) decoderClass.newInstance();
401 }
402 }
403 }