import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import jalview.bin.Cache;
import jalview.bin.Console;
private static final String oldTempFileSuffix = "_oldfile_tobedeleted";
+ // thread pool used for completablefutures
+ private static final ExecutorService executorService = Executors
+ .newFixedThreadPool(3);
+
+ private static List<BackupFiles> savesInProgress = new ArrayList<>();
+
+ private CompletableFuture<Boolean> myFuture = null;
+
+ private boolean addSaveInProgress()
+ {
+ if (savesInProgress.contains(this))
+ {
+ return false;
+ }
+ else
+ {
+ this.setMyFuture();
+ savesInProgress.add(this);
+ return true;
+ }
+ }
+
+ private boolean removeSaveInProgress(boolean ret)
+ {
+ if (savesInProgress.contains(this))
+ {
+ this.getMyFuture().complete(ret);
+ // remove all occurrences
+ while (savesInProgress.remove(this))
+ {
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private static CompletableFuture<Boolean> getNewFuture()
+ {
+ return new CompletableFuture<Boolean>()
+ {
+ };
+ }
+
+ private CompletableFuture<Boolean> getMyFuture()
+ {
+ return this.myFuture;
+ }
+
+ private void setMyFuture()
+ {
+ this.myFuture = getNewFuture();
+ }
+
+ public static boolean hasSavesInProgress()
+ {
+ boolean has = false;
+ for (CompletableFuture cf : savesInProgressCompletableFutures(true))
+ {
+ has |= !cf.isDone();
+ }
+ return has;
+ }
+
+ public static List<File> savesInProgressFiles(boolean all)
+ {
+ List<File> files = new ArrayList<>();
+ for (BackupFiles bfile : savesInProgress)
+ {
+ if (all || !bfile.getMyFuture().isDone())
+ files.add(bfile.getFile());
+ }
+ return files;
+ }
+
+ public static List<CompletableFuture<Boolean>> savesInProgressCompletableFutures(
+ boolean all)
+ {
+ List<CompletableFuture<Boolean>> cfs = new ArrayList<>();
+ for (BackupFiles bfile : savesInProgress)
+ {
+ if (all || !bfile.getMyFuture().isDone())
+ cfs.add(bfile.getMyFuture());
+ }
+ return cfs;
+ }
+
+ public static Future<Boolean> allSaved()
+ {
+ CompletableFuture<Boolean> f = new CompletableFuture<>();
+
+ executorService.submit(() -> {
+ for (BackupFiles buf : savesInProgress)
+ {
+ boolean allSaved = true;
+ try
+ {
+ allSaved &= buf.getMyFuture().get();
+ } catch (InterruptedException e)
+ {
+ Console.debug("InterruptedException waiting for files to save",
+ e);
+ } catch (ExecutionException e)
+ {
+ Console.debug("ExecutionException waiting for files to save", e);
+ }
+ f.complete(allSaved);
+ }
+ });
+ return f;
+ }
+
public BackupFiles(String filename)
{
this(new File(filename));
{
classInit();
this.file = file;
+
+ // add this file from the save in progress stack
+ addSaveInProgress();
+
BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
.getSavedBackupEntry();
this.suffix = bfpe.suffix;
{
String tempfilename = file.getName();
File tempdir = file.getParentFile();
+ tempdir.mkdirs();
Console.trace(
"BACKUPFILES [file!=null] attempting to create temp file for "
+ tempfilename + " in dir " + tempdir);
tidyUpFiles();
}
+ // remove this file from the save in progress stack
+ removeSaveInProgress(rename);
+
return rename;
}
return ret;
}
+ public File getFile()
+ {
+ return file;
+ }
+
public static boolean moveFileToFile(File oldFile, File newFile)
{
Console.initLogger();