1 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 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 151 protected void disposeCodecResources(IoSession session) { 152 154 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 String dump = in.getHexDump(); 278 in.position(in.limit()); throw new ProtocolDecoderException( 280 "No appropriate message decoder: " + dump); 281 } 282 283 if (currentDecoder == null) { 284 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 } 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 } 397 | Popular Tags |