1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.mina.protocol.codec;
20
21 import java.util.HashSet;
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.protocol.ProtocolCodecFactory;
29 import org.apache.mina.protocol.ProtocolDecoder;
30 import org.apache.mina.protocol.ProtocolDecoderOutput;
31 import org.apache.mina.protocol.ProtocolEncoder;
32 import org.apache.mina.protocol.ProtocolEncoderOutput;
33 import org.apache.mina.protocol.ProtocolSession;
34 import org.apache.mina.protocol.ProtocolViolationException;
35
36 /***
37 * A composite {@link ProtocolCodecFactory} that consists of multiple
38 * {@link MessageEncoder}s and {@link MessageDecoder}s.
39 * {@link ProtocolEncoder} and {@link ProtocolDecoder} this factory
40 * returns demultiplex incoming messages and buffers to
41 * appropriate {@link MessageEncoder}s and {@link MessageDecoder}s.
42 *
43 * @author The Apache Directory Project (dev@directory.apache.org)
44 * @author Trustin Lee (trustin@apache.org)
45 * @version $Rev: 210062 $, $Date: 2005-07-11 12:52:38 +0900 $
46 *
47 * @see MessageEncoder
48 * @see MessageDecoder
49 */
50 public class DemuxingProtocolCodecFactory implements ProtocolCodecFactory {
51
52 private MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0];
53 private MessageEncoderFactory[] encoderFactories = new MessageEncoderFactory[0];
54
55 public DemuxingProtocolCodecFactory()
56 {
57 }
58
59 public void register( Class encoderOrDecoderClass )
60 {
61 if( encoderOrDecoderClass == null )
62 {
63 throw new NullPointerException( "encoderOrDecoderClass" );
64 }
65
66 boolean registered = false;
67 if( MessageEncoder.class.isAssignableFrom( encoderOrDecoderClass ) )
68 {
69 register( new DefaultConstructorMessageEncoderFactory( encoderOrDecoderClass ) );
70 registered = true;
71 }
72
73 if( MessageDecoder.class.isAssignableFrom( encoderOrDecoderClass ) )
74 {
75 register( new DefaultConstructorMessageDecoderFactory( encoderOrDecoderClass ) );
76 registered = true;
77 }
78
79 if( !registered )
80 {
81 throw new IllegalArgumentException( "Unregisterable type: " + encoderOrDecoderClass );
82 }
83 }
84
85 public void register( MessageEncoder encoder )
86 {
87 register( new SingletonMessageEncoderFactory( encoder ) );
88 }
89
90 public void register( MessageEncoderFactory factory )
91 {
92 if( factory == null )
93 {
94 throw new NullPointerException( "factory" );
95 }
96 MessageEncoderFactory[] encoderFactories = this.encoderFactories;
97 MessageEncoderFactory[] newEncoderFactories = new MessageEncoderFactory[ encoderFactories.length + 1 ];
98 System.arraycopy( encoderFactories, 0, newEncoderFactories, 0, encoderFactories.length );
99 newEncoderFactories[ encoderFactories.length ] = factory;
100 this.encoderFactories = newEncoderFactories;
101 }
102
103 public void register( MessageDecoder decoder )
104 {
105 register( new SingletonMessageDecoderFactory( decoder ) );
106 }
107
108 public void register( MessageDecoderFactory factory )
109 {
110 if( factory == null )
111 {
112 throw new NullPointerException( "factory" );
113 }
114 MessageDecoderFactory[] decoderFactories = this.decoderFactories;
115 MessageDecoderFactory[] newDecoderFactories = new MessageDecoderFactory[ decoderFactories.length + 1 ];
116 System.arraycopy( decoderFactories, 0, newDecoderFactories, 0, decoderFactories.length );
117 newDecoderFactories[ decoderFactories.length ] = factory;
118 this.decoderFactories = newDecoderFactories;
119 }
120
121 public ProtocolEncoder newEncoder() {
122 return new ProtocolEncoderImpl();
123 }
124
125 public ProtocolDecoder newDecoder() {
126 return new ProtocolDecoderImpl();
127 }
128
129 private class ProtocolEncoderImpl implements ProtocolEncoder
130 {
131 private final Map encoders = new IdentityHashMap();
132
133 private ProtocolEncoderImpl()
134 {
135 MessageEncoderFactory[] encoderFactories = DemuxingProtocolCodecFactory.this.encoderFactories;
136 for( int i = encoderFactories.length - 1; i >= 0; i-- )
137 {
138 MessageEncoder encoder = encoderFactories[ i ].newEncoder();
139 Iterator it = encoder.getMessageTypes().iterator();
140 while( it.hasNext() )
141 {
142 Class type = ( Class ) it.next();
143 encoders.put( type, encoder );
144 }
145 }
146 }
147
148 public void encode( ProtocolSession session, Object message,
149 ProtocolEncoderOutput out ) throws ProtocolViolationException
150 {
151 Class type = message.getClass();
152 MessageEncoder encoder = findEncoder( type );
153 if( encoder == null )
154 {
155 throw new ProtocolViolationException( "Unexpected message type: " + type );
156 }
157
158 encoder.encode( session, message, out );
159 }
160
161 private MessageEncoder findEncoder( Class type )
162 {
163 MessageEncoder encoder = ( MessageEncoder ) encoders.get( type );
164 if( encoder == null )
165 {
166 encoder = findEncoder( type, new HashSet() );
167 }
168
169 return encoder;
170 }
171
172 private MessageEncoder findEncoder( Class type, Set triedClasses )
173 {
174 MessageEncoder encoder;
175
176 if( triedClasses.contains( type ) )
177 return null;
178 triedClasses.add( type );
179
180 encoder = ( MessageEncoder ) encoders.get( type );
181 if( encoder == null )
182 {
183 encoder = findEncoder( type, triedClasses );
184 if( encoder != null )
185 return encoder;
186
187 Class[] interfaces = type.getInterfaces();
188 for( int i = 0; i < interfaces.length; i ++ )
189 {
190 encoder = findEncoder( interfaces[ i ], triedClasses );
191 if( encoder != null )
192 return encoder;
193 }
194
195 return null;
196 }
197 else
198 return encoder;
199 }
200 }
201
202 private class ProtocolDecoderImpl extends CumulativeProtocolDecoder
203 {
204 private final MessageDecoder[] decoders;
205 private MessageDecoder currentDecoder;
206
207 protected ProtocolDecoderImpl()
208 {
209 super( 16 );
210
211 MessageDecoderFactory[] decoderFactories = DemuxingProtocolCodecFactory.this.decoderFactories;
212 decoders = new MessageDecoder[ decoderFactories.length ];
213 for( int i = decoderFactories.length - 1; i >= 0; i-- )
214 {
215 decoders[ i ] = decoderFactories[ i ].newDecoder();
216 }
217 }
218
219 protected boolean doDecode( ProtocolSession session, ByteBuffer in,
220 ProtocolDecoderOutput out) throws ProtocolViolationException
221 {
222 if( currentDecoder == null )
223 {
224 MessageDecoder[] decoders = this.decoders;
225 int undecodables = 0;
226 for( int i = decoders.length - 1; i >= 0; i -- )
227 {
228 MessageDecoder decoder = decoders[i];
229 int limit = in.limit();
230 int pos = in.position();
231
232 MessageDecoderResult result;
233 try
234 {
235 result = decoder.decodable( session, in );
236 }
237 finally
238 {
239 in.position( pos );
240 in.limit( limit );
241 }
242
243 if( result == MessageDecoder.OK )
244 {
245 currentDecoder = decoder;
246 break;
247 }
248 else if( result == MessageDecoder.NOT_OK )
249 {
250 undecodables ++;
251 }
252 else if( result != MessageDecoder.NEED_DATA )
253 {
254 throw new IllegalStateException( "Unexpected decode result (see your decodable()): " + result );
255 }
256 }
257
258 if( undecodables == decoders.length )
259 {
260
261 in.position( in.limit() );
262 throw new ProtocolViolationException(
263 "No appropriate message decoder: " + in.getHexDump() );
264 }
265
266 if( currentDecoder == null )
267 {
268
269 return false;
270 }
271 }
272
273 MessageDecoderResult result = currentDecoder.decode( session, in, out );
274 if( result == MessageDecoder.OK )
275 {
276 currentDecoder = null;
277 return true;
278 }
279 else if( result == MessageDecoder.NEED_DATA )
280 {
281 return false;
282 }
283 else if( result == MessageDecoder.NOT_OK )
284 {
285 throw new ProtocolViolationException( "Message decoder returned NOT_OK." );
286 }
287 else
288 {
289 throw new IllegalStateException( "Unexpected decode result (see your decode()): " + result );
290 }
291 }
292 }
293
294 private static class SingletonMessageEncoderFactory implements MessageEncoderFactory
295 {
296 private final MessageEncoder encoder;
297
298 private SingletonMessageEncoderFactory( MessageEncoder encoder )
299 {
300 if( encoder == null )
301 {
302 throw new NullPointerException( "encoder" );
303 }
304 this.encoder = encoder;
305 }
306
307 public MessageEncoder newEncoder()
308 {
309 return encoder;
310 }
311 }
312
313 private static class SingletonMessageDecoderFactory implements MessageDecoderFactory
314 {
315 private final MessageDecoder decoder;
316
317 private SingletonMessageDecoderFactory( MessageDecoder decoder )
318 {
319 if( decoder == null )
320 {
321 throw new NullPointerException( "decoder" );
322 }
323 this.decoder = decoder;
324 }
325
326 public MessageDecoder newDecoder()
327 {
328 return decoder;
329 }
330 }
331
332 private static class DefaultConstructorMessageEncoderFactory implements MessageEncoderFactory
333 {
334 private final Class encoderClass;
335
336 private DefaultConstructorMessageEncoderFactory( Class encoderClass )
337 {
338 if( encoderClass == null )
339 {
340 throw new NullPointerException( "encoderClass" );
341 }
342
343 if( !MessageEncoder.class.isAssignableFrom( encoderClass ) )
344 {
345 throw new IllegalArgumentException( "encoderClass is not assignable to MessageEncoder" );
346 }
347 this.encoderClass = encoderClass;
348 }
349
350 public MessageEncoder newEncoder()
351 {
352 try
353 {
354 return ( MessageEncoder ) encoderClass.newInstance();
355 }
356 catch( Exception e )
357 {
358 throw new RuntimeException( "Failed to create a new instance of " + encoderClass, e );
359 }
360 }
361 }
362
363 private static class DefaultConstructorMessageDecoderFactory implements MessageDecoderFactory
364 {
365 private final Class decoderClass;
366
367 private DefaultConstructorMessageDecoderFactory( Class decoderClass )
368 {
369 if( decoderClass == null )
370 {
371 throw new NullPointerException( "decoderClass" );
372 }
373
374 if( !MessageDecoder.class.isAssignableFrom( decoderClass ) )
375 {
376 throw new IllegalArgumentException( "decoderClass is not assignable to MessageDecoder" );
377 }
378 this.decoderClass = decoderClass;
379 }
380
381 public MessageDecoder newDecoder()
382 {
383 try
384 {
385 return ( MessageDecoder ) decoderClass.newInstance();
386 }
387 catch( Exception e )
388 {
389 throw new RuntimeException( "Failed to create a new instance of " + decoderClass, e );
390 }
391 }
392 }
393 }