package com.tacitknowledge.slowlight.proxyserver.handler;
import com.tacitknowledge.slowlight.proxyserver.config.HandlerConfig;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.lang.RandomStringUtils;
import java.util.concurrent.TimeUnit;
/**
* RandomDataChannelHandler class allows to generate random data as a response back to the client.
* For example this handler could be used if you want to simulate that server respond with some junk data of an arbitrary size.<br />
* <br />
* Handler parameters:<br />
* 1. <b>dataFragmentSize</b> - defines the size of data fragment that must be generated<br />
* 2. <b>dataFragments</b> - defines the number data fragments to be generated<br />
*
* @author Alexandr Donciu (adonciu@tacitknowledge.com)
*/
public class RandomDataChannelHandler extends AbstractChannelHandler
{
protected static final String PARAM_DATA_FRAGMENTS = "dataFragments";
protected static final String PARAM_DATA_FRAGMENT_SIZE = "dataFragmentSize";
public RandomDataChannelHandler(final HandlerConfig handlerConfig)
{
super(handlerConfig);
}
@Override
public void channelActive(final ChannelHandlerContext ctx) throws Exception
{
ctx.read();
}
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception
{
final int dataFragments = handlerParams.getInt(PARAM_DATA_FRAGMENTS);
final int dataFragmentSize = handlerParams.getInt(PARAM_DATA_FRAGMENT_SIZE);
ctx.executor().schedule(new GenerateRandomDataTask(ctx, dataFragments, dataFragmentSize), 0L, TimeUnit.MILLISECONDS);
}
@Override
protected void populateHandlerParams()
{
handlerParams.setProperty(PARAM_DATA_FRAGMENTS, handlerConfig.getParam(PARAM_DATA_FRAGMENTS));
handlerParams.setProperty(PARAM_DATA_FRAGMENT_SIZE, handlerConfig.getParam(PARAM_DATA_FRAGMENT_SIZE));
}
protected class GenerateRandomDataTask implements Runnable
{
private final int dataFragments;
private final int dataFragmentSize;
private int dataFragmentIndex;
private ChannelHandlerContext ctx;
private final GenerateRandomDataTask generateRandomDataTask;
protected GenerateRandomDataTask(final ChannelHandlerContext ctx, final int dataFragments, final int dataFragmentSize)
{
this.dataFragments = dataFragments;
this.dataFragmentSize = dataFragmentSize;
this.ctx = ctx;
this.generateRandomDataTask = this;
}
@Override
public void run()
{
final ByteBuf channelBuffer = Unpooled.wrappedBuffer(generateData());
ctx.channel().writeAndFlush(channelBuffer).addListener(new GenerateDataListener());
}
private byte[] generateData()
{
return RandomStringUtils.randomAlphanumeric(dataFragmentSize).getBytes();
}
/**
* Listener class to schedule next generate random data fragment task.
*/
protected class GenerateDataListener implements ChannelFutureListener
{
@Override
public void operationComplete(final ChannelFuture future) throws Exception
{
if (future.isSuccess())
{
if (dataFragmentIndex++ < dataFragments)
{
ctx.executor().schedule(generateRandomDataTask, 0, TimeUnit.MILLISECONDS);
}
else
{
ctx.channel().read();
}
}
else
{
future.channel().close();
}
}
}
}
}