/**
*
*/
package com.trendrr.beanstalk;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SocketChannel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* Wraps the beanstalk connection.
*
*
* @author dustin
*
*/
public class BeanstalkConnection {
protected Log log = LogFactory.getLog(BeanstalkConnection.class);
private SocketChannel channel;
private ByteArrayOutputStream outbuf = new ByteArrayOutputStream();
public void connect(String addr, int port) throws BeanstalkException {
try {
this.channel = SocketChannel.open();
this.channel.connect(new InetSocketAddress(addr, port));
this.channel.finishConnect();
} catch (Exception x) {
throw new BeanstalkException(x);
}
}
public void close() {
try {
outbuf.close();
} catch (Exception x) {
log.debug("Caught", x);
}
try {
channel.close();
} catch (Exception x) {
log.debug("Caught", x);
}
}
public boolean isOpen() {
return channel != null && channel.isOpen();
}
public void write(String str) throws BeanstalkDisconnectedException, BeanstalkException{
try {
ByteBuffer buf = ByteBuffer.wrap(str.getBytes());
while(buf.hasRemaining()) {
channel.write(buf);
}
} catch (Exception x) {
this.throwException(x);
}
}
private void throwException(Exception x) throws BeanstalkDisconnectedException, BeanstalkException{
if (x instanceof NotYetConnectedException) {
throw new BeanstalkDisconnectedException(x);
}
if (x instanceof IOException) {
throw new BeanstalkDisconnectedException(x);
}
throw new BeanstalkException(x);
}
public void write(byte[] bytes) throws BeanstalkDisconnectedException, BeanstalkException{
try {
ByteBuffer buf = ByteBuffer.wrap(bytes);
while(buf.hasRemaining()) {
channel.write(buf);
}
} catch (Exception x) {
this.throwException(x);
}
}
/**
* returns the control response. ends with \r\n
* @return
*/
public String readControlResponse() throws BeanstalkDisconnectedException, BeanstalkException{
//clear the old out buffer
String response = null;
int count = 0;
while (response == null) {
count++;
outbuf = new ByteArrayOutputStream();
ByteBuffer buf = ByteBuffer.allocate(4096);
if (count > 10000) {
throw new BeanstalkException("OH Snap, nothing to read from the buffer for 100 seconds!");
}
try {
if (channel.read(buf) == 0) {
log.warn("Nothing in the buffer, sleeping for 100 millis, will try again");
try {
Thread.sleep(100);
} catch (Exception x) {
log.error("CuaghT", x);
}
continue;
}
} catch (Exception x) {
this.throwException(x);
}
byte[] bytes = buf.array();
ByteArrayOutputStream stringBuf = new ByteArrayOutputStream();
byte lastByte = ' ';
for (int i=0 ; i < buf.position(); i++) {
byte curByte = bytes[i];
if (lastByte == '\r' && curByte == '\n' && response == null) {
response = new String(stringBuf.toByteArray()).trim();
if (response.isEmpty()) {
log.warn("Errant line end found, possibly from the previous request. skipping");
response = null;
}
continue;
}
if (response == null) {
stringBuf.write(curByte);
} else {
outbuf.write(curByte);
}
lastByte = curByte;
}
// log.info("OUTBUF: " + outbuf.size() + " :" + new String(outbuf.toByteArray()));
}
return response;
}
public byte[] readBytes(int numBytes) throws BeanstalkDisconnectedException, BeanstalkException{
byte[] bytes = new byte[numBytes];
byte[] array = this.outbuf.toByteArray();
this.outbuf = new ByteArrayOutputStream();
int bytesWritten = 0;
//first read any bytes that are already in the outbuffer.
for (int i=0; i < array.length; i++) {
if (bytesWritten < bytes.length) {
bytes[i] = array[i];
bytesWritten++;
} else {
this.outbuf.write(array[i]);
}
}
// log.info("GOT 468: " + bytesWritten + " " + bytes.length);
if (bytesWritten >= bytes.length) {
return bytes;
}
int numRead = 1;
while(numRead >0) {
//then read the bytes waiting in the channel.
ByteBuffer buf = ByteBuffer.allocate(4096);
try {
numRead = channel.read(buf);
} catch (Exception x) {
this.throwException(x);
}
byte[] read = buf.array();
for (int i=0 ; i<numRead; i++) {
if (bytesWritten < bytes.length) {
bytes[bytesWritten] = read[i];
} else {
this.outbuf.write(read[i]);
}
bytesWritten++;
}
if (bytesWritten >= bytes.length) {
log.debug("468 GOT : " + bytesWritten + " " + bytes.length);
return bytes;
}
}
// log.info("GOT : " + bytesWritten + " " + bytes.length);
return bytes;
}
@Override
public void finalize() {
this.close();//just for safety.
}
}