/**
*
*/
package com.trendrr.beanstalk;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.ByteArrayOutputStream;
import java.util.Date;
//import com.trendrr.common.DynMap;
/**
* @author dustin norlander
*
*/
public class BeanstalkClient {
protected Log log = LogFactory.getLog(BeanstalkClient.class);
protected BeanstalkConnection con;
private boolean inited = false;
boolean reap = false; //this will tell the pool to reap it when returned
protected String addr;
protected int port;
protected String tube;
/**
* these variables are only used in the pool
*/
Date inUseSince = null;
Date lastUsed = null;
BeanstalkPool pool = null;
public static void main(String...strings) throws Exception{
}
public BeanstalkClient(BeanstalkConnection con) {
this.con = con;
this.inited = true;
}
public BeanstalkClient(String addr, int port) {
this(addr, port, null);
}
public BeanstalkClient(String addr, int port, String tube) {
this.addr = addr;
this.port = port;
this.tube = tube;
}
public BeanstalkClient(String addr, int port, String tube, BeanstalkPool pool) {
this.addr = addr;
this.port = port;
this.tube = tube;
this.pool = pool;
}
/**
* will return the connection to the pool, or close the underlying socket if this
* did not come from a pool
*/
public void close() {
if (this.pool == null) {
if (this.con != null) {
this.con.close();
}
return;
}
pool.done(this);
}
private void init() throws BeanstalkException{
if (inited) {
return;
}
try {
this.inited = true;
this.con = new BeanstalkConnection();
this.con.connect(addr, port);
if (this.tube != null) {
this.useTube(tube);
this.watchTube(tube);
this.ignoreTube("default"); //remove the default tube from watchlist
}
} catch (BeanstalkException x) {
throw x;
}
}
public void useTube(String tube) throws BeanstalkException{
try {
this.init();
con.write("use " + tube + "\r\n");
String line = con.readControlResponse();
log.debug(line);
if (line.startsWith("USING")) {
return;
}
throw new BeanstalkException(line);
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
} catch (BeanstalkException x) {
throw x;
}
}
public void watchTube(String tube) throws BeanstalkException{
try {
this.init();
con.write("watch " + tube + "\r\n");
String line = con.readControlResponse();
log.debug(line);
if (line.startsWith("WATCHING")) {
return;
}
throw new BeanstalkException(line);
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
} catch (BeanstalkException x) {
throw x;
}
}
public void ignoreTube(String tube) throws BeanstalkException{
try {
this.init();
con.write("ignore " + tube + "\r\n");
String line = con.readControlResponse();
log.debug(line);
if (line.startsWith("WATCHING")) {
return;
}
throw new BeanstalkException(line);
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
}
}
/**
* stats for the current tube
* @throws BeanstalkException
*/
public String tubeStats() throws BeanstalkException {
return this.tubeStats(this.tube);
}
public String tubeStats(String tube) throws BeanstalkException {
try {
this.init();
String command = "stats-tube " + tube + "\r\n";
// log.info(command);
con.write(command);
String line = con.readControlResponse();
// log.info(line);
if (!line.startsWith("OK")) {
throw new BeanstalkException(line);
}
int numBytes = Integer.parseInt(line.split(" ")[1]);
String response = new String(con.readBytes(numBytes));
log.info(response);
return response;
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
}
}
/**
* Puts a task into the currently used queue (see {@link #useTube(String)}.
* @param priority The job priority, from 0 to 2^32. Most urgent = 0, least urgent = 4294967295.
* @param delay The time the server will wait before putting the job on the ready queue.
* @param ttr The job time-to-run. The server will automatically release the job after this TTR (in seconds)
* after a client reserves it.
* @param data The job data.
* @return The id of the inserted job.
* @throws BeanstalkException If an unexpected response is received from the server, or other unexpected
* problem occurs.
*/
public long put(long priority, int delay, int ttr, byte[] data) throws BeanstalkException{
try {
this.init();
Date start = new Date();
String command = "put " + priority + " " + delay + " " + ttr + " " + data.length + "\r\n";
// log.info(command);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
buf.write(command.getBytes());
buf.write(data);
buf.write("\r\n".getBytes());
con.write(buf.toByteArray());
// String line = in.readLine();
String line = con.readControlResponse();
// log.info("INPUT: " + line);
// log.info("READ RESPONSE IN : " + (new Date().getTime() - start.getTime()) );
if (line.startsWith("INSERTED")) {
long id = Long.parseLong(line.replaceAll("[^0-9]", ""));
return id;
}
//there was an error.
throw new BeanstalkException(line);
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
} catch (BeanstalkException x) {
throw x;
} catch (Exception x) {
throw new BeanstalkException(x);
}
}
public void deleteJob(BeanstalkJob job) throws BeanstalkException {
deleteJob(job.getId());
}
public void deleteJob(long id) throws BeanstalkException {
try {
this.init();
String command = "delete " + id + "\r\n";
log.debug(this);
log.debug(command);
con.write(command);
String line = con.readControlResponse();
log.debug(line);
if (line.startsWith("DELETED")) {
return;
}
throw new BeanstalkException(line);
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
}
}
/**
* Reserves a job from the queue.
* @param timeoutSeconds The number of seconds to wait for a job. Null if a job should be reserved
* only if immediately available.
* @return The head of the queue, or null if the specified timeout elapses before a job is available.
* @throws BeanstalkException If an unexpected response is received from the server, or other unexpected
* problem occurs.
*/
public BeanstalkJob reserve(Integer timeoutSeconds) throws BeanstalkException{
try {
this.init();
String command = "reserve\r\n";
if (timeoutSeconds != null) {
command = "reserve-with-timeout " + timeoutSeconds + "\r\n";
}
log.debug(this);
log.debug(command);
con.write(command);
String line = con.readControlResponse();
log.debug(line);
if (line.startsWith("TIMED_OUT")) {
return null;
}
if (!line.startsWith("RESERVED")) {
throw new BeanstalkException(line);
}
String[] tmp = line.split("\\s+");
long id = Long.parseLong(tmp[1]);
int numBytes= Integer.parseInt(tmp[2]);
log.debug("ID : " + id);
log.debug("numbytes: " + numBytes);
byte[] bytes = con.readBytes(numBytes);
// log.info("GOT TASK: " + new String(bytes));
BeanstalkJob job = new BeanstalkJob();
job.setData(bytes);
job.setId(id);
job.setClient(this);
return job;
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
} catch (BeanstalkException x) {
throw x;
} catch (Exception x) {
throw new BeanstalkException(x);
}
}
public void release(long id, int priority, int delay) throws BeanstalkException {
try {
this.init();
String command = "release " + id + " " + priority + " " + delay + "\r\n";
log.debug(this);
log.debug(command);
con.write(command);
String line = con.readControlResponse();
log.debug(line);
if (!line.startsWith("RELEASED")) {
throw new BeanstalkException(line);
}
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
} catch (BeanstalkException x) {
throw x;
} catch (Exception x) {
throw new BeanstalkException(x);
}
}
/**
* Releases a job (places it back onto the queue).
* @param job The job to release. This job must previously have been reserved.
* @param priority The new priority to assign to the released job.
* @param delay The number of seconds the server should wait before placing the job onto the ready queue.
* @throws BeanstalkException If an unexpected response is received from the server, or other unexpected
* problem occurs.
*/
public void release(BeanstalkJob job, int priority, int delay) throws BeanstalkException {
release(job.getId(), priority, delay);
}
/**
* Buries a job ("buried" state means the job will not be touched by the server again until "kicked").
* @throws BeanstalkException If an unexpected response is received from the server, or other unexpected
* problem occurs.
* @param job The job to bury. This job must previously have been reserved.
* @param priority The new priority to assign to the job.
*/
public void bury(BeanstalkJob job, int priority) throws BeanstalkException {
try {
this.init();
String command = "bury " + job.getId() + " " + priority + "\r\n";
log.debug(this);
log.debug(command);
con.write(command);
String line = con.readControlResponse();
log.debug(line);
if (!line.startsWith("BURIED")) {
throw new BeanstalkException(line);
}
} catch (BeanstalkDisconnectedException x) {
this.reap = true; //reap that shit..
throw x;
} catch (BeanstalkException x) {
throw x;
} catch (Exception x) {
throw new BeanstalkException(x);
}
}
}