package com.netifera.platform.internal.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.db4o.ext.DatabaseClosedException;
import com.netifera.platform.api.events.EventListenerManager;
import com.netifera.platform.api.events.IEventHandler;
import com.netifera.platform.api.tasks.ITaskOutput;
import com.netifera.platform.api.tasks.ITaskOutputEvent;
import com.netifera.platform.api.tasks.ITaskRecord;
import com.netifera.platform.api.tasks.ITaskStatus;
public class TaskRecord implements ITaskRecord {
private final static int BACKGROUND_COMMIT_INTERVAL = 30000;
private final Space space;
private final ITaskStatus taskStatus;
private final List<ITaskOutput> taskOutput;
private final long taskId;
private transient EventListenerManager taskChangeListeners;
private transient Thread commitThread;
private transient volatile boolean commitThreadActive;
private transient volatile boolean taskOutputDirty;
TaskRecord(ITaskStatus status, Space space) {
this.space = space;
this.taskStatus = status;
this.taskOutput = new ArrayList<ITaskOutput>();
this.taskId = status.getTaskId();
space.getDatabase().store(this);
this.commitThreadActive = false;
}
public void updateTaskStatus(ITaskStatus newStatus) {
taskStatus.update(newStatus);
space.getDatabase().store(taskStatus);
space.updateTaskRecord(this);
if(commitThreadActive && (taskStatus.isFinished() || taskStatus.isFailed())) {
stopCommitThread();
}
}
public void addTaskOutputListener(IEventHandler handler) {
getEventManager().addListener(handler);
}
public void removeTaskOutputListener(IEventHandler handler) {
getEventManager().removeListener(handler);
}
private EventListenerManager getEventManager() {
if(taskChangeListeners == null) {
taskChangeListeners = new EventListenerManager();
}
return taskChangeListeners;
}
public List<ITaskOutput> getTaskOutput() {
return Collections.unmodifiableList(taskOutput);
}
public void addTaskOutput(final ITaskOutput output) {
taskOutput.add(output);
taskOutputDirty = true;
if(!commitThreadActive)
startCommitThread();
space.updateTaskRecord(this);
getEventManager().fireEvent(new ITaskOutputEvent() {
public ITaskOutput getMessage() {
return output;
}
});
}
/* Delegates to taskStatus */
public long getElapsedTime() {
return taskStatus.getElapsedTime();
}
public long getProbeId() {
return space.getProbeId();
}
public long getStartTime() {
return taskStatus.getStartTime();
}
public String getStateDescription() {
return taskStatus.getStateDescription();
}
/* Must not delegate to taskStatus or it will break the query optimizer */
public long getTaskId() {
return taskId;
}
public String getTitle() {
return taskStatus.getTitle();
}
public String getStatus() {
return taskStatus.getStatus();
}
public int getWorkDone() {
return taskStatus.getWorkDone();
}
public int getRunState() {
return taskStatus.getRunState();
}
public boolean isFailed() {
return taskStatus.isFailed();
}
public boolean isFinished() {
return taskStatus.isFinished();
}
public boolean isRunning() {
return taskStatus.isRunning();
}
public boolean isWaiting() {
return taskStatus.isWaiting();
}
private synchronized void startCommitThread() {
if(commitThreadActive) {
return;
}
commitThread = new Thread(new Runnable() {
public void run() {
while(commitThreadActive) {
try {
Thread.sleep(BACKGROUND_COMMIT_INTERVAL);
if(space.getDatabase().ext().isClosed()) {
commitThreadActive = false;
return;
} else {
runCommit();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
commitThreadActive = false;
} catch(DatabaseClosedException e) {
commitThreadActive = false;
return;
}
}
runCommit();
return;
}
});
commitThread.setDaemon(true);
if(getTitle() != null) {
commitThread.setName("Background Commit TaskRecord [" + getTitle() + "]");
} else {
commitThread.setName("Background Commit TaskRecord [taskId = " + taskId + "]");
}
commitThreadActive = true;
commitThread.start();
}
private synchronized void stopCommitThread() {
if(!commitThreadActive) {
return;
}
commitThreadActive = false;
commitThread.interrupt();
// try {
// commitThread.join();
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// }
commitThread = null;
}
private synchronized void runCommit() {
if(!taskOutputDirty)
return;
synchronized(taskOutput) {
space.getDatabase().store(taskOutput);
}
}
}