package io.lumify.sql.model.longRunningProcess;
import com.google.inject.Inject;
import io.lumify.core.exception.LumifyException;
import io.lumify.core.model.longRunningProcess.LongRunningProcessRepository;
import io.lumify.core.model.user.UserRepository;
import io.lumify.core.model.workQueue.WorkQueueRepository;
import io.lumify.core.user.ProxyUser;
import io.lumify.core.user.User;
import io.lumify.core.util.LumifyLogger;
import io.lumify.core.util.LumifyLoggerFactory;
import io.lumify.sql.model.HibernateSessionManager;
import io.lumify.sql.model.user.SqlUser;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.json.JSONObject;
import org.securegraph.Authorizations;
import org.securegraph.Graph;
import org.securegraph.util.ConvertingIterable;
import java.util.List;
import static org.securegraph.util.IterableUtils.toList;
public class SqlLongRunningProcessRepository extends LongRunningProcessRepository {
private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(SqlLongRunningProcessRepository.class);
private final HibernateSessionManager sessionManager;
private final UserRepository userRepository;
private final Graph graph;
private final WorkQueueRepository workQueueRepository;
@Inject
public SqlLongRunningProcessRepository(
final HibernateSessionManager sessionManager,
final UserRepository userRepository,
final Graph graph,
final WorkQueueRepository workQueueRepository) {
this.sessionManager = sessionManager;
this.userRepository = userRepository;
this.graph = graph;
this.workQueueRepository = workQueueRepository;
}
@Override
public String enqueue(JSONObject longRunningProcessQueueItem, User user, Authorizations authorizations) {
String longRunningProcessId;
Session session = sessionManager.getSession();
Transaction transaction = null;
SqlLongRunningProcess longRunningProcess;
try {
transaction = session.beginTransaction();
longRunningProcess = new SqlLongRunningProcess();
longRunningProcessId = graph.getIdGenerator().nextId();
longRunningProcess.setCanceled(false);
longRunningProcess.setLongRunningProcessId(longRunningProcessId);
longRunningProcessQueueItem.put("id", longRunningProcessId);
longRunningProcessQueueItem.put("enqueueTime", System.currentTimeMillis());
longRunningProcessQueueItem.put("userId", user.getUserId());
longRunningProcess.setJson(longRunningProcessQueueItem.toString());
if (user instanceof ProxyUser) {
user = userRepository.findById(user.getUserId());
}
longRunningProcess.setUser((SqlUser) user);
LOGGER.debug("add %s to long running process table", longRunningProcessId);
session.save(longRunningProcess);
session.update(user);
transaction.commit();
this.workQueueRepository.pushLongRunningProcessQueue(longRunningProcessQueueItem);
} catch (HibernateException e) {
if (transaction != null) {
transaction.rollback();
}
throw new LumifyException("Could not add long running process: " + longRunningProcessQueueItem.toString(), e);
}
return longRunningProcessId;
}
@Override
public void beginWork(final JSONObject longRunningProcessQueueItem) {
super.beginWork(longRunningProcessQueueItem);
updateLongRunningProcess(longRunningProcessQueueItem, new UpdateLongRunningProcessAction() {
@Override
public void run(SqlLongRunningProcess longRunningProcess) {
long startTime = longRunningProcessQueueItem.optLong("startTime", -1);
if (startTime == -1) {
startTime = System.currentTimeMillis();
}
longRunningProcess.setStartTime(startTime);
}
});
}
@Override
public void ack(final JSONObject longRunningProcessQueueItem) {
updateLongRunningProcess(longRunningProcessQueueItem, new UpdateLongRunningProcessAction() {
@Override
public void run(SqlLongRunningProcess longRunningProcess) {
long endTime = longRunningProcessQueueItem.optLong("endTime", -1);
if (endTime == -1) {
endTime = System.currentTimeMillis();
}
longRunningProcess.setEndTime(endTime);
}
});
}
@Override
public void nak(final JSONObject longRunningProcessQueueItem, Throwable ex) {
updateLongRunningProcess(longRunningProcessQueueItem, new UpdateLongRunningProcessAction() {
@Override
public void run(SqlLongRunningProcess longRunningProcess) {
long endTime = longRunningProcessQueueItem.optLong("endTime", -1);
if (endTime == -1) {
endTime = System.currentTimeMillis();
}
longRunningProcess.setEndTime(endTime);
longRunningProcess.setErred(true);
}
});
}
@Override
public void cancel(String longRunningProcessId, User user) {
updateLongRunningProcess(longRunningProcessId, new UpdateLongRunningProcessAction() {
@Override
public void run(SqlLongRunningProcess longRunningProcess) {
longRunningProcess.setCanceled(true);
}
});
}
@Override
public void reportProgress(JSONObject longRunningProcessQueueItem, final double progressPercent, final String message) {
final JSONObject[] json = new JSONObject[1];
updateLongRunningProcess(longRunningProcessQueueItem, new UpdateLongRunningProcessAction() {
@Override
public void run(SqlLongRunningProcess longRunningProcess) {
json[0] = new JSONObject(longRunningProcess.getJson());
json[0].put("progress", progressPercent);
json[0].put("progressMessage", message);
longRunningProcess.setJson(json[0].toString());
}
});
workQueueRepository.broadcastLongRunningProcessChange(json[0]);
}
@Override
public List<JSONObject> getLongRunningProcesses(User user) {
Session session = sessionManager.getSession();
List longRunningProcesses = session.createCriteria(SqlLongRunningProcess.class)
.add(Restrictions.eq("user.userId", user.getUserId()))
.list();
return toList(new ConvertingIterable<Object, JSONObject>(longRunningProcesses) {
@Override
protected JSONObject convert(Object longRunningProcessObj) {
SqlLongRunningProcess longRunningProcess = (SqlLongRunningProcess) longRunningProcessObj;
JSONObject json = new JSONObject(longRunningProcess.getJson());
json.put("id",longRunningProcess.getLongRunningProcessId());
return json;
}
});
}
private SqlLongRunningProcess findSqlLongRunningProcessById(String longRunningProcessId) {
Session session = sessionManager.getSession();
List longRunningProcesses = session.createCriteria(SqlLongRunningProcess.class)
.add(Restrictions.eq("longRunningProcessId", longRunningProcessId))
.list();
if (longRunningProcesses.size() == 0) {
return null;
} else if (longRunningProcesses.size() > 1) {
throw new LumifyException("more than one long running process was returned");
} else {
return (SqlLongRunningProcess) longRunningProcesses.get(0);
}
}
@Override
public JSONObject findById(String longRunningProcessId, User user) {
SqlLongRunningProcess sqlLongRunningProcess = findSqlLongRunningProcessById(longRunningProcessId);
return new JSONObject(sqlLongRunningProcess.getJson());
}
@Override
public void delete(String longRunningProcessId, User authUser) {
Session session = sessionManager.getSession();
SqlLongRunningProcess sqlLongRunningProcess = findSqlLongRunningProcessById(longRunningProcessId);
Transaction transaction = null;
try {
transaction = session.beginTransaction();
session.delete(sqlLongRunningProcess);
transaction.commit();
} catch (HibernateException e) {
if (transaction != null) {
transaction.rollback();
}
throw new RuntimeException(e);
}
}
public void updateLongRunningProcess(String longRunningProcessId, UpdateLongRunningProcessAction updateLongRunningProcessAction) {
SqlLongRunningProcess longRunningProcess = findSqlLongRunningProcessById(longRunningProcessId);
Session session = sessionManager.getSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
updateLongRunningProcessAction.run(longRunningProcess);
session.update(longRunningProcess);
transaction.commit();
} catch (HibernateException e) {
if (transaction != null) {
transaction.rollback();
}
throw new LumifyException("Could not update long running process: " + longRunningProcess.toString(), e);
}
}
public void updateLongRunningProcess(JSONObject longRunningProcessQueueItem, UpdateLongRunningProcessAction updateLongRunningProcessAction) {
updateLongRunningProcess(longRunningProcessQueueItem.getString("id"), updateLongRunningProcessAction);
}
private abstract class UpdateLongRunningProcessAction {
public abstract void run(SqlLongRunningProcess longRunningProcess);
}
}