package dk.daoas.adressevedligehold.tasks; import dk.daoas.adressevedligehold.util.TimingHelper; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; public abstract class Task implements Runnable { private TaskLogger logger = TaskLogger.getInstance(); public enum TaskState { STATE_QUEUED, STATE_RUNNING, STATE_DONE, STATE_ABORTED; } @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")//bliver læst via gson - og det forvirrer findbugs public static class TaskBean { public int id; public String description; public String detail; public String errorMessage; public double percentCompleted; public String state; } protected volatile boolean abort = false;//mark volatile to make sure value isn't cached by threads protected volatile TaskState state = TaskState.STATE_QUEUED; protected TaskManager manager; private String errorMsg; private String logMessages; private int id; public final void setManager(TaskManager manager) { this.manager = manager; } @Override public final void run() { if (this.state == TaskState.STATE_ABORTED) {//if this task as cancelled while still in queue return; } TaskLogger.getInstance().reset(); TimingHelper timing = new TimingHelper(); logger.info("Starting " + this.getDescription() ); this.state = TaskState.STATE_RUNNING; manager.setCurrentTask(this); try { taskRun(); if (this.state != TaskState.STATE_ABORTED) { //just to make sure we wasn't aborted this.state = TaskState.STATE_DONE; } } catch (Exception e) { logger.warning("Error during taskrun", e); this.errorMsg = e.getMessage(); this.state = TaskState.STATE_ABORTED; } manager.setCurrentTask(null); logger.info("Done " + this.getDescription() + " " + timing.getElapsed() + "ms"); logMessages = TaskLogger.getInstance().getBuffer(); // Make some delay between tasks to make sure that the VM settles and other contexts can perform their tasks as well try { Thread.sleep(60*1000); } catch (InterruptedException e) { e.printStackTrace(); } } public final String getLog() { if (this.state == TaskState.STATE_RUNNING) { return TaskLogger.getInstance().getBuffer(); //if live return current log buffer content } else { return logMessages; } } public final void setId(int newId) { this.id = newId; } public final int getId() { return this.id; } public final TaskState getState() { return this.state; } public boolean isAborted() { return this.abort; } public void doAbort() { this.abort = true; } public void doAbort(Exception e) { this.abort = true; this.errorMsg = e.getMessage(); } public TaskBean getTaskBean() { TaskBean bean = new TaskBean(); bean.id = this.getId(); bean.description = this.getDescription(); bean.detail = this.getDetail(); bean.percentCompleted = this.getPercentCompleted(); bean.state = this.state.toString(); bean.errorMessage = this.getErrorMessage(); return bean; } public String getErrorMessage() { return this.errorMsg; } @Override public int hashCode() { return this.id; } @Override public boolean equals(Object o) { if (! (o instanceof Task)) return false; Task otherTask = (Task) o; return this.getId() == otherTask.getId(); } /** * @throws Exception * * Implementing classes should not catch terminating exceptions but let it propagate to Task the Task::run() * method. */ protected abstract void taskRun() throws Exception; public abstract String getDescription(); public abstract String getDetail(); public abstract double getPercentCompleted(); }