diff --git a/src/main/java/net/imagej/legacy/task/TaskHelper.java b/src/main/java/net/imagej/legacy/task/TaskHelper.java new file mode 100644 index 000000000..54e3d4a2b --- /dev/null +++ b/src/main/java/net/imagej/legacy/task/TaskHelper.java @@ -0,0 +1,246 @@ +package net.imagej.legacy.task; + +import net.imagej.legacy.LegacyService; +import org.scijava.log.LogService; +import org.scijava.object.ObjectService; +import org.scijava.task.Task; +import org.scijava.task.TaskService; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Static methods enabling the use of {@link Task} in ImageJ macro language through the call method: + * output = call('net.imagej.legacy.task.Taskhelper.METHODNAME', args, ...); + * where METHODNAME belong to the {@link Task} interface + *

+ * The ObjectService is used to store tasks created using this static class (within {@link TaskHelper#createTask(String)}) + * Tasks are removed from the ObjectService when {@link TaskHelper#finish(String)} is called. + *

+ * Using this class, it is possible to create two tasks with the same name. Name uniqueness is not guaranteed. + * If two tasks with the same name exist in the ObjectService, a warning message will be displayed via the + * {@link LogService}. It is possible to clear all tasks present in the ObjectService with a specific name + * using {@link TaskHelper#removeAll(String)}. This may be necessary to remove dangling tasks existing after + * a macro has not not been completed successfully, or in the case where calling task.finish was forgotten. + *

+ * The {@link LogService} and {@link ObjectService} are accessed + * statically via the {@link LegacyService}, where a single instance can exist anyway. + *

+ * @author Nicolas Chiaruttini, EPFL, 2023 + */ +@SuppressWarnings("unused") +public class TaskHelper { + + // Since the LegacyService exists only once, the LogService and the ObjectService can be accessed statically + private static volatile LogService logService; + private static volatile ObjectService objectService; + private static volatile TaskService taskService; + public static LogService logService() { + if (logService == null) { + synchronized (LogService.class) { + if (logService == null) { + logService = LegacyService.getInstance().log(); + } + } + } + return logService; + } + + public static ObjectService objectService() { + if (objectService == null) { + synchronized (ObjectService.class) { + if (objectService == null) { + objectService = LegacyService.getInstance().context().getService(ObjectService.class); + } + } + } + return objectService; + } + + public static TaskService taskService() { + if (taskService == null) { + synchronized (TaskService.class) { + if (taskService == null) { + taskService = LegacyService.getInstance().context().getService(TaskService.class); + } + } + } + return taskService; + } + + + private static Task getTaskNamed(String name) throws IllegalArgumentException { + + List tasks = objectService().getObjects(Task.class) + .stream() + .filter(task -> task.getName().equals(name)).collect(Collectors.toList()); + + if (tasks.size() == 0) { + throw new IllegalArgumentException("No task named "+name+" was found in the object service."); + } + + if (tasks.size() > 1) { + logService().warn("Multiple tasks named "+name+" found! Taking the first one."); + } + + return tasks.get(0); + } + + private static List getTasksNamed(String name) { + return objectService().getObjects(Task.class) + .stream() + .filter(task -> task.getName().equals(name)).collect(Collectors.toList()); + } + + /** + * Returns true as a String if the (first) task named taskName found in the {@link ObjectService} has been cancelled + * Returns false as a String if the (first) task named taskName found in the {@link ObjectService} has not been cancelled + * @param taskName name of the task to act on + * @return true or false as String depending on whether the task named taskName has been cancelled + */ + public static String isCanceled(String taskName) { + try { + Task task = getTaskNamed(taskName); + return task.isCanceled()?"true":"false"; + } catch (IllegalArgumentException e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + return "Error: task not found. ("+e.getMessage()+")"; + } + } + + /** + * Returns {@link Task#getCancelReason()} on the (first) task named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + * @return the cancellation reason of the task named taskName + */ + public static String getCancelReason(String taskName) { + try { + Task task = getTaskNamed(taskName); + return task.getCancelReason(); + } catch (IllegalArgumentException e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + return "Error: task not found. ("+e.getMessage()+")"; + } + } + + /** + * Creates a new {@link Task} named taskNamer and stores it into {@link ObjectService} + * @param taskName name of the task to act on + */ + public static void createTask(String taskName) { + Task task = taskService().createTask(taskName); + objectService().addObject(task); + } + + /** + * Sets the maximal progression of the first task {@link Task} named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + * @param max the progression maximum (when the task is done) + */ + public static void setProgressMaximum(String taskName, String max) { + try { + Task task = getTaskNamed(taskName); + task.setProgressMaximum(Long.parseLong(max)); + } catch (IllegalArgumentException e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + } + } + + /** + * Returns {@link Task#getProgressMaximum()} on the (first) task named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + * @return the current maximal progression of the task named taskName + */ + public static String getProgressMaximum(String taskName) { + try { + Task task = getTaskNamed(taskName); + return Long.toString(task.getProgressMaximum()); + } catch (Exception e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + return "task "+taskName+" not found."; + } + } + + /** + * Sets the status message of the first task {@link Task} named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + * @param status the status message to set + */ + public static void setStatusMessage(String taskName, String status) { + try { + Task task = getTaskNamed(taskName); + task.setStatusMessage(status); + } catch (Exception e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + } + } + + /** + * Returns {@link Task#getStatusMessage()} on the (first) task named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + * @return the current status message of the task named taskName + */ + public static String getStatusMessage(String taskName) { + try { + Task task = getTaskNamed(taskName); + return task.getStatusMessage(); + } catch (Exception e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + return "task "+taskName+" not found."; + } + } + + /** + * Calls {@link Task#start()} on the (first) task named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + */ + public static void start(String taskName) { + try { + Task task = getTaskNamed(taskName); + task.start(); + } catch (Exception e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + } + } + + /** + * Calls {@link Task#setProgressValue(long)} on the (first) task named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + * @param step the current task progression value + */ + public static void setProgressValue(String taskName, String step) { + try { + Task task = getTaskNamed(taskName); + task.setProgressValue(Long.parseLong(step)); + } catch (Exception e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + } + } + + /** + * Calls {@link Task#finish()} on the (first) task named taskName found in the {@link ObjectService} + * @param taskName name of the task to act on + */ + public static void finish(String taskName) { + try { + Task task = getTaskNamed(taskName); + task.finish(); + objectService().removeObject(task); + } catch (Exception e) { + logService().error("Error: task not found. ("+e.getMessage()+")"); + } + } + + /** + * Clean up method to removes tasks dangling after a macro has crashed. + * If several tasks exist with the same name, they will all be removed + * @param taskName name of the tasks to remove + */ + public static void removeAll(String taskName) { + for (Task task: getTasksNamed(taskName)) { + task.finish(); + objectService().removeObject(task); + } + } + +} diff --git a/src/main/resources/script_templates/ImageJ_1.x/Task/SimpleTask.groovy b/src/main/resources/script_templates/ImageJ_1.x/Task/SimpleTask.groovy new file mode 100644 index 000000000..a18fb84f3 --- /dev/null +++ b/src/main/resources/script_templates/ImageJ_1.x/Task/SimpleTask.groovy @@ -0,0 +1,22 @@ +#@ TaskService taskService +#@ Double (label = "Waiting time per step (s)", style = "0.000", value = "0.5") wait_s +#@ Integer(label = "Number of steps", value = "20") n_steps + +def task = taskService.createTask("A task"); +task.setProgressMaximum(n_steps) + +try { + + task.start() + //... do stuff + for (int i = 0; i