package com.opensource.netty.cmcc.decoder;
public interface DecodeResult<E>
{
enum Type
{
FINISHED, CONTINUE
}
Type getType();
}
package com.opensource.netty.cmcc.decoder;
public class ContinueDecodeResult<E> implements DecodeResult<E>
{
// internal vars ----------------------------------------------------------
private final E nextState;
// constructors -----------------------------------------------------------
public ContinueDecodeResult(E nextState)
{
this.nextState = nextState;
}
// DecodeResult -----------------------------------------------------------
@Override
public Type getType()
{
return Type.CONTINUE;
}
// getters & setters ------------------------------------------------------
public E getNextState()
{
return nextState;
}
}
package com.opensource.netty.cmcc.decoder;
public class FinishedDecodeResult<E> implements DecodeResult<E>
{
// internal vars ----------------------------------------------------------
private final Object result;
// constructors -----------------------------------------------------------
public FinishedDecodeResult(Object result)
{
this.result = result;
}
// DecodeResult -----------------------------------------------------------
@Override
public Type getType()
{
return Type.FINISHED;
}
// getters & setters ------------------------------------------------------
public Object getResult()
{
return result;
}
}
package com.opensource.netty.cmcc.decoder;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
public abstract class EnhancedReplayingDecoder<T extends Enum<T>> extends ReplayingDecoder<T>
{
// internal vars ----------------------------------------------------------
protected Channel channel;
private final T initialState;
// constructors -----------------------------------------------------------
public EnhancedReplayingDecoder(T initialState)
{
this(initialState, false);
}
public EnhancedReplayingDecoder(T initialState, boolean unfold)
{
super(initialState, unfold);
this.initialState = initialState;
}
// ReplayingDecoder -------------------------------------------------------
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, T state)
throws Exception
{
this.channel = channel;
for (;;)
{
// Request a decode with provided buffer and current state. It can
// only end in one of three ways:
// 1. There is still data missing (CONTINUE), so a checkpoint will
// be set and buffer draining will continue;
// 2. There was enough data to build a message (FINISHED), so reset
// the decoder and return the result;
// 3. There was insufficient data, in which case an exception will
// be thrown and handled by the ReplayingDecoder.
DecodeResult<T> result = this.decode(buffer, this.getState());
if (result == null)
{
throw new IllegalArgumentException("decode() returned null");
}
switch (result.getType())
{
case FINISHED:
// Final state, with composed object.
try
{
return ((FinishedDecodeResult<T>)result).getResult();
}
finally
{
this.reset();
}
case CONTINUE:
// Keep processing the message, setting a checkpoint to the
// next state.
this.checkpoint(((ContinueDecodeResult<T>)result).getNextState());
break;
default:
// Never actually falls here...
throw new IllegalArgumentException("Unsupported result: " + result.getType());
}
}
}
// protected helpers ------------------------------------------------------
protected DecodeResult<T> continueDecoding(T nextState)
{
return new ContinueDecodeResult<T>(nextState);
}
protected DecodeResult<T> finishedDecoding(Object result)
{
return new FinishedDecodeResult<T>(result);
}
protected void reset()
{
this.cleanup();
this.setState(this.initialState);
}
protected abstract DecodeResult<T> decode(ChannelBuffer buffer, T currentState)
throws Exception;
protected abstract void cleanup();
}