package org.simpleframework.http.validate;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import org.simpleframework.common.buffer.Allocator;
import org.simpleframework.common.buffer.Buffer;
import org.simpleframework.common.buffer.FileAllocator;
public class Client {
private static final AtomicInteger SEQUENCE = new AtomicInteger();
private final ExecutorService executor;
private final Measurement measurement;
private final Test test;
private final File configDir;
private final boolean debug;
private final int pipeline;
private final int timeout;
public Client(ExecutorService executor, Measurement measurement, File configDir, Test test, int count, int timeout, int pipeline, boolean debug) throws IOException {
this.executor = executor;
this.measurement = measurement;
this.configDir = configDir;
this.pipeline = pipeline;
this.timeout = timeout;
this.debug = debug;
this.test = test;
}
public Buffer execute(Socket socket, byte[] request, double throttle) throws Exception {
Allocator allocator = new FileAllocator();
Buffer response = allocator.allocate();
SendTask sender = new SendTask(socket, request);
InputStream in = socket.getInputStream();
byte[] buffer = new byte[2048];
int byteCount = 0;
int count = 0;
if(debug) {
System.out.println("New connection ["+socket.getLocalPort()+"]");
}
measurement.threadRunning();
measurement.connectionEstablished();
socket.setSoTimeout(timeout);
executor.execute(sender);
try {
while((count = in.read(buffer)) != -1){
if(throttle > 0) {
double random = Math.random() * 1000; // randomize throttle
double delay = random % throttle;
if(delay > 0) {
Thread.sleep((int)delay);
}
}
byteCount += count; // bytes transferred
if(debug) {
//System.out.println("Read ["+count+"] bytes from connected socket ["+socket.getLocalPort()+"]");
}
response.append(buffer, 0, count);
}
} catch(Exception e) {
e.printStackTrace();
test.investigate(response, configDir);
measurement.errorOccured();
} finally {
measurement.receivedResponse(pipeline);
measurement.bytesTransferred(byteCount);
measurement.connectionTerminated();
measurement.threadWaiting();
socket.close();
}
if(debug) {
File outputFile = new File(configDir, "out-"+SEQUENCE.getAndIncrement());
OutputStream debugFile = new FileOutputStream(outputFile);
InputStream responseContent = response.open();
debugFile.write(String.valueOf(count).getBytes());
debugFile.write(13);
debugFile.write(10);
debugFile.write(request);
while((count = responseContent.read(buffer)) != -1) {
debugFile.write(buffer, 0, count);
}
debugFile.flush();
debugFile.close();
}
return response;
}
private class SendTask implements Runnable {
private final Socket socket;
private final byte[] request;
public SendTask(Socket socket, byte[] request) {
this.socket = socket;
this.request = request;
}
public void run() {
try {
OutputStream out = socket.getOutputStream();
int block = 1024;
int count = 0;
while(count < request.length) {
int size = Math.min(block, request.length - count);
if(debug) {
System.out.println("Write write("+request.length+", "+count+", "+size+") to connected socket ["+socket.getLocalPort()+"]");
}
if(size > 0) {
out.write(request, count, size);
}
count += size;
};
measurement.sentRequest(pipeline);
} catch(IOException e) {
e.printStackTrace();
measurement.errorOccured();
}
}
}
}