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