📄 demuxingprotocolcodecfactory.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */package org.apache.mina.filter.codec.demux;import java.util.IdentityHashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;import org.apache.mina.common.ByteBuffer;import org.apache.mina.common.IoSession;import org.apache.mina.filter.codec.CumulativeProtocolDecoder;import org.apache.mina.filter.codec.ProtocolCodecFactory;import org.apache.mina.filter.codec.ProtocolDecoder;import org.apache.mina.filter.codec.ProtocolDecoderException;import org.apache.mina.filter.codec.ProtocolDecoderOutput;import org.apache.mina.filter.codec.ProtocolEncoder;import org.apache.mina.filter.codec.ProtocolEncoderException;import org.apache.mina.filter.codec.ProtocolEncoderOutput;import org.apache.mina.util.IdentityHashSet;/** * A composite {@link ProtocolCodecFactory} that consists of multiple * {@link MessageEncoder}s and {@link MessageDecoder}s. * {@link ProtocolEncoder} and {@link ProtocolDecoder} this factory * returns demultiplex incoming messages and buffers to * appropriate {@link MessageEncoder}s and {@link MessageDecoder}s. * * <h2>Disposing resources acquired by {@link MessageEncoder} and {@link MessageDecoder}</h2> * <p> * Make your {@link MessageEncoder} and {@link MessageDecoder} to put all * resources that need to be released as a session attribute. {@link #disposeCodecResources(IoSession)} * method will be invoked when a session is closed. Override {@link #disposeCodecResources(IoSession)} * to release the resources you've put as an attribute. * <p> * We didn't provide any <tt>dispose</tt> method for {@link MessageEncoder} and {@link MessageDecoder} * because they can give you a big performance penalty in case you have a lot of * message types to handle. * * @author The Apache Directory Project (mina-dev@directory.apache.org) * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13 7월 2007) $ * * @see MessageEncoder * @see MessageDecoder */public class DemuxingProtocolCodecFactory implements ProtocolCodecFactory { private MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0]; private MessageEncoderFactory[] encoderFactories = new MessageEncoderFactory[0]; private static final Class<?>[] EMPTY_PARAMS = new Class[0]; public DemuxingProtocolCodecFactory() { } public void register(Class<?> encoderOrDecoderClass) { if (encoderOrDecoderClass == null) { throw new NullPointerException("encoderOrDecoderClass"); } try { encoderOrDecoderClass.getConstructor(EMPTY_PARAMS); } catch (NoSuchMethodException e) { throw new IllegalArgumentException( "The specifiec class doesn't have a public default constructor."); } boolean registered = false; if (MessageEncoder.class.isAssignableFrom(encoderOrDecoderClass)) { register(new DefaultConstructorMessageEncoderFactory( encoderOrDecoderClass)); registered = true; } if (MessageDecoder.class.isAssignableFrom(encoderOrDecoderClass)) { register(new DefaultConstructorMessageDecoderFactory( encoderOrDecoderClass)); registered = true; } if (!registered) { throw new IllegalArgumentException("Unregisterable type: " + encoderOrDecoderClass); } } public void register(MessageEncoder encoder) { register(new SingletonMessageEncoderFactory(encoder)); } public void register(MessageEncoderFactory factory) { if (factory == null) { throw new NullPointerException("factory"); } MessageEncoderFactory[] encoderFactories = this.encoderFactories; MessageEncoderFactory[] newEncoderFactories = new MessageEncoderFactory[encoderFactories.length + 1]; System.arraycopy(encoderFactories, 0, newEncoderFactories, 0, encoderFactories.length); newEncoderFactories[encoderFactories.length] = factory; this.encoderFactories = newEncoderFactories; } public void register(MessageDecoder decoder) { register(new SingletonMessageDecoderFactory(decoder)); } public void register(MessageDecoderFactory factory) { if (factory == null) { throw new NullPointerException("factory"); } MessageDecoderFactory[] decoderFactories = this.decoderFactories; MessageDecoderFactory[] newDecoderFactories = new MessageDecoderFactory[decoderFactories.length + 1]; System.arraycopy(decoderFactories, 0, newDecoderFactories, 0, decoderFactories.length); newDecoderFactories[decoderFactories.length] = factory; this.decoderFactories = newDecoderFactories; } public ProtocolEncoder getEncoder() throws Exception { return new ProtocolEncoderImpl(); } public ProtocolDecoder getDecoder() throws Exception { return new ProtocolDecoderImpl(); } /** * Implement this method to release all resources acquired to perform * encoding and decoding messages for the specified <tt>session</tt>. * By default, this method does nothing. * * @param session the session that requires resource deallocation now */ protected void disposeCodecResources(IoSession session) { // Do nothing by default; let users implement it as they want. // This statement is just to avoid compiler warning. Please ignore. session.getTransportType(); } private class ProtocolEncoderImpl implements ProtocolEncoder { private final Map<Class<?>, MessageEncoder> encoders = new IdentityHashMap<Class<?>, MessageEncoder>(); private ProtocolEncoderImpl() throws Exception { MessageEncoderFactory[] encoderFactories = DemuxingProtocolCodecFactory.this.encoderFactories; for (int i = encoderFactories.length - 1; i >= 0; i--) { MessageEncoder encoder = encoderFactories[i].getEncoder(); Set<Class<?>> messageTypes = encoder.getMessageTypes(); if (messageTypes == null) { throw new IllegalStateException(encoder.getClass() .getName() + "#getMessageTypes() may not return null."); } Iterator<Class<?>> it = messageTypes.iterator(); while (it.hasNext()) { Class<?> type = it.next(); encoders.put(type, encoder); } } } public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception { Class<?> type = message.getClass(); MessageEncoder encoder = findEncoder(type); if (encoder == null) { throw new ProtocolEncoderException("Unexpected message type: " + type); } encoder.encode(session, message, out); } private MessageEncoder findEncoder(Class<?> type) { MessageEncoder encoder = encoders.get(type); if (encoder == null) { encoder = findEncoder(type, new IdentityHashSet<Class<?>>()); } return encoder; } private MessageEncoder findEncoder(Class<?> type, Set<Class<?>> triedClasses) { MessageEncoder encoder; if (triedClasses.contains(type)) return null; triedClasses.add(type); encoder = encoders.get(type); if (encoder == null) { encoder = findEncoder(type, triedClasses); if (encoder != null) return encoder; Class<?>[] interfaces = type.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { encoder = findEncoder(interfaces[i], triedClasses); if (encoder != null) return encoder; } return null; } else return encoder; } public void dispose(IoSession session) throws Exception { DemuxingProtocolCodecFactory.this.disposeCodecResources(session); } } private class ProtocolDecoderImpl extends CumulativeProtocolDecoder { private final MessageDecoder[] decoders; private MessageDecoder currentDecoder; protected ProtocolDecoderImpl() throws Exception { MessageDecoderFactory[] decoderFactories = DemuxingProtocolCodecFactory.this.decoderFactories; decoders = new MessageDecoder[decoderFactories.length]; for (int i = decoderFactories.length - 1; i >= 0; i--) { decoders[i] = decoderFactories[i].getDecoder(); } } protected boolean doDecode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception { if (currentDecoder == null) { MessageDecoder[] decoders = this.decoders; int undecodables = 0; for (int i = decoders.length - 1; i >= 0; i--) { MessageDecoder decoder = decoders[i]; int limit = in.limit(); int pos = in.position(); MessageDecoderResult result; try { result = decoder.decodable(session, in); } finally { in.position(pos); in.limit(limit); } if (result == MessageDecoder.OK) { currentDecoder = decoder; break; } else if (result == MessageDecoder.NOT_OK) { undecodables++; } else if (result != MessageDecoder.NEED_DATA) { throw new IllegalStateException( "Unexpected decode result (see your decodable()): " + result); } } if (undecodables == decoders.length) { // Throw an exception if all decoders cannot decode data. String dump = in.getHexDump(); in.position(in.limit()); // Skip data throw new ProtocolDecoderException( "No appropriate message decoder: " + dump); } if (currentDecoder == null) { // Decoder is not determined yet (i.e. we need more data) return false; } } MessageDecoderResult result = currentDecoder.decode(session, in, out); if (result == MessageDecoder.OK) { currentDecoder = null; return true; } else if (result == MessageDecoder.NEED_DATA) { return false; } else if (result == MessageDecoder.NOT_OK) { throw new ProtocolDecoderException( "Message decoder returned NOT_OK."); } else { throw new IllegalStateException( "Unexpected decode result (see your decode()): " + result); } } public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception { if (currentDecoder == null) { return; } currentDecoder.finishDecode(session, out); } public void dispose(IoSession session) throws Exception { super.dispose(session); // ProtocolEncoder.dispose() already called disposeCodec(), // so there's nothing more we need to do. } } private static class SingletonMessageEncoderFactory implements MessageEncoderFactory { private final MessageEncoder encoder; private SingletonMessageEncoderFactory(MessageEncoder encoder) { if (encoder == null) { throw new NullPointerException("encoder"); } this.encoder = encoder; } public MessageEncoder getEncoder() { return encoder; } } private static class SingletonMessageDecoderFactory implements MessageDecoderFactory { private final MessageDecoder decoder; private SingletonMessageDecoderFactory(MessageDecoder decoder) { if (decoder == null) { throw new NullPointerException("decoder"); } this.decoder = decoder; } public MessageDecoder getDecoder() { return decoder; } } private static class DefaultConstructorMessageEncoderFactory implements MessageEncoderFactory { private final Class<?> encoderClass; private DefaultConstructorMessageEncoderFactory(Class<?> encoderClass) { if (encoderClass == null) { throw new NullPointerException("encoderClass"); } if (!MessageEncoder.class.isAssignableFrom(encoderClass)) { throw new IllegalArgumentException( "encoderClass is not assignable to MessageEncoder"); } this.encoderClass = encoderClass; } public MessageEncoder getEncoder() throws Exception { return (MessageEncoder) encoderClass.newInstance(); } } private static class DefaultConstructorMessageDecoderFactory implements MessageDecoderFactory { private final Class<?> decoderClass; private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) { if (decoderClass == null) { throw new NullPointerException("decoderClass"); } if (!MessageDecoder.class.isAssignableFrom(decoderClass)) { throw new IllegalArgumentException( "decoderClass is not assignable to MessageDecoder"); } this.decoderClass = decoderClass; } public MessageDecoder getDecoder() throws Exception { return (MessageDecoder) decoderClass.newInstance(); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -