Skip to content
Snippets Groups Projects
Commit ba9a586f authored by Jan Kožusznik's avatar Jan Kožusznik
Browse files

list of performed jobs

parent 8ba0b20f
No related branches found
No related tags found
No related merge requests found
package cz.it4i.fiji.haas;
import java.awt.Frame;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.scijava.Context;
import org.scijava.command.Command;
import org.scijava.log.LogService;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.ui.ApplicationFrame;
import org.scijava.ui.UIService;
import org.scijava.widget.UIComponent;
import cz.it4i.fiji.haas.JobManager.JobInfo;
import javafx.application.Platform;
import net.imagej.ImageJ;
/**
*
* @author koz01
......@@ -21,29 +29,55 @@ public class CheckStatusOfHaaS extends CommandBase implements Command {
@Parameter
private LogService log;
@Parameter(label="Work directory",persist=true)
@Parameter(label = "Work directory", persist = true, style = "directory")
private File workDirectory;
@Parameter(label="Work directory",persist=true,required = false)
private File workDirectory2;
@SuppressWarnings("unused")
@Parameter
private UIService uiService;
@Parameter
private Context context;
private JobManager jobManager;
@Override
public void run() {
try {
jobManager = new JobManager(getWorkingDirectoryPath(), getGate());
jobManager = new JobManager(getWorkingDirectoryPath(), context);
if (uiService.isHeadless()) {
downloadAll();
} else {
CheckStatusOfHaaSWindow window;
(window = new CheckStatusOfHaaSWindow(getFrame(),context)).setVisible(true);
Platform.runLater(() -> jobManager.getJobs().forEach(job -> window.addJob(job)));
}
} catch (IOException e) {
log.error(e);
}
}
private Frame getFrame() {
ApplicationFrame af = uiService.getDefaultUI().getApplicationFrame();
if (af instanceof Frame) {
return (Frame) af;
} else if (af instanceof UIComponent) {
Object component = ((UIComponent<?>) af).getComponent();
if (component instanceof Frame) {
return (Frame) component;
}
}
return null;
}
private void downloadAll() {
for (JobInfo id : jobManager.getJobsNeedingDownload()) {
System.out.println("Job " + id.getId() + " needs download");
jobManager.downloadJob(id.getId());
}
}
private Path getWorkingDirectoryPath() {
return Paths.get(workDirectory.toString());
}
......@@ -52,9 +86,8 @@ public class CheckStatusOfHaaS extends CommandBase implements Command {
// Launch ImageJ as usual.
final ImageJ ij = new ImageJ();
ij.launch(args);
//ij.command().run(CheckStatusOfHaaS.class, true);
// ij.command().run(CheckStatusOfHaaS.class, true);
}
}
package cz.it4i.fiji.haas;
import java.awt.Frame;
import org.scijava.Context;
import org.scijava.plugin.Parameter;
import cz.it4i.fiji.haas.JobManager.JobInfo;
import cz.it4i.fiji.haas.ui.CheckStatusOfHaaSController;
public class CheckStatusOfHaaSWindow extends FXFrame<CheckStatusOfHaaSController> {
private static final long serialVersionUID = 1L;
@Parameter
private Context context;
private CheckStatusOfHaaSController controller;
public CheckStatusOfHaaSWindow(Frame applicationFrame, Context context) {
super(applicationFrame,"/cz/it4i/fiji/haas/ui/CheckStatusOfHaaS.fxml");
this.context = context;
init(this::initController);
this.setResizable(false);
this.setTitle("Manage status of HaaS jobs");
}
public void addJob(JobInfo job) {
controller.addJob(job);
}
private void initController(CheckStatusOfHaaSController controller) {
this.controller = controller;
context.inject(controller);
controller.init();
}
}
package cz.it4i.fiji.haas;
import java.awt.Dimension;
import java.awt.Frame;
import java.io.IOException;
import java.net.URL;
import java.util.function.Consumer;
import javax.swing.JDialog;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class FXFrame<C> extends JDialog {
private static final long serialVersionUID = 1L;
private JFXPanel fxPanel;
private String fxmlFile;
private Consumer<C> controlerInit;
public FXFrame(String fxmlFile) {
this(null, fxmlFile);
}
public FXFrame(Frame applicationFrame, String string) {
super(applicationFrame);
fxmlFile = string;
}
/**
* Create the JFXPanel that make the link between Swing (IJ) and JavaFX plugin.
*/
protected void init( Consumer<C> controlerInit) {
this.controlerInit = controlerInit;
this.fxPanel = new JFXPanel();
this.add(this.fxPanel);
this.setVisible(true);
// The call to runLater() avoid a mix between JavaFX thread and Swing thread.
Platform.runLater(new Runnable() {
@Override
public void run() {
initFX(fxPanel);
}
});
}
private void initFX(JFXPanel fxPanel) {
// Init the root layout
try {
FXMLLoader loader = new FXMLLoader();
URL res = FXFrame.class.getResource(fxmlFile);
loader.setLocation(res);
Parent rootLayout = (Parent) loader.load();
// Get the controller and add an ImageJ context to it.
C controller = loader.<C>getController();
controlerInit.accept(controller);
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
this.fxPanel.setScene(scene);
this.fxPanel.setVisible(true);
// Resize the JFrame to the JavaFX scene
Dimension dim = new Dimension((int) scene.getWidth(), (int) scene.getHeight());
this.fxPanel.setMinimumSize(dim);
this.fxPanel.setMaximumSize(dim);
this.fxPanel.setPreferredSize(dim);
//this.setSize((int) scene.getWidth(), (int) scene.getHeight());
this.pack();
} catch (IOException e) {
e.printStackTrace();
}
}
}
......@@ -17,89 +17,109 @@ import cz.it4i.fiji.haas_java_client.JobState;
public class Job {
private static final String JOB_ID_PROPERTY = "job.id";
private static final String JOB_STATE_PROPERTY = "job.state";
private static final String JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY = "job.needDownload";
public static boolean isJobPath(Path p) {
return isValidPath(p);
}
private static String JOB_INFO_FILE = ".jobinfo";
private Path jobDir;
private Supplier<HaaSClient> haasClientSupplier;
private JobState state;
private ImageJGate gate;
public Job(Path path, Collection<Path> files, Supplier<HaaSClient> haasClientSupplier, ImageJGate gate) throws IOException {
this(haasClientSupplier,gate);
private Boolean needsDownload;
private Long jobId;
public Job(Path path, Collection<Path> files, Supplier<HaaSClient> haasClientSupplier)
throws IOException {
this(haasClientSupplier);
HaaSClient client = this.haasClientSupplier.get();
long id = client.start(files, "TestOutRedirect",
Collections.emptyList());
long id = client.start(files, "TestOutRedirect", Collections.emptyList());
jobDir = path.resolve("" + id);
Files.createDirectory(jobDir);
state = client.obtainJobInfo(id).getState();
saveJobinfo();
}
public Job(Path p, Supplier<HaaSClient> haasClientSupplier, ImageJGate gate) throws IOException {
this(haasClientSupplier,gate);
public Job(Path p, Supplier<HaaSClient> haasClientSupplier) throws IOException {
this(haasClientSupplier);
jobDir = p;
loadJobInfo();
checkStateForDownload();
updateState();
}
private Job(Supplier<HaaSClient> haasClientSupplier) {
this.haasClientSupplier = haasClientSupplier;
}
public boolean needsDownload() {
return needsDownload != null && needsDownload;
}
private synchronized void checkStateForDownload() throws IOException {
synchronized public long getJobId() {
if (jobId == null) {
jobId = getJobId(jobDir);
}
return jobId;
}
synchronized public void updateState() throws IOException {
long jobId = getJobId();
JobState actualState = haasClientSupplier.get().obtainJobInfo(jobId).getState();
gate.getLog().info("Job: " + jobId + " is " + actualState);
if(EnumSet.of(JobState.Failed, JobState.Finished, JobState.Canceled).contains(actualState) && state != actualState) {
gate.getLog().info("Downloading data.");
haasClientSupplier.get().download(jobId, jobDir);
if (EnumSet.of(JobState.Failed, JobState.Finished, JobState.Canceled).contains(actualState)
&& state != actualState) {
needsDownload = true;
state = actualState;
saveJobinfo();
}
}
private Job(Supplier<HaaSClient> haasClientSupplier, ImageJGate gate) {
this.haasClientSupplier = haasClientSupplier;
this.gate = gate;
synchronized public void download() {
if(!needsDownload()) {
throw new IllegalStateException("Job: " + getJobId() + " dosn't need download");
}
haasClientSupplier.get().download(getJobId(), jobDir);
needsDownload = false;
}
public JobState getState() {
return state;
}
private synchronized void saveJobinfo() throws IOException {
try(OutputStream ow= Files.newOutputStream(jobDir.resolve(JOB_INFO_FILE), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) {
try (OutputStream ow = Files.newOutputStream(jobDir.resolve(JOB_INFO_FILE),
StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) {
Properties prop = new Properties();
prop.setProperty(JOB_ID_PROPERTY, "" + getJobId());
prop.setProperty(JOB_STATE_PROPERTY, "" + state);
if (needsDownload != null) {
prop.setProperty(JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY, needsDownload.toString());
}
prop.store(ow, null);
}
}
private synchronized void loadJobInfo() throws IOException {
try(InputStream is= Files.newInputStream(jobDir.resolve(JOB_INFO_FILE))) {
try (InputStream is = Files.newInputStream(jobDir.resolve(JOB_INFO_FILE))) {
Properties prop = new Properties();
prop.load(is);
state = JobState.valueOf(prop.getProperty(JOB_STATE_PROPERTY));
assert getJobId() == Long.parseLong(prop.getProperty(JOB_ID_PROPERTY));
if (prop.containsKey(JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY)) {
needsDownload = Boolean.parseBoolean(prop.getProperty(JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY));
}
}
}
private long getJobId() {
return getJobId(jobDir);
}
private static boolean isValidPath(Path path) {
......
......@@ -4,28 +4,37 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import org.scijava.Context;
import cz.it4i.fiji.haas_java_client.HaaSClient;
import cz.it4i.fiji.haas_java_client.JobState;
public class JobManager {
private Path workDirectory;
private Collection<Job> jobs = new LinkedList<>();
private HaaSClient haasClient;
private ImageJGate gate;
private Context context;
public JobManager(Path workDirectory, ImageJGate gate) throws IOException {
public JobManager(Path workDirectory, Context ctx) throws IOException {
super();
this.gate = gate;
this.context = ctx;
this.workDirectory = workDirectory;
context.inject(this);
Files.list(this.workDirectory).filter(p -> Files.isDirectory(p) && Job.isJobPath(p))
.forEach(p -> {
try {
jobs.add(new Job(p,this::getHaasClient, gate));
jobs.add(inject(new Job(p,this::getHaasClient)));
} catch (IOException e) {
e.printStackTrace();
}
......@@ -33,8 +42,28 @@ public class JobManager {
}
private Job inject(Job job) {
context.inject(job);
return job;
}
public void startJob(Path path, Collection<Path> files) throws IOException {
jobs.add(new Job(path, files,this::getHaasClient,gate));
jobs.add(new Job(path, files,this::getHaasClient));
}
public Iterable<JobInfo> getJobsNeedingDownload() {
return ()->jobs.stream().filter(j->j.needsDownload()).map(j->new JobInfo(j)).iterator();
}
public Iterable<JobInfo> getJobs() {
return ()->jobs.stream().map(j->new JobInfo(j)).iterator();
}
public void downloadJob(Long id) {
Iterator<Job> job =jobs.stream().filter(j->j.getJobId() == id).iterator();
assert job.hasNext();
job.next().download();
}
private HaaSClient getHaasClient() {
......@@ -44,4 +73,25 @@ public class JobManager {
return haasClient;
}
public static class JobInfo {
private Job job;
public JobInfo(Job job) {
this.job = job;
}
public Long getId() {
return job.getJobId();
}
public JobState getState() {
return job.getState();
}
public boolean needsDownload() {
return job.needsDownload();
}
}
}
......@@ -8,6 +8,7 @@ import java.nio.file.Paths;
import java.util.Collection;
import java.util.stream.Collectors;
import org.scijava.Context;
import org.scijava.command.Command;
import org.scijava.log.LogService;
import org.scijava.plugin.Parameter;
......@@ -31,12 +32,15 @@ public class RunWithHaaS extends CommandBase implements Command {
@Parameter(label="Data directory")
private File dataDirectory;
@Parameter
private Context context;
private JobManager jobManager;
@Override
public void run() {
try {
jobManager = new JobManager(getWorkingDirectoryPath(), getGate());
jobManager = new JobManager(getWorkingDirectoryPath(), context);
jobManager.startJob(getWorkingDirectoryPath(),getContent(dataDirectory));
} catch (IOException e) {
log.error(e);
......
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.it4i.fiji.haas.ui.CheckStatusOfHaaSController">
<center>
<TableView fx:id="jobs" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn prefWidth="75.0" text="Job Id" />
<TableColumn prefWidth="145.0" text="Status" />
</columns>
</TableView>
</center>
</BorderPane>
package cz.it4i.fiji.haas.ui;
import org.scijava.log.LogService;
import org.scijava.plugin.Parameter;
import cz.it4i.fiji.haas.JobManager.JobInfo;
import javafx.beans.InvalidationListener;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.ContextMenuEvent;
import javafx.util.Callback;
public class CheckStatusOfHaaSController {
@Parameter
private LogService logService;
@FXML
private TableView<JobInfo> jobs;
public CheckStatusOfHaaSController() {
}
public void addJob(JobInfo job) {
jobs.getItems().add(job);
}
@SuppressWarnings("unchecked")
public void init() {
ContextMenu cm = new ContextMenu();
MenuItem download = new MenuItem("Download");
cm.getItems().add(download);
((TableColumn<JobInfo, String>)jobs.getColumns().get(0)).setCellValueFactory(new PropertyValueFactory<JobInfo,String>("id"));
((TableColumn<JobInfo, String>)jobs.getColumns().get(1)).setCellValueFactory(new P_Factory());
jobs.setContextMenu(cm);
jobs.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
@Override
public void handle(ContextMenuEvent event) {
if(jobs.getSelectionModel().getSelectedCells().size() < 1) {
return;
}
int row = jobs.getSelectionModel().getSelectedCells().get(0).getRow();
if(0 >= row && row < jobs.getItems().size() && jobs.getItems().get(row).needsDownload()) {
download.setDisable(false);
} else {
download.setDisable(true);
}
}
});
logService.info("init");
}
private class P_Factory implements Callback<CellDataFeatures<JobInfo, String>, ObservableValue<String>> {
@Override
public ObservableValue<String> call(final CellDataFeatures<JobInfo, String> param) {
return new ObservableValue<String>() {
@Override
public void addListener(InvalidationListener listener) {
}
@Override
public void removeListener(InvalidationListener listener) {
}
@Override
public void addListener(ChangeListener<? super String> listener) {
}
@Override
public void removeListener(ChangeListener<? super String> listener) {
}
@Override
public String getValue() {
JobInfo ji = param.getValue();
return ji.getState().toString() + (ji.needsDownload()?" - needs download":"");
}
};
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment