MINA Multiplexing Protocol Codec Factory One (Multiplexing Protocol Encoder)

MINA Demultiplexing Decoder Example: http://donald-draper.iteye.com/blog/2375324
Mina Protocol Codec Filter One (Protocol Codec Factory, Protocol Encoder):
http://donald-draper.iteye .com/blog/2376663
Mina Protocol Codec Filter 2 (Protocol Decoder):
http://donald-draper.iteye.com/blog/2376679
Mina Queue: http://donald-draper.iteye.com/ blog/2376712
Mina protocol codec filter three (session write and message reception filtering):
http://donald-draper.iteye.com/blog/2376818
/**
 * 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.
 * The multiplexed protocol codec factory DemuxingProtocolCodecFactory contains multiple message encoders and decoders, this multiplexed codec factory,
 It can return the codec corresponding to the message or buffer, and demultiplex.
 * <h2>Disposing resources acquired by {@link MessageEncoder} and {@link MessageDecoder}</h2>
 * <p>The message codec needs to release the corresponding resources.
 * 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.
 * In the message codec, we do not provide a dispose method, because the dispose method may have an impact on performance in the case of encoding a large number of message types.
 * @author The Apache Directory Project ([email protected])
 * @version $Rev$, $Date$
 *
 * @see MessageEncoder
 * @see MessageDecoder
 */
public class DemuxingProtocolCodecFactory
    implements ProtocolCodecFactory
{
    private final DemuxingProtocolEncoder encoder = new DemuxingProtocolEncoder();//Multiplexed protocol encoder
    private final DemuxingProtocolDecoder decoder = new DemuxingProtocolDecoder();//Multiplexed protocol decoder
    public DemuxingProtocolCodecFactory()
    {
    }
    public ProtocolEncoder getEncoder(IoSession session)
        throws Exception
    {
        return encoder;
    }
    public ProtocolDecoder getDecoder(IoSession session)
        throws Exception
    {
        return decoder;
    }
    ...
}

From the above, the multiplexed protocol codec factory contains a multiplexed protocol encoder and decoder. Before going further, let's take a look at the multiplexed protocol encoders and decoders.
Let's first look at the multiplexed protocol encoder DemuxingProtocolEncoder:
public class DemuxingProtocolEncoder
    implements ProtocolEncoder
{
    private final AttributeKey STATE = new AttributeKey(getClass(), "state");
    //Mapping relationship between message type Class and encoder factory MessageEncoderFactory CopyOnWriteMap<Class, MessageEncoderFactory>
    private final Map type2encoderFactory = new CopyOnWriteMap();
    private static final Class EMPTY_PARAMS[] = new Class[0];
     public DemuxingProtocolEncoder()
    {
    }
}

Look at the multiplexed protocol encoder to add a message encoder operation:
//According to the message type and message encoder type, add a message encoder
public void addMessageEncoder(Class messageType, Class encoderClass)
    {
        if(encoderClass == null)
            throw new IllegalArgumentException("encoderClass");
        try
        {
            encoderClass.getConstructor(EMPTY_PARAMS);//Get the encoder no-parameter construction
        }
        catch(NoSuchMethodException e)
        {
            throw new IllegalArgumentException("The specified class doesn't have a public default constructor.");
        }
        boolean registered = false;
	//If the encoder is MessageEncoder, add message and message encoding factory mapping to message encoder Map mapping type2encoderFactory
        if(org/apache/mina/filter/codec/demux/MessageEncoder.isAssignableFrom(encoderClass))
        {
            addMessageEncoder(messageType, ((MessageEncoderFactory) (new DefaultConstructorMessageEncoderFactory(encoderClass))));
            registered = true;
        }
        if(!registered)
            throw new IllegalArgumentException((new StringBuilder()).append("Unregisterable type: ").append(encoderClass).toString());
        else
            return;
 }


Let's look at the mapping relationship between adding message types and message encoding factories
public void addMessageEncoder(Class messageType, MessageEncoderFactory factory)
    {
        if(messageType == null)
            throw new IllegalArgumentException("messageType");
        if(factory == null)
            throw new IllegalArgumentException("factory");
        synchronized(type2encoderFactory)
        {
	   //Add the mapping relationship between message type and message encoding factory to type2encoderFactory
            if(type2encoderFactory.containsKey(messageType))
                throw new IllegalStateException((new StringBuilder()).append("The specified message type (").append(messageType.getName()).append(") is registered already.").toString());
            type2encoderFactory.put(messageType, factory);
        }
    }

Look at the default constructor message encoding factory DefaultConstructorMessageEncoderFactory
private static class DefaultConstructorMessageEncoderFactory
        implements MessageEncoderFactory
    {
         private final Class encoderClass;//Message encoder class
	 private DefaultConstructorMessageEncoderFactory(Class encoderClass)
        {
            if(encoderClass == null)
                throw new IllegalArgumentException("encoderClass");
            if(!org/apache/mina/filter/codec/demux/MessageEncoder.isAssignableFrom(encoderClass))
            {
                throw new IllegalArgumentException("encoderClass is not assignable to MessageEncoder");
            } else
            {
                this.encoderClass = encoderClass;
                return;
            }
        }
	// produce message encoder
        public MessageEncoder getEncoder()
            throws Exception
        {
	   //Create a message encoder instance
            return (MessageEncoder)encoderClass.newInstance();
        }
}

As can be seen from the above, the multiplexed protocol encoder adds a message encoder. If the parameters are message type and message encoder type, add the message type and the default constructed message encoding factory
to the message encoder Map mapping type2encoderFactory.
Let's look at adding a message encoder based on the message type and message encoder instance
 
public void addMessageEncoder(Class messageType, MessageEncoder encoder)
    {
        //The encoder factory is a singleton message encoder factory
        addMessageEncoder(messageType, ((MessageEncoderFactory) (new SingletonMessageEncoderFactory(encoder))));
    }

//SingletonMessageEncoderFactory SingletonMessageEncoderFactory
private static class SingletonMessageEncoderFactory
        implements MessageEncoderFactory
    {
        private final MessageEncoder encoder;//Message encoder instance
        private SingletonMessageEncoderFactory(MessageEncoder encoder)
        {
            if(encoder == null)
            {
                throw new IllegalArgumentException("encoder");
            } else
            {
                this.encoder = encoder;
                return;
            }
        }
	//Get the singleton message decoder
        public MessageEncoder getEncoder()
        {
            return encoder;
        }
    }

As can be seen from the above, the multiplexed protocol encoder adds a message encoder. If the parameters are the message type and the message encoder instance, add the message type and the singleton message encoder factory
to the message encoder Map mapping type2encoderFactory.
The methods of the following message encoders are no different from the above two methods and are easy to understand
public void addMessageEncoder(Iterable messageTypes, Class encoderClass)
    {
        Class messageType;
        for(Iterator iterator = messageTypes.iterator(); iterator.hasNext(); addMessageEncoder(messageType, encoderClass))
            messageType = (Class)iterator.next();

    }
    public void addMessageEncoder(Iterable messageTypes, MessageEncoder encoder)
    {
        Class messageType;
        for(Iterator iterator = messageTypes.iterator(); iterator.hasNext(); addMessageEncoder(messageType, encoder))
            messageType = (Class)iterator.next();

    }
    public void addMessageEncoder(Iterable messageTypes, MessageEncoderFactory factory)
    {
        Class messageType;
        for(Iterator iterator = messageTypes.iterator(); iterator.hasNext(); addMessageEncoder(messageType, factory))
            messageType = (Class)iterator.next();
    }

Let's look at the message encoding again:
public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
        throws Exception
    {
        State state = getState(session);//Get session message encoder state
	//Get the encoder corresponding to the message
        MessageEncoder encoder = findEncoder(state, message.getClass());
        if(encoder != null)
	    //encode message
            encoder.encode(session, message, out);
        else
            throw new UnknownMessageTypeException((new StringBuilder()).append("No message encoder found for message: ").append(message).toString());
    }

There are two things to keep in mind about the encoded message method
1.
State state = getState(session);//Get session message encoder state

Let's first look at the definition of the session encoder state:
private class State
    {

        private final ConcurrentHashMap findEncoderCache;//Message encoder cache
        private final Map type2encoder;//Mapping relationship between message and message encoder
        final DemuxingProtocolEncoder this$0;
        private State()
            throws Exception
        {
            this$0 = DemuxingProtocolEncoder.this;
            super();
            findEncoderCache = new ConcurrentHashMap ();
            type2encoder = new ConcurrentHashMap();
            java.util.Map.Entry e;
	    // Traverse the message encoder Map of the multiplexed protocol encoder to map type2encoderFactory
	    //Add the message type and the factory-produced message encoder mapping to the session encoder state State message and message encoder mapping relationship type2encoder
            for(Iterator iterator = type2encoderFactory.entrySet().iterator(); iterator.hasNext(); type2encoder.put(e.getKey(), ((MessageEncoderFactory)e.getValue()).getEncoder()))
                e = (java.util.Map.Entry)iterator.next();

        }
    }

Let's look at getting the session encoder state:
private State getState(IoSession session)
        throws Exception
    {
        //Get the message encoder status from the session, if it is empty, add the message encoder status to the session, otherwise return the session encoder status
        State state = (State)session.getAttribute(STATE);
        if(state == null)
        {
            state = new State();
            State oldState = (State)session.setAttributeIfAbsent(STATE, state);
            if(oldState != null)
                state = oldState;
        }
        return state;
    }


2.
//Get the encoder corresponding to the message
MessageEncoder encoder = findEncoder(state, message.getClass());

//Get the encoder corresponding to the message type from the session message encoder state
protected MessageEncoder findEncoder(State state, Class type)
    {
        return findEncoder(state, type, null);
    }
    private MessageEncoder findEncoder(State state, Class type, Set triedClasses)
    {
        MessageEncoder encoder = null;
        if(triedClasses != null && triedClasses.contains(type))
            return null;
	//Get the message encoder from the session message encoder state cache
        encoder = (MessageEncoder)state.findEncoderCache.get(type);
	// not null, return
        if(encoder != null)
            return encoder;
	//Otherwise get the message encoder from the message encoder map Map of the session message encoder state
        encoder = (MessageEncoder)state.type2encoder.get(type);
        if(encoder == null)
        {
	    //If the encoder is empty, get the encoder corresponding to the secondary interface of the message type
            if(triedClasses == null)
                triedClasses = new IdentityHashSet();
            triedClasses.add(type);
            Class interfaces[] = type.getInterfaces();
            Class aclass[] = interfaces;
            int i = aclass.length;
            int j = 0;
            do
            {
                if(j >= i)
                    break;
                Class element = aclass[j];
                encoder = findEncoder(state, element, triedClasses);
                if(encoder != null)
                    break;
                j++;
            } while(true);
        }
        if(encoder == null)
        {
	   //Get the message encoder corresponding to the parent class of the message type
            Class superclass = type.getSuperclass();
            if(superclass != null)
                encoder = findEncoder(state, superclass);
        }
        if(encoder != null)
        {
	   //Not empty, add the message encoder to the session message encoder state findEncoderCache
            state.findEncoderCache.put(type, encoder);
            MessageEncoder tmpEncoder = (MessageEncoder)state.findEncoderCache.putIfAbsent(type, encoder);
            if(tmpEncoder != null)
                encoder = tmpEncoder;
        }
        return encoder;
    }

As can be seen from the above, the multiplexed protocol encoder encodes the message, first obtains the message encoder state from the session, and obtains the encoder corresponding to the message from the message encoder state (first search from the message encoder, if not, from the message encoding If there is no decoding corresponding to the message, look up the encoder corresponding to the parent interface and class of the message, and encode the message.

// release the session encoder state
public void dispose(IoSession session)
        throws Exception
    {
        session.removeAttribute(STATE);
    }

Let's come back to the definition of the message encoder:
//Message encoder factory MessageEncoderFactory
public interface MessageEncoderFactory
{
    public abstract MessageEncoder getEncoder()
        throws Exception;
}

//MessageEncoder
public interface MessageEncoder
{
    public abstract void encode(IoSession iosession, Object obj, ProtocolEncoderOutput protocolencoderoutput)
        throws Exception;
}

The multiplexed protocol decoder DemuxingProtocolDecoder, we will look at it in the next article.
Summary:
The multiplexed protocol encoder adds a message encoder. If the parameters are message type and message encoder type, add the message type and the default constructed message encoding factory to the message encoder Map mapping type2encoderFactory; if the parameters are message type and message Encoder instance, add message type and singleton message encoder factory to message encoder Map mapping type2encoderFactory. The multiplexed protocol encoder encodes the message, first obtains the message encoder state from the session, and obtains the encoder corresponding to the message from the message encoder state (first look up from the message encoder, if not, look up from the message encoder mapping type2encoder), If there is no decoding corresponding to the message, look up the encoder corresponding to the parent interface and class of the message, and encode the message.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326430391&siteId=291194637