package io.github.infolis.algorithm;
import io.github.infolis.datastore.AbstractClient;
import io.github.infolis.datastore.DataStoreClient;
import io.github.infolis.datastore.FileResolver;
import io.github.infolis.datastore.LocalClient;
import io.github.infolis.datastore.TempFileResolver;
import io.github.infolis.model.Execution;
import io.github.infolis.model.ExecutionStatus;
import io.github.infolis.util.SerializationUtils;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.ws.rs.BadRequestException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author kba
* @author domi
*/
public abstract class BaseAlgorithm implements Algorithm {
private static final Logger log = LoggerFactory.getLogger(BaseAlgorithm.class);
/*
* The list of algorithms
*/
public static Map<String, Class<? extends BaseAlgorithm>> algorithms = new HashMap<>();
static {
algorithms.put(TextExtractor.class.getSimpleName(), TextExtractor.class);
}
public BaseAlgorithm(
DataStoreClient inputDataStoreClient, DataStoreClient outputDataStoreClient,
FileResolver inputFileResolver, FileResolver outputFileResolver) {
this.outputDataStoreClient = outputDataStoreClient;
this.inputDataStoreClient = inputDataStoreClient;
this.outputFileResolver = outputFileResolver;
this.inputFileResolver = inputFileResolver;
}
private Execution execution;
private FileResolver outputFileResolver;
private FileResolver inputFileResolver;
private DataStoreClient inputDataStoreClient;
private DataStoreClient outputDataStoreClient;
public void baseValidate() throws IllegalAlgorithmArgumentException {
if (null == getExecution()) {
throw new IllegalAlgorithmArgumentException(getClass(), "execution", "Algorithm must have a 'Excecution' set to run().");
}
if (null == getInputFileResolver()) {
throw new IllegalAlgorithmArgumentException(getClass(), "inputFileResolver", "Algorithm must have an input 'FileResolver' set to run().");
}
if (null == getOutputFileResolver()) {
throw new IllegalAlgorithmArgumentException(getClass(), "outputFileResolver", "Algorithm must have an output 'FileResolver' set to run().");
}
if (null == getOutputDataStoreClient()) {
throw new IllegalAlgorithmArgumentException(getClass(), "dataStoreClient", "Algorithm must have a 'dataStoreClient' set to run().");
}
}
@Override
public void debug(Logger log, String fmt, Object... args) {
log(log, fmt, "DEBUG", args);
}
@Override
public void fatal(Logger log, String fmt, Object... args) {
log(log, fmt, "FATAL", args);
}
@Override
public void error(Logger log, String fmt, Object... args) {
log(log, fmt, "ERROR", args);
}
@Override
public void warn(Logger log, String fmt, Object... args) {
log(log, fmt, "WARN", args);
}
@Override
public DataStoreClient getOutputDataStoreClient() {
return outputDataStoreClient;
}
@Override
public DataStoreClient getInputDataStoreClient() {
return inputDataStoreClient;
}
@Override
public Execution getExecution() {
return execution;
}
@Override
public FileResolver getInputFileResolver() {
return inputFileResolver;
}
@Override
public FileResolver getOutputFileResolver() {
return outputFileResolver;
}
@Override
public AbstractClient getTempDataStoreClient() {
return new LocalClient(UUID.randomUUID());
}
@Override
public TempFileResolver getTempFileResolver() {
return new TempFileResolver();
}
@Override
public void info(Logger log, String fmt, Object... args) {
log(log, fmt, "INFO", args);
}
private String log(Logger log, String fmt, String level, Object... args) {
fmt = fmt.replaceAll("%", "%%");
final String str = String.format(fmt.replaceAll("\\{\\}", "%s"), args);
switch (level.toLowerCase()) {
case "trace":
log.trace(str);
break;
case "debug":
log.debug(str);
break;
case "info":
log.info(str);
break;
case "warn":
log.warn(str);
break;
case "error":
log.error(str);
break;
case "fatal":
log.error(str);
break;
}
getExecution().getLog().add(String.format("%s [%s -- %s] %s", level, new Date(), getClass().getSimpleName(), str));
return str;
}
protected void persistExecution() throws BadRequestException {
log.debug("Persisting execution");
if (null != getExecution().getUri()) {
getOutputDataStoreClient().put(Execution.class, getExecution());
} else {
getOutputDataStoreClient().post(Execution.class, getExecution());
}
}
@Override
public final void run() {
log.debug("{}", SerializationUtils.toJSON(getExecution()));
try {
getExecution().setStartTime(new Date());
getExecution().setStatus(ExecutionStatus.STARTED);
baseValidate();
validate();
} catch (IllegalAlgorithmArgumentException | RuntimeException e) {
getExecution().setStatus(ExecutionStatus.FAILED);
error(log, "Validation threw an Exception: {}", e);
e.printStackTrace();
getExecution().setEndTime(new Date());
getExecution().setProgress(100);
return;
} finally {
persistExecution();
}
try {
execute();
getExecution().setEndTime(new Date());
getExecution().setProgress(100);
} catch (IOException e) {
error(log, "Execution threw an Exception: {}", e);
e.printStackTrace();
getExecution().setStatus(ExecutionStatus.FAILED);
getExecution().setEndTime(new Date());
getExecution().setProgress(100);
} finally {
persistExecution();
}
}
@Override
public void setDataStoreClient(DataStoreClient dataStoreClient) {
this.inputDataStoreClient = dataStoreClient;
}
@Override
public void setExecution(Execution execution) {
this.execution = execution;
}
/**
* Update the current process of the execution each second.
*
* @param done
* @param total
*/
@Override
public void updateProgress(int done, int total) {
Date now = new Date(System.currentTimeMillis());
if ((now.getTime() - getExecution().getStartTime().getTime()) > 1000) {
int percentage = new Double(100*((double)done/(double)total)).intValue();
getExecution().setProgress(percentage);
if (null != getExecution().getUri()) {
getOutputDataStoreClient().put(Execution.class, getExecution());
} else {
getOutputDataStoreClient().post(Execution.class, getExecution());
}
}
}
}