package com.dgrid.transport;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.dgrid.errors.TransportException;
import com.dgrid.gen.Constants;
import com.dgrid.gen.Host;
import com.dgrid.gen.InvalidApiKey;
import com.dgrid.gen.InvalidHost;
import com.dgrid.gen.InvalidJobId;
import com.dgrid.gen.InvalidJobletId;
import com.dgrid.gen.Job;
import com.dgrid.gen.JobService;
import com.dgrid.gen.Joblet;
import com.dgrid.gen.JobletResult;
import com.dgrid.gen.NoHostAvailable;
import com.dgrid.gen.NoWorkAvailable;
import com.dgrid.service.DGridSyncJobService;
import com.dgrid.service.DGridTransport;
import com.dgrid.util.io.HostnameDiscovery;
import com.facebook.thrift.TException;
import com.facebook.thrift.protocol.TBinaryProtocol;
import com.facebook.thrift.protocol.TProtocol;
import com.facebook.thrift.transport.TSocket;
import com.facebook.thrift.transport.TTransport;
import com.facebook.thrift.transport.TTransportException;
public class DGridThriftTransport implements DGridTransport {
public static final String NAME = "thrift";
private static final int RETRIES = 3;
private Log log = LogFactory.getLog(getClass());
private DGridSyncJobService syncJobService;
private String hostname;
private String server = "localhost";
private int port = Constants.DEFAULT_PORT;
private String apiKey = "123";
private int hostid = 0;
public void setSyncJobService(DGridSyncJobService service) {
this.syncJobService = service;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public void setEndpoint(String endpoint) {
this.server = endpoint;
}
public void setPort(int port) {
this.port = port;
}
public void init() {
this.hostname = HostnameDiscovery.getHostname();
}
public Host getHost(int id) throws TransportException, InvalidApiKey,
InvalidHost {
log.trace("getHost()");
TConnection conn = null;
try {
conn = connect();
Host host = conn.jobService.getHost(apiKey, id);
return host;
} catch (TException e) {
log
.error(String.format("TException in getHost(%1$s)",
hostname), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public Host getHostByName(String hostname) throws TransportException,
InvalidApiKey, InvalidHost {
log.trace("getHostByName()");
TConnection conn = null;
try {
conn = connect();
Host host = getHost(conn, hostname);
return host;
} catch (TException e) {
log
.error(String.format("TException in getHost(%1$s)",
hostname), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public Host registerHost(String hostname) throws TransportException,
InvalidApiKey, InvalidHost {
log.trace("registerHost()");
TConnection conn = null;
try {
conn = connect();
Host host = conn.jobService.registerHost(apiKey, hostname);
return host;
} catch (TException e) {
log.error(String.format("TException in registerHost(%1$s)",
hostname), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public void setHostFacts(int hostid, Map<String, String> facts)
throws TransportException, InvalidApiKey, InvalidHost {
log.trace("setHostFacts()");
TConnection conn = null;
try {
conn = connect();
conn.jobService.setHostFacts(apiKey, hostid, facts);
} catch (TException e) {
log.error(
String.format("TException in setHostFacts(%1$s)", hostid),
e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public String getHostSetting(int hostid, String name, String defaultValue)
throws TransportException, InvalidApiKey, InvalidHost {
log.trace("getHostSetting()");
TConnection conn = null;
try {
conn = connect();
String value = conn.jobService.getHostSetting(apiKey, hostid, name,
defaultValue);
return value;
} catch (TException e) {
log.error(String.format("TException in getSetting(%1$s, %2$s)",
name, defaultValue), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public String getSetting(String name, String defaultValue)
throws TransportException, InvalidApiKey {
log.trace("getSetting()");
TConnection conn = null;
try {
conn = connect();
String value = conn.jobService.getSetting(apiKey, name,
defaultValue);
return value;
} catch (TException e) {
log.error(String.format("TException in getSetting(%1$s, %2$s)",
name, defaultValue), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public void log(int jobletId, int jobletStatus, String message)
throws TransportException, InvalidApiKey, InvalidJobletId {
log.trace("log()");
TConnection conn = null;
try {
conn = connect();
conn.jobService.log(apiKey, this.getHostIdCached(conn), jobletId,
jobletStatus, message);
} catch (TException e) {
log.error(String.format("TException in log(%1$s, %2$s)", jobletId,
message), e);
throw (new TransportException(e));
} catch (InvalidHost e) {
log.error(String.format("InvalidHost in log(%1$s, %2$s)", jobletId,
message), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public JobletResult gridExecute(Joblet joblet, int retries)
throws InvalidApiKey, TransportException, NoHostAvailable {
log.trace("gridExecute()");
TConnection conn = null;
try {
conn = connect();
Host host = conn.jobService.getSyncJobServiceHost(apiKey);
JobletResult result = null;
Exception e = null;
for (int i = 0; i < retries; ++i) {
try {
result = syncJobService.gridExecute(host.getHostname(),
joblet);
break;
} catch (Exception e1) {
log.warn("Exception in gridExecute()", e1);
if (i < retries)
log.warn("Retrying...");
e = e1;
}
}
if (result == null) {
if (e == null)
throw (new TransportException(
String
.format(
"Max retries of %1$d exceeded, no valid result returned",
retries)));
else
throw (new TransportException(e));
}
return result;
} catch (TException e) {
log.error("TException in execute()", e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public Job submitJob(Job job) throws TransportException, InvalidApiKey {
log.trace("submitJob()");
TConnection conn = null;
try {
conn = connect();
Job j = conn.jobService.submitJob(apiKey, job);
return j;
} catch (TException e) {
log.error("TException in submitJob()", e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public Joblet submitJoblet(Joblet joblet, int jobId, int callbackType,
String callbackAddress, String callbackContent)
throws TransportException, InvalidApiKey, InvalidJobId {
log.trace("submitJoblet()");
TConnection conn = null;
try {
conn = connect();
Joblet j = conn.jobService.submitJoblet(apiKey, joblet, jobId,
callbackType, callbackAddress, callbackContent);
return j;
} catch (TException e) {
log.error("TException in submitJoblet()", e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public void completeJoblet(int jobletId, JobletResult result,
String logMessage) throws TransportException, InvalidApiKey,
InvalidJobletId {
log.trace("completeJoblet()");
TConnection conn = null;
try {
conn = connect();
conn.jobService.completeJoblet(apiKey, this.getHostIdCached(conn),
jobletId, result, logMessage);
} catch (TException e) {
log.error("TException in completeJoblet()", e);
throw (new TransportException(e));
} catch (InvalidHost e) {
log.error("InvalidHost in completeJoblet()", e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public void releaseJoblet(int jobletId) throws InvalidApiKey,
TransportException, InvalidJobletId {
log.trace("releaseJoblet()");
TConnection conn = null;
try {
conn = connect();
conn.jobService.releaseJoblet(apiKey, this.getHostIdCached(conn),
jobletId);
} catch (TException e) {
log.error(String.format("TException in releaseJoblet(%1$d)",
jobletId), e);
throw (new TransportException(e));
} catch (InvalidHost e) {
log.error(String.format("InvalidHost in releaseJoblet(%1$d)",
jobletId), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public Job getJob(int jobId) throws TransportException, InvalidApiKey,
InvalidJobId {
log.trace("getJob()");
TConnection conn = null;
try {
conn = connect();
Job job = conn.jobService.getJob(apiKey, jobId);
return job;
} catch (TException e) {
log.error(String.format("TException in getJob(%1$d)", jobId), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public JobletResult getJobletResult(int jobletId)
throws TransportException, InvalidApiKey, InvalidJobletId {
log.trace("getJobletResult()");
TConnection conn = null;
try {
conn = connect();
JobletResult result = conn.jobService.getJobletResult(apiKey,
jobletId);
return result;
} catch (TException e) {
log.error(String.format("TException in getJobletResult(%1$d)",
jobletId), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public List<JobletResult> getResults(int jobId) throws TransportException,
InvalidApiKey, InvalidJobId {
log.trace("getResults()");
TConnection conn = null;
try {
conn = connect();
List<JobletResult> results = conn.jobService.getResults(apiKey,
jobId);
return results;
} catch (TException e) {
log
.error(String.format("TException in getResults(%1$d)",
jobId), e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public Joblet getWork() throws TransportException, InvalidApiKey,
InvalidHost, NoWorkAvailable {
log.trace("getWork()");
Joblet joblet = null;
TConnection conn = null;
try {
conn = connect();
Host host = getHost(conn, this.hostname);
joblet = conn.jobService.getWork(apiKey, host.getId());
return joblet;
} catch (TException e) {
log.error("TException in getWork()", e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public int getJobletQueueSize() throws TransportException, InvalidApiKey {
log.trace("getJobletQueueSize()");
TConnection conn = null;
try {
conn = connect();
int size = conn.jobService.getJobletQueueSize(apiKey);
return size;
} catch (TException e) {
log.error("TException in getJobletQueueSize()", e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
public List<Joblet> listActiveJoblets(String submitter, int offset,
int limit) throws TransportException, InvalidApiKey {
log.trace("listActiveJoblets()");
TConnection conn = null;
try {
conn = connect();
List<Joblet> joblets = conn.jobService.listActiveJoblets(apiKey,
submitter, offset, limit);
return joblets;
} catch (TException e) {
log.error("TException in getJobletQueueSize()", e);
throw (new TransportException(e));
} finally {
disconnect(conn);
}
}
private int getHostIdCached(TConnection conn) throws InvalidApiKey,
TException, InvalidHost {
int retval = 0;
if (this.hostid != 0)
retval = this.hostid;
else {
Host h = getHost(conn, this.hostname);
retval = h.getId();
}
return retval;
}
private Host getHost(TConnection conn, String hostname)
throws InvalidApiKey, TException, InvalidHost {
log.trace("getHost()");
TTransportException e = null;
for (int i = 0; i < RETRIES; ++i) {
try {
Host host = conn.jobService.getHostByName(apiKey, hostname);
return host;
} catch (TTransportException tte) {
e = tte;
if (i < RETRIES)
conn = connect();
}
}
throw e;
}
private TConnection connect() throws TTransportException {
log.trace("connect()");
TSocket socket = new TSocket(server, port);
TProtocol protocol = new TBinaryProtocol(socket);
JobService.Iface jobService = new JobService.Client(protocol);
socket.open();
return new TConnection(socket, jobService);
/*
* TTransport transport = new TFramedTransport(socket); TProtocol
* protocol = new TBinaryProtocol(transport); JobService.Iface
* jobService = new JobService.Client(protocol); transport.open();
* return new TConnection(transport, jobService);
*/
}
private void disconnect(TConnection connection) {
log.trace("disconnect()");
try {
connection.transport.close();
} catch (Exception e) {
log.warn("Exception calling transport.close()", e);
}
}
private static class TConnection {
public TTransport transport;
public JobService.Iface jobService;
public TConnection(TTransport transport, JobService.Iface jobService) {
this.transport = transport;
this.jobService = jobService;
}
}
}