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 throw new ProtocolDecoderException(
279 "No appropriate message decoder: " + dump);
280 }
281
282 if (currentDecoder == null) {
283
284 return false;
285 }
286 }
287
288 MessageDecoderResult result = currentDecoder.decode(session, in,
289 out);
290 if (result == MessageDecoder.OK) {
291 currentDecoder = null;
292 return true;
293 } else if (result == MessageDecoder.NEED_DATA) {
294 return false;
295 } else if (result == MessageDecoder.NOT_OK) {
296 currentDecoder = null;
297 throw new ProtocolDecoderException(
298 "Message decoder returned NOT_OK.");
299 } else {
300 currentDecoder = null;
301 throw new IllegalStateException(
302 "Unexpected decode result (see your decode()): "
303 + result);
304 }
305 }
306
307 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
308 throws Exception {
309 if (currentDecoder == null) {
310 return;
311 }
312
313 currentDecoder.finishDecode(session, out);
314 }
315
316 public void dispose(IoSession session) throws Exception {
317 super.dispose(session);
318
319
320
321 }
322 }
323
324 private static class SingletonMessageEncoderFactory implements
325 MessageEncoderFactory {
326 private final MessageEncoder encoder;
327
328 private SingletonMessageEncoderFactory(MessageEncoder encoder) {
329 if (encoder == null) {
330 throw new NullPointerException("encoder");
331 }
332 this.encoder = encoder;
333 }
334
335 public MessageEncoder getEncoder() {
336 return encoder;
337 }
338 }
339
340 private static class SingletonMessageDecoderFactory implements
341 MessageDecoderFactory {
342 private final MessageDecoder decoder;
343
344 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
345 if (decoder == null) {
346 throw new NullPointerException("decoder");
347 }
348 this.decoder = decoder;
349 }
350
351 public MessageDecoder getDecoder() {
352 return decoder;
353 }
354 }
355
356 private static class DefaultConstructorMessageEncoderFactory implements
357 MessageEncoderFactory {
358 private final Class encoderClass;
359
360 private DefaultConstructorMessageEncoderFactory(Class encoderClass) {
361 if (encoderClass == null) {
362 throw new NullPointerException("encoderClass");
363 }
364
365 if (!MessageEncoder.class.isAssignableFrom(encoderClass)) {
366 throw new IllegalArgumentException(
367 "encoderClass is not assignable to MessageEncoder");
368 }
369 this.encoderClass = encoderClass;
370 }
371
372 public MessageEncoder getEncoder() throws Exception {
373 return (MessageEncoder) encoderClass.newInstance();
374 }
375 }
376
377 private static class DefaultConstructorMessageDecoderFactory implements
378 MessageDecoderFactory {
379 private final Class decoderClass;
380
381 private DefaultConstructorMessageDecoderFactory(Class decoderClass) {
382 if (decoderClass == null) {
383 throw new NullPointerException("decoderClass");
384 }
385
386 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
387 throw new IllegalArgumentException(
388 "decoderClass is not assignable to MessageDecoder");
389 }
390 this.decoderClass = decoderClass;
391 }
392
393 public MessageDecoder getDecoder() throws Exception {
394 return (MessageDecoder) decoderClass.newInstance();
395 }
396 }
397 }