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 protected boolean doDecode(IoSession session, ByteBuffer in,
246 ProtocolDecoderOutput out) throws Exception {
247 if (currentDecoder == null) {
248 MessageDecoder[] decoders = this.decoders;
249 int undecodables = 0;
250 for (int i = decoders.length - 1; i >= 0; i--) {
251 MessageDecoder decoder = decoders[i];
252 int limit = in.limit();
253 int pos = in.position();
254
255 MessageDecoderResult result;
256 try {
257 result = decoder.decodable(session, in);
258 } finally {
259 in.position(pos);
260 in.limit(limit);
261 }
262
263 if (result == MessageDecoder.OK) {
264 currentDecoder = decoder;
265 break;
266 } else if (result == MessageDecoder.NOT_OK) {
267 undecodables++;
268 } else if (result != MessageDecoder.NEED_DATA) {
269 throw new IllegalStateException(
270 "Unexpected decode result (see your decodable()): "
271 + result);
272 }
273 }
274
275 if (undecodables == decoders.length) {
276
277 String dump = in.getHexDump();
278 in.position(in.limit());
279 throw new ProtocolDecoderException(
280 "No appropriate message decoder: " + dump);
281 }
282
283 if (currentDecoder == null) {
284
285 return false;
286 }
287 }
288
289 MessageDecoderResult result = currentDecoder.decode(session, in,
290 out);
291 if (result == MessageDecoder.OK) {
292 currentDecoder = null;
293 return true;
294 } else if (result == MessageDecoder.NEED_DATA) {
295 return false;
296 } else if (result == MessageDecoder.NOT_OK) {
297 throw new ProtocolDecoderException(
298 "Message decoder returned NOT_OK.");
299 } else {
300 throw new IllegalStateException(
301 "Unexpected decode result (see your decode()): "
302 + result);
303 }
304 }
305
306 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
307 throws Exception {
308 if (currentDecoder == null) {
309 return;
310 }
311
312 currentDecoder.finishDecode(session, out);
313 }
314
315 public void dispose(IoSession session) throws Exception {
316 super.dispose(session);
317
318
319
320 }
321 }
322
323 private static class SingletonMessageEncoderFactory implements
324 MessageEncoderFactory {
325 private final MessageEncoder encoder;
326
327 private SingletonMessageEncoderFactory(MessageEncoder encoder) {
328 if (encoder == null) {
329 throw new NullPointerException("encoder");
330 }
331 this.encoder = encoder;
332 }
333
334 public MessageEncoder getEncoder() {
335 return encoder;
336 }
337 }
338
339 private static class SingletonMessageDecoderFactory implements
340 MessageDecoderFactory {
341 private final MessageDecoder decoder;
342
343 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
344 if (decoder == null) {
345 throw new NullPointerException("decoder");
346 }
347 this.decoder = decoder;
348 }
349
350 public MessageDecoder getDecoder() {
351 return decoder;
352 }
353 }
354
355 private static class DefaultConstructorMessageEncoderFactory implements
356 MessageEncoderFactory {
357 private final Class<?> encoderClass;
358
359 private DefaultConstructorMessageEncoderFactory(Class<?> encoderClass) {
360 if (encoderClass == null) {
361 throw new NullPointerException("encoderClass");
362 }
363
364 if (!MessageEncoder.class.isAssignableFrom(encoderClass)) {
365 throw new IllegalArgumentException(
366 "encoderClass is not assignable to MessageEncoder");
367 }
368 this.encoderClass = encoderClass;
369 }
370
371 public MessageEncoder getEncoder() throws Exception {
372 return (MessageEncoder) encoderClass.newInstance();
373 }
374 }
375
376 private static class DefaultConstructorMessageDecoderFactory implements
377 MessageDecoderFactory {
378 private final Class<?> decoderClass;
379
380 private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
381 if (decoderClass == null) {
382 throw new NullPointerException("decoderClass");
383 }
384
385 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
386 throw new IllegalArgumentException(
387 "decoderClass is not assignable to MessageDecoder");
388 }
389 this.decoderClass = decoderClass;
390 }
391
392 public MessageDecoder getDecoder() throws Exception {
393 return (MessageDecoder) decoderClass.newInstance();
394 }
395 }
396 }