import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Map;
import java.util.TreeMap;
/*
* BackupFiles used for manipulating (naming rolling/deleting) backup/version files when an alignment or project file is saved.
* User configurable options are:
* BACKUPFILES_ENABLED - boolean flag as to whether to use this mechanism or act as before, including overwriting files as saved.
- * BACKUPFILES_SUFFIX - a template to insert just before the file extension. Use '%n' to be replaced by a 0-led SUFFIX_DIGITS long integer.
+ * BACKUPFILES_SUFFIX - a template to insert after the file extension. Use '%n' to be replaced by a 0-led SUFFIX_DIGITS long integer.
* BACKUPFILES_NO_MAX - flag to turn off setting a maximum number of backup files to keep.
* BACKUPFILES_ROLL_MAX - the maximum number of backupfiles to keep for any one alignment or project file.
* BACKUPFILES_SUFFIX_DIGITS - the number of digits to insert replace %n with (e.g. BACKUPFILES_SUFFIX_DIGITS = 3 would make "001", "002", etc)
{
// labels for saved params in Cache and .jalview_properties
- private static String NS = "BACKUPFILES";
+ public static final String NS = "BACKUPFILES";
- public static String ENABLED = NS + "_ENABLED";
+ public static final String ENABLED = NS + "_ENABLED";
- public static String SUFFIX = NS + "_SUFFIX";
+ public static final String SUFFIX = NS + "_SUFFIX";
- public static String NO_MAX = NS + "_NO_MAX";
+ public static final String NO_MAX = NS + "_NO_MAX";
- public static String ROLL_MAX = NS + "_ROLL_MAX";
+ public static final String ROLL_MAX = NS + "_ROLL_MAX";
- public static String SUFFIX_DIGITS = NS + "_SUFFIX_DIGITS";
+ public static final String SUFFIX_DIGITS = NS + "_SUFFIX_DIGITS";
- protected static String NUM_PLACEHOLDER = "%n";
+ public static final String NUM_PLACEHOLDER = "%n";
- public static String REVERSE_ORDER = NS + "_REVERSE_ORDER";
+ public static final String REVERSE_ORDER = NS + "_REVERSE_ORDER";
- public static String CONFIRM_DELETE_OLD = NS + "_CONFIRM_DELETE_OLD";
+ public static final String CONFIRM_DELETE_OLD = NS
+ + "_CONFIRM_DELETE_OLD";
- private static String DEFAULT_TEMP_FILE = "jalview_temp_file_" + NS;
+ private static final String DEFAULT_TEMP_FILE = "jalview_temp_file_" + NS;
+
+ private static final String TEMP_FILE_EXT = ".tmp";
// file - File object to be backed up and then updated (written over)
private File file;
// deleting old backup/version files
private static boolean confirmDelete;
- private static boolean classInit = false;
-
// defaultSuffix - default template to use to append to basename of file
private String suffix;
// REVERSE_ORDER
public BackupFiles(File file)
{
- this(file, "-v" + NUM_PLACEHOLDER, false, 4, 3, false);
+ this(file, ".bak" + NUM_PLACEHOLDER, false, 3, 3, false);
}
- public BackupFiles(File file,
- String defaultSuffix, boolean defaultNoMax, int defaultMax,
- int defaultDigits,
- boolean defaultReverseOrder)
+ public BackupFiles(File file, String defaultSuffix, boolean defaultNoMax,
+ int defaultMax, int defaultDigits, boolean defaultReverseOrder)
{
classInit();
this.file = file;
{
String tempfilename = file.getName();
File tempdir = file.getParentFile();
- temp = File.createTempFile(tempfilename, ".tmp", tempdir);
+ temp = File.createTempFile(tempfilename, TEMP_FILE_EXT, tempdir);
}
else
{
- temp = File.createTempFile(DEFAULT_TEMP_FILE, ".tmp");
+ temp = File.createTempFile(DEFAULT_TEMP_FILE, TEMP_FILE_EXT);
}
} catch (IOException e)
{
public static void classInit()
{
- if (!classInit)
- {
- setEnabled(Cache.getDefault(ENABLED, true));
- setConfirmDelete(Cache.getDefault(CONFIRM_DELETE_OLD, true));
- classInit = true;
- }
+ setEnabled(Cache.getDefault(ENABLED, true));
+ setConfirmDelete(Cache.getDefault(CONFIRM_DELETE_OLD, true));
}
public static void setEnabled(boolean flag)
return path;
}
- public static String getNumPlaceHolder()
- {
- return NUM_PLACEHOLDER;
- }
-
public boolean setWriteSuccess(boolean flag)
{
boolean old = this.tempFileWriteSuccess;
return tempFile.renameTo(file);
}
-
// roll the backupfiles
public boolean rollBackupFiles()
{
- // file doesn't yet exist or backups are not enabled
- if ((!file.exists()) || (!enabled) || (max < 0))
+ // file doesn't yet exist or backups are not enabled or template is null or
+ // empty
+ if ((!file.exists()) || (!enabled) || max < 0 || suffix == null
+ || suffix.length() == 0)
{
// nothing to do
return true;
}
- // split filename up to insert suffix template in the right place. template
- // and backupMax can be set in .jalview_properties
String dir = "";
File dirFile;
try
}
String filename = file.getName();
String basename = filename;
- String extension = "";
- int dotcharpos = filename.lastIndexOf('.');
- // don't split of filenames with the last '.' at the very beginning or
- // very end of the filename
- if ((dotcharpos > 0) && (dotcharpos < filename.length() - 1))
- {
- basename = filename.substring(0, dotcharpos);
- extension = filename.substring(dotcharpos); // NOTE this includes the '.'
- }
boolean ret = true;
// Create/move backups up one
File[] oldFilesToDelete = null;
-
+
// find existing backup files
BackupFilenameFilter bff = new BackupFilenameFilter(basename, suffix,
- digits,
- extension);
+ digits);
File[] backupFiles = dirFile.listFiles(bff);
int nextIndexNum = 0;
String confirmDeleteExtraInfo = null;
-
+
if (backupFiles.length == 0)
{
// No other backup files. Just need to move existing file to backupfile_1
}
else
{
-
- // sort the backup files (based on integer found in the suffix) using a
- // precomputed Hashmap for speed
- HashMap<Integer, File> bfHashMap = new HashMap<>();
- for (int i = 0; i < backupFiles.length; i++)
- {
- File f = backupFiles[i];
- BackupFilenameParts bfp = new BackupFilenameParts(f, basename, suffix, digits, extension);
- bfHashMap.put(bfp.indexNum(), f);
- }
- TreeMap<Integer, File> bfTreeMap = new TreeMap<>();
- bfTreeMap.putAll(bfHashMap);
+ TreeMap<Integer, File> bfTreeMap = sortBackupFilesAsTreeMap(
+ backupFiles, basename);
if (reverseOrder)
{
{
// int n = tempMax - m;
String backupfilename = dir + File.separatorChar
- + BackupFilenameFilter.getBackupFilename(n, basename,
- suffix, digits, extension);
+ + BackupFilenameParts.getBackupFilename(n, basename,
+ suffix, digits);
File backupfile_n = new File(backupfilename);
if (!backupfile_n.exists())
// if (m == 0 && backupfile_n.exists())
if ((!noMax) && n == tempMax && backupfile_n.exists())
{
- // move the largest (max) rolled file to a temp file and add to the delete list
+ // move the largest (max) rolled file to a temp file and add to the
+ // delete list
try
{
- File temp = File.createTempFile(backupfilename, ".tmp",
- dirFile);
+ File temp = File.createTempFile(backupfilename, TEMP_FILE_EXT,
+ dirFile);
backupfile_n.renameTo(temp);
oldFilesToDelete = new File[] { temp };
// version style numbering (with earliest file deletion if max files
// reached)
-
bfTreeMap.values().toArray(backupFiles);
// noMax == true means keep all backup files
}
}
+ deleteOldFiles(oldFilesToDelete, confirmDeleteExtraInfo);
+
+ // Let's make the new backup file!! yay, got there at last!
+ String latestBackupFilename = dir + File.separatorChar
+ + BackupFilenameParts.getBackupFilename(nextIndexNum, basename,
+ suffix, digits);
+ File latestBackupFile = new File(latestBackupFilename);
+ ret = ret && file.renameTo(latestBackupFile);
+
+ return ret;
+ }
+
+ private void deleteOldFiles(File[] oldFilesToDelete,
+ String confirmDeleteExtraInfo)
+ {
if (oldFilesToDelete != null && oldFilesToDelete.length > 0)
{
// delete old backup/version files
boolean delete = false;
if (confirmDelete)
{
- // Object[] confirmMessageArray = {};
StringBuilder confirmMessage = new StringBuilder();
confirmMessage.append(MessageManager
.getString("label.backupfiles_confirm_delete_old_files"));
}
}
+ }
- // Let's make the new backup file!! yay, got there at last!
- String latestBackupFilename = dir + File.separatorChar
- + BackupFilenameFilter.getBackupFilename(nextIndexNum, basename,
- suffix, digits, extension);
- File latestBackupFile = new File(latestBackupFilename);
- ret = ret && file.renameTo(latestBackupFile);
-
- return ret;
+ private TreeMap<Integer, File> sortBackupFilesAsTreeMap(
+ File[] backupFiles,
+ String basename)
+ {
+ // sort the backup files (based on integer found in the suffix) using a
+ // precomputed Hashmap for speed
+ Map<Integer, File> bfHashMap = new HashMap<>();
+ for (int i = 0; i < backupFiles.length; i++)
+ {
+ File f = backupFiles[i];
+ BackupFilenameParts bfp = new BackupFilenameParts(f, basename, suffix,
+ digits);
+ bfHashMap.put(bfp.indexNum(), f);
+ }
+ TreeMap<Integer, File> bfTreeMap = new TreeMap<>();
+ bfTreeMap.putAll(bfHashMap);
+ return bfTreeMap;
}
public boolean rollBackupsAndRenameTempFile()
{
boolean write = this.getWriteSuccess();
-
+
boolean roll = false;
- if (write) {
+ if (write)
+ {
roll = this.rollBackupFiles();
- } else {
+ }
+ else
+ {
return false;
}
-
+
/*
* Not sure that this confirmation is desirable. By this stage the new file is
* already written successfully, but something (e.g. disk full) has happened while
int confirm = JvOptionPane.showConfirmDialog(Desktop.desktop,
MessageManager.getString(
"label.backupfiles_confirm_save_file_backupfiles_roll_wrong"),
- MessageManager.getString("label.backupfiles_confirm_save_file"),
+ MessageManager
+ .getString("label.backupfiles_confirm_save_file"),
JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE);
if (confirm == JvOptionPane.YES_OPTION)
return rename;
}
-}
+ public static TreeMap<Integer, File> getBackupFilesAsTreeMap(
+ String fileName, String suffix, int digits)
+ {
+ File[] backupFiles = null;
+
+ File file = new File(fileName);
+ File dirFile;
+ try
+ {
+ dirFile = file.getParentFile();
+ } catch (Exception e)
+ {
+ System.out.println(
+ "Could not get canonical path for file '" + file + "'");
+ return new TreeMap<>();
+ }
+
+ String filename = file.getName();
+ String basename = filename;
+
+ // find existing backup files
+ BackupFilenameFilter bff = new BackupFilenameFilter(basename, suffix,
+ digits);
+ backupFiles = dirFile.listFiles(bff); // is clone needed?
+
+ // sort the backup files (based on integer found in the suffix) using a
+ // precomputed Hashmap for speed
+ Map<Integer, File> bfHashMap = new HashMap<>();
+ for (int i = 0; i < backupFiles.length; i++)
+ {
+ File f = backupFiles[i];
+ BackupFilenameParts bfp = new BackupFilenameParts(f, basename, suffix,
+ digits);
+ bfHashMap.put(bfp.indexNum(), f);
+ }
+ TreeMap<Integer, File> bfTreeMap = new TreeMap<>();
+ bfTreeMap.putAll(bfHashMap);
+
+ return bfTreeMap;
+ }
+
+}