package de.uni_luebeck.inb.krabbenhoeft.eQTL.server;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.Session;
import org.hibernate.Transaction;
import de.uni_luebeck.inb.krabbenhoeft.eQTL.entities.ColumnForDataSetLayer;
import de.uni_luebeck.inb.krabbenhoeft.eQTL.entities.DataSetLayer;
import de.uni_luebeck.inb.krabbenhoeft.eQTL.entities.ProcessingParameters;
import de.uni_luebeck.inb.krabbenhoeft.eQTL.server.DataSetProcessor.ProcessingResult;
import de.uni_luebeck.inb.krabbenhoeft.eQTL.server.helpers.persistence.RunWithHibernate;
public class DataProcessingInternalServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final Logger log = Logger.getLogger(getClass().getName());
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(200);
final String basePath = getBasePath(req);
final String key = req.getParameter("key");
if (key != null) {
invokeProcessor(key);
return;
}
final String layer = req.getParameter("layer");
final String workingSetSize = req.getParameter("workingSetSize");
if (workingSetSize != null) {
invokeWorkingSet(basePath, Integer.parseInt(layer), Integer.parseInt(workingSetSize));
return;
}
final String cleanup = req.getParameter("cleanup");
if (cleanup != null) {
invokeCleanup(basePath, Integer.parseInt(layer), Integer.parseInt(cleanup));
return;
}
}
@SuppressWarnings("unchecked")
public void invokeWorkingSet(final String basePath, final int targetDataSetLayerKey, final int workingSetSize) {
log.info("Invoking a working set of size " + workingSetSize + " for target layer " + targetDataSetLayerKey);
final ExecutorService threadPool = Executors.newCachedThreadPool();
boolean hasMore = new RunWithHibernate<Boolean>() {
public Boolean work(Transaction transaction, Session session) throws Exception {
final org.hibernate.Query query = session.createQuery("select key from ProcessingParameters where targetDataSetLayerKey = :a and processingResult is null");
final List<Integer> callThese = query.setParameter("a", targetDataSetLayerKey).setMaxResults(workingSetSize + 1).list();
boolean hasMore = callThese.size() > workingSetSize;
boolean skipOne = hasMore;
for (final Integer key : callThese) {
if (skipOne) {
skipOne = false;
continue;
}
final String command = basePath + "/data_set_processor?key=" + Integer.toString(key);
threadPool.execute(DataProcessingService.runnableForCommand(command));
}
return hasMore;
}
}.run();
threadPool.shutdown();
try {
threadPool.awaitTermination(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}
if (hasMore) {
final String command = "/data_set_processor?layer=" + targetDataSetLayerKey + "&workingSetSize=" + workingSetSize;
DataProcessingService.invokeSelfAsync(basePath + command);
} else
DataProcessingService.invokeSelfAsync(basePath + "/data_set_processor?layer=" + targetDataSetLayerKey + "&cleanup=1");
}
public void invokeProcessor(String key) {
log.info("Invoking processor for key " + key);
final Integer keyInt = Integer.valueOf(key);
new RunWithHibernate<Void>() {
public Void work(Transaction transaction, Session session) throws Exception {
ProcessingParameters parameters = (ProcessingParameters) session.load(ProcessingParameters.class, keyInt);
final DataSetProcessorFactory factory = DataProcessingService.getFacoryByKey(parameters.getProcessorKey());
final DataSetProcessor processor = factory.configure(parameters.getProcessorConfiguration());
final ProcessingResult processingResult = processor.process(parameters);
parameters.setProcessingResult(processingResult);
session.flush();
return null;
}
}.run();
}
@SuppressWarnings("unchecked")
private void invokeCleanup(final String basePath, final int targetDataSetLayerKey, final int cleanupsLeft) {
log.info("Invoking cleanup for layer " + targetDataSetLayerKey);
boolean retry = new RunWithHibernate<Boolean>() {
public Boolean work(Transaction transaction, Session session) throws Exception {
final DataSetLayer dataSetLayer = (DataSetLayer) session.load(DataSetLayer.class, targetDataSetLayerKey);
Map<String, ColumnForDataSetLayer> name2column = new HashMap<String, ColumnForDataSetLayer>();
for (ColumnForDataSetLayer column : dataSetLayer.getColumns()) {
name2column.put(column.getName(), column);
}
final int workingSetSize = 990;
final org.hibernate.Query query = session.createQuery("from ProcessingParameters where targetDataSetLayerKey = :a");
final List<ProcessingParameters> processingWorkers = query.setParameter("a", targetDataSetLayerKey).setMaxResults(workingSetSize + 1).list();
boolean hasMore = processingWorkers.size() > workingSetSize;
boolean skipOne = hasMore;
boolean missingResult = false;
final List<ProcessingParameters> processingWorkersToDelete = new ArrayList<ProcessingParameters>();
for (ProcessingParameters worker : processingWorkers) {
if (skipOne) {
skipOne = false;
continue;
}
final ProcessingResult result = worker.getProcessingResult();
if (result == null) {
missingResult = true;
continue;
}
dataSetLayer.setNumberOfItems(dataSetLayer.getNumberOfItems() + result.numberOfItemsEmitted);
for (ColumnForDataSetLayer column : result.columnDefinitions) {
switch (column.getType()) {
case Category:
name2column.get(column.getName()).getValues().addAll(column.getValues());
break;
case Numerical: {
final ColumnForDataSetLayer ocol = name2column.get(column.getName());
ocol.setMin(Math.min(ocol.getMin(), column.getMin()));
ocol.setMax(Math.max(ocol.getMax(), column.getMax()));
break;
}
default:
break;
}
}
processingWorkersToDelete.add(worker);
}
if (processingWorkersToDelete.size() > 0) {
// remove all the workes we just collected
for (ProcessingParameters processingParameters : processingWorkersToDelete)
session.delete(processingParameters);
}
final boolean retry = (hasMore || missingResult) && cleanupsLeft > 0;
if (!retry) {
dataSetLayer.setCalculationComplete(true);
session.flush();
}
return retry;
}
}.run();
if (retry)
DataProcessingService.invokeSelfAsync(basePath + "/data_set_processor?layer=" + targetDataSetLayerKey + "&cleanup=" + (cleanupsLeft - 1));
}
private String getBasePath(HttpServletRequest request) {
String path = request.getRequestURL().toString();
path = path.substring(0, path.indexOf('/', 9));
return path;
}
}