There is insufficient information for AsyncWeb (subproject of Mina) on internet,
what I need is simulating a web services that reply in various seconds for load testing.
the following code may not be correct, some wiered debug message…
and I just depressed it by log4j.properties
Mostly follow the lightweight example of AsyncWeb,
the eclipse project zip can be obtained here
public class Main {
private static final int PORT = 80;
/**
* Main
*
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
SocketAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new HttpCodecFactory()));
acceptor.getFilterChain().addLast("executor", new ExecutorFilter(new OrderedThreadPoolExecutor(32)));
//Allow the port to be reused even if the socket is in TIME_WAIT state
acceptor.setReuseAddress(true);
acceptor.getSessionConfig().setReuseAddress(true);
acceptor.getSessionConfig().setReceiveBufferSize(1024);
acceptor.getSessionConfig().setSendBufferSize(1024);
// No Nagle's algorithm
acceptor.getSessionConfig().setTcpNoDelay(true);
acceptor.getSessionConfig().setSoLinger(-1);
acceptor.setBacklog(10240);
acceptor.setHandler(new CustomHttpIoHandler()); // customer handler
acceptor.bind(new InetSocketAddress(PORT));
}
}
public class CustomHttpIoHandler implements IoHandler {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Timer timer;
private Random random = new Random(System.currentTimeMillis());
private final String SOAPENV_HEAD = "";
public CustomHttpIoHandler(){
timer = new Timer(true);
}
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
if (!(cause instanceof IOException)) {
cause.printStackTrace();
}
session.close(true);
}
public void messageSent(IoSession session, Object message) throws Exception {
}
public void sessionClosed(IoSession session) throws Exception {
}
public void sessionCreated(IoSession session) throws Exception {
}
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
session.close(true);
}
public void sessionOpened(IoSession session) throws Exception {
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
}
public void messageReceived(IoSession session, Object message) throws Exception {
HttpRequest req = (HttpRequest) message;
doAsynchronousDelayedResponse(session, req);
}
/**
* business logic for various percentage and behaviour
*
* @param session mina session
* @param req Http request
* @throws CharacterCodingException
*/
private void doAsynchronousDelayedResponse(final IoSession session, final HttpRequest req) throws CharacterCodingException {
int delay = 0;
Behaviour behaviour;
int value = nextRandom(1, 100);
if(value < = 50){
// 50% of responses return valid result within 0-3 secs (good response time & good result)
delay = nextRandom(10, 3000);
behaviour = Behaviour.GOOD_TIME_GOOD_RESULT;
}else if(value > 50 && value < =60){
//10% of responses return expected error within 0-3 secs (good response time & expected error result)
delay = nextRandom(10, 3000);
behaviour = Behaviour.GOOD_TIME_ERROR_RESULT;
}else if(value > 60 && value < = 90){
//30% of responses return valid result within 3-15 secs (fair response time & good result)
delay = nextRandom(3000, 15000);
behaviour = Behaviour.FAIR_TIME_GOOD_RESULT;
}else if(value > 90 && value < =95){
//5% of responses return valid result within 15-190 secs (poor response time & good result)
delay = nextRandom(15000, 190000);
behaviour = Behaviour.POOR_TIME_GOOD_RESULT;
}else if(value > 95 && value < =97){
//2.5% of responses return valid result after 190 seconds (bad response time & good result)
delay = nextRandom(15000, 190000);
behaviour = Behaviour.BAD_TIME_GOOD_RESULT;
}else{
//2.5% of responses return 'no content' after 190 seconds (bad response time & bad result)
delay = nextRandom(15000, 190000);
behaviour = Behaviour.BAD_TIME_BAD_RESULT;
}
final MutableHttpResponse res = new DefaultHttpResponse();
res.setStatus(HttpResponseStatus.OK);
res.setContentType("application/soap+xml; charset=utf-8");
// get corresponding response from behaviour
StringBuffer sb = getResponseXML(behaviour);
IoBuffer bb = IoBuffer.allocate(1024);
bb.setAutoExpand(true);
bb.putString(sb.toString(), Charset.forName("UTF-8").newEncoder());
bb.flip();
res.setContent(bb);
logger.info("delay:" + delay + " stub:" + behaviour);
timer.schedule(new TimerTask() {
@Override
public void run() {
writeResponse(session, req, res);
}
}, delay);
}
/**
* Write the http response
*
* @param session mina session
* @param req HTTP Request
* @param res HTTP Response
*/
private void writeResponse(IoSession session, HttpRequest req, MutableHttpResponse res) {
res.normalize(req);
WriteFuture future = session.write(res);
if (!HttpHeaderConstants.VALUE_KEEP_ALIVE.equalsIgnoreCase(
res.getHeader( HttpHeaderConstants.KEY_CONNECTION))) {
future.addListener(IoFutureListener.CLOSE);
}
}
/**
* Generate next random number from min(inclusive) to max(inclusive)
* @param min minimum number
* @param max maximum number
* @return random integer
*/
private int nextRandom(int min, int max){
return random.nextInt(max-min+1)+min;
}
/**
* Indicate what kind of behaviour
*
* @author SteveChan
*/
public enum Behaviour{
GOOD_TIME_GOOD_RESULT, //return valid result within 0-3 secs
GOOD_TIME_ERROR_RESULT, //return expected error within 0-3 secs
FAIR_TIME_GOOD_RESULT, //return valid result within 3-15 secs
POOR_TIME_GOOD_RESULT, //return valid result within 15-190 secs (
BAD_TIME_GOOD_RESULT, //return valid result after 190 seconds
BAD_TIME_BAD_RESULT //return 'no content' after 190 seconds
}
/**
*
* @param stub indicate what Behaviour
* @return StringBuffer with return xml content
*/
private StringBuffer getResponseXML(Behaviour stub){
StringBuffer sb = new StringBuffer();
if(stub.equals(Behaviour.GOOD_TIME_GOOD_RESULT) ||
stub.equals(Behaviour.FAIR_TIME_GOOD_RESULT) ||
stub.equals(Behaviour.POOR_TIME_GOOD_RESULT) ||
stub.equals(Behaviour.BAD_TIME_GOOD_RESULT)){
sb.append(SOAPENV_HEAD)
.append("")
// some content here
.append("")
.append("");
}else if(stub.equals(Behaviour.GOOD_TIME_ERROR_RESULT)){
sb.append(SOAPENV_HEAD)
.append("")
// some content here
.append("")
.append("");
}else{
//BAD_TIME_BAD_RESULT
sb.append(SOAPENV_HEAD)
.append("")
// some content here
.append("")
.append("");
}
if(logger.isDebugEnabled()){
logger.debug("return stardard soap response xml by " + stub );
logger.debug(sb.toString());
}
return sb;
}
}