/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.sa.engine;
import com.emc.storageos.db.client.model.uimodels.ExecutionTaskLog;
import com.emc.vipr.client.Task;
import com.emc.vipr.client.exceptions.TimeoutException;
/**
* Wrapper around a ViPR Task that allows for monitoring progress and updating the execution logs on success/failure.
*
* @param <T>
* the result type of the ViPR task.
*/
public class ViPRTaskMonitor<T> {
private final ExecutionContext context;
private final ExecutionTaskLog log;
private final Task<T> task;
/** Whether the task has been completed. */
private boolean complete;
/** The result of the task. */
private T value;
/** The error if the task failed. */
private ExecutionException error;
public ViPRTaskMonitor(ExecutionContext context, ExecutionTaskLog log, Task<T> task) {
this.context = context;
this.log = log;
this.task = task;
}
/**
* Waits until the task completes. This is equivalent to {@code waitFor(-1)}.
*/
public void waitFor() {
waitFor(-1);
}
/**
* Waits until the task completes or the specified timeout (millis), whichever is first.
*
* @param timeout
* the maximum time to wait.
* @return whether the task completed or not.
*/
public boolean waitFor(long timeout) {
if (!complete) {
try {
value = task.get(timeout);
complete = true;
context.updateTaskLog(log, elapsedTime());
} catch (TimeoutException e) {
// Ignore
} catch (Exception e) {
error = new ExecutionException(e);
complete = true;
context.updateTaskLog(log, elapsedTime(), e);
}
}
return complete;
}
/**
* Checks the task for complete. If the task has already completed this will return right away, otherwise the task
* is refreshed and checked for complete.
*
* @return whether the task is completed.
*/
public boolean check() {
if (!complete) {
try {
task.refresh();
complete = task.isComplete();
if (complete) {
value = task.get();
}
context.updateTaskLog(log, elapsedTime());
} catch (TimeoutException e) {
// Ignore
} catch (Exception e) {
error = new ExecutionException(e);
complete = true;
context.updateTaskLog(log, elapsedTime(), e);
}
}
return complete;
}
/**
* Determines if the task is complete (success or failure).
*
* @return whether the task is complete.
*/
public boolean isComplete() {
return complete;
}
/**
* Determines if the task completed successfully.
*
* @return whether the task completed successfully.
*/
public boolean isSuccess() {
return complete && (error == null);
}
/**
* Determines if the task completed with an error.
*
* @return whether the task completed with an error.
*/
public boolean isError() {
return error != null;
}
/**
* Gets the underlying ViPR task.
*
* @return the task.
*/
public Task<T> getTask() {
return task;
}
/**
* Gets the error wrapping the thrown error (if the task completed in error).
*
* @return the error.
*/
public ExecutionException getError() {
return error;
}
/**
* Waits for the task to complete and returns the result of the task. If the task fails the error is thrown.
*
* @return the value
*
* @throws ExecutionException
* if the task failed.
*/
public T getValue() {
waitFor();
if (error != null) {
throw error;
}
return value;
}
/**
* Gets the elapsed time of the task, or the elapsed time to now if the task has not yet completed.
*
* @return the elapsed time of the task.
*/
private long elapsedTime() {
long startTime = log.getDate().getTime();
if (task.getEndTime() != null) {
return task.getEndTime().getTimeInMillis() - startTime;
}
else {
return System.currentTimeMillis() - startTime;
}
}
}