diff options
Diffstat (limited to 'src/main/java/com/keuin/kbackupfabric/operation/backup')
6 files changed, 57 insertions, 200 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java index 4e9eb6c..b65a076 100644 --- a/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java +++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java @@ -1,7 +1,6 @@ package com.keuin.kbackupfabric.operation.backup; -import com.keuin.kbackupfabric.util.backup.builder.BackupFileNameBuilder; -import com.keuin.kbackupfabric.util.backup.formatter.BackupFileNameFormatter; +import com.keuin.kbackupfabric.operation.backup.feedback.PrimitiveBackupFeedback; import java.io.IOException; @@ -16,29 +15,8 @@ public interface BackupMethod { * @param backupName the backup name. * @return if the backup operation succeed. */ - BackupResult backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException; + PrimitiveBackupFeedback backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException; boolean restore(String backupName, String levelPath, String backupSaveDirectory) throws IOException; - BackupFileNameBuilder getBackupFileNameBuilder(); - - BackupFileNameFormatter getBackupFileNameFormatter(); - - class BackupResult { - private final boolean success; - private final long backupSizeBytes; - - public BackupResult(boolean success, long backupSizeBytes) { - this.success = success; - this.backupSizeBytes = backupSizeBytes; - } - - public boolean isSuccess() { - return success; - } - - public long getBackupSizeBytes() { - return backupSizeBytes; - } - } } diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupMethod.java deleted file mode 100644 index 4a87bb3..0000000 --- a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupMethod.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.keuin.kbackupfabric.operation.backup; - -import com.google.gson.JsonObject; -import com.keuin.kbackupfabric.util.PrintUtil; -import com.keuin.kbackupfabric.util.backup.builder.BackupFileNameBuilder; -import com.keuin.kbackupfabric.util.backup.builder.ObjectTreeBackupFileNameBuilder; -import com.keuin.kbackupfabric.util.backup.formatter.BackupFileNameFormatter; -import com.keuin.kbackupfabric.util.backup.formatter.ObjectTreeBackupFileNameFormatter; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.time.LocalDateTime; - -public class IncrementalBackupMethod implements BackupMethod { - - private static final IncrementalBackupMethod INSTANCE = new IncrementalBackupMethod(); - - public static IncrementalBackupMethod getInstance() { - return INSTANCE; - } - - @Override - public BackupResult backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException { - /* - 1. Analyze the save directory, to get a json containing md5 values of all files. - 2. Copy new files which we do not have in our backup repository. - 3. Save the above json as a backup file. When restoring from this, - what we have to do is just copy all files back from the repository, - based on their md5 digests. - */ - - boolean success = true; - // Generate JSON - JsonObject hashJson = IncrementalBackupUtil.generateDirectoryJsonObject(levelPath); - // Copy files - long newFilesSizeBytes = IncrementalBackupUtil.saveNewFiles(backupSaveDirectory, levelPath, hashJson); - if(newFilesSizeBytes < 0) { - success = false; - PrintUtil.error("Failed to copy new files to object tree."); - } - // Save JSON tree - File jsonFile = new File(String.valueOf(Paths.get(backupSaveDirectory, BackupFileNameBuilder.objectTreeBackup().build(LocalDateTime.now(), backupName)))); - // TODO - return new BackupResult(success, newFilesSizeBytes); - } - - @Override - public boolean restore(String backupName, String levelPath, String backupSaveDirectory) throws IOException { - return false; - } - - @Override - public BackupFileNameBuilder getBackupFileNameBuilder() { - return null; - } - - @Override - public BackupFileNameFormatter getBackupFileNameFormatter() { - return null; - } -} diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupUtil.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupUtil.java deleted file mode 100644 index f90aef1..0000000 --- a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupUtil.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.keuin.kbackupfabric.operation.backup; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.keuin.kbackupfabric.util.FilesystemUtil; -import org.apache.commons.codec.digest.DigestUtils; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.*; -import java.util.Map; - -public class IncrementalBackupUtil { - /** - * Generate a json object representing a directory and its all sub files and directories. - * @param path path to the directory. - * @return a json object. - */ - public static JsonObject generateDirectoryJsonObject(String path) throws IOException { - JsonObject json = new JsonObject(); - File directory = new File(path); - if (!(directory.isDirectory() && directory.exists())) - throw new IOException(String.format("Path %s is not a valid directory.", path)); - - // Iterate all sub files using BFS. - try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(path))) { - for (Path sub : directoryStream) { - if (sub.toFile().isFile()) { - // A sub file - // Just hash and add it as a string - try (InputStream is = Files.newInputStream(sub)) { - String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is); - json.addProperty(sub.getFileName().toString(), md5); - } - } else { - // A sub directory - // Search into - json.addProperty(String.valueOf(sub.getFileName()), sub.toString()); - } - } - } - - return json; - } - - /** - * Save new (or modified) files to target path, based on hash json. - * @param targetSavePath where we should save new files. - * @param sourcePath where new files come from. This path must be the base directory of given hash json. - * @param hashJson the json object obtained by calling generateDirectoryJsonObject method. - * @return total size of new files. If failed, will return -1. - */ - public static long saveNewFiles(String targetSavePath, String sourcePath, JsonObject hashJson) throws IOException { - long bytesCopied = 0; - for (Map.Entry<String, JsonElement> entry : hashJson.entrySet()) { - String key = entry.getKey(); - JsonElement value = entry.getValue(); - if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) { - // A sub file - // key is file name - // value is file md5 - String md5 = value.getAsJsonPrimitive().getAsString(); - File saveTarget = new File(targetSavePath, md5); - if (!saveTarget.exists()) { - // Target file does not exist. We have to copy this to the target. - File sourceFile = new File(sourcePath, key); - Files.copy(sourceFile.toPath(), saveTarget.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); - try { - bytesCopied += sourceFile.length(); - } catch (SecurityException ignored) { - // failed to get the file size. Just ignore this. - } - } - } else if (value.isJsonObject()) { - // A sub directory - // key is directory name - // value is directory json object - // Go into - if(!value.isJsonObject()) - throw new IllegalArgumentException(String.format("Hash json contains illegal argument of a directory item: %s -> %s.", key, value)); - Path pathSource = Paths.get(sourcePath, key); - bytesCopied += saveNewFiles(targetSavePath, pathSource.toString(), value.getAsJsonObject()); - } else { - throw new IllegalArgumentException(String.format("Hash json contains illegal element: %s -> %s.", key, value)); - } - } - return bytesCopied; - } -} diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java index 854355d..9c065a6 100644 --- a/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java +++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java @@ -2,11 +2,13 @@ package com.keuin.kbackupfabric.operation.backup; import com.keuin.kbackupfabric.exception.ZipUtilException; import com.keuin.kbackupfabric.metadata.BackupMetadata; +import com.keuin.kbackupfabric.operation.backup.feedback.PrimitiveBackupFeedback; import com.keuin.kbackupfabric.util.FilesystemUtil; import com.keuin.kbackupfabric.util.PrintUtil; import com.keuin.kbackupfabric.util.ZipUtil; -import com.keuin.kbackupfabric.util.backup.builder.BackupFileNameBuilder; -import com.keuin.kbackupfabric.util.backup.formatter.BackupFileNameFormatter; +import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil; +import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter; +import com.keuin.kbackupfabric.util.backup.name.PrimitiveBackupFileNameEncoder; import java.io.File; import java.io.IOException; @@ -23,27 +25,32 @@ public class PrimitiveBackupMethod implements BackupMethod { return INSTANCE; } + @Deprecated + private String getBackupFileName(LocalDateTime time, String backupName) { + String timeString = BackupNameTimeFormatter.localDateTimeToString(time); + return String.format("%s%s_%s%s", BackupFilesystemUtil.getBackupFileNamePrefix(), timeString, backupName, ".zip"); + } + @Override - public BackupResult backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException { - String backupFileName = BackupFileNameBuilder.primitiveZipBackup().build(LocalDateTime.now(),backupName); + public PrimitiveBackupFeedback backup(String customBackupName, String levelPath, String backupSavePath) throws IOException { +// String backupFileName = getBackupFileName(LocalDateTime.now(),backupName); + String backupFileName = new PrimitiveBackupFileNameEncoder().encode(customBackupName, LocalDateTime.now()); try { - BackupMetadata backupMetadata = new BackupMetadata(System.currentTimeMillis(), backupName); - - PrintUtil.info(String.format("zip(srcPath=%s, destPath=%s)", levelPath, backupSaveDirectory)); + BackupMetadata backupMetadata = new BackupMetadata(System.currentTimeMillis(), customBackupName); + PrintUtil.info(String.format("zip(srcPath=%s, destPath=%s)", levelPath, backupSavePath)); PrintUtil.info("Compressing level ..."); - ZipUtil.makeBackupZip(levelPath, backupSaveDirectory, backupFileName, backupMetadata); - + ZipUtil.makeBackupZip(levelPath, backupSavePath, backupFileName, backupMetadata); } catch (ZipUtilException exception) { PrintUtil.info("Infinite recursive of directory tree detected, backup was aborted."); - return new BackupResult(false, 0); + return new PrimitiveBackupFeedback(false, 0); } // Get backup file size and return - return new BackupResult(true, FilesystemUtil.getFileSizeBytes(backupSaveDirectory, backupFileName)); + return new PrimitiveBackupFeedback(true, FilesystemUtil.getFileSizeBytes(backupSavePath, backupFileName)); } @Override - public boolean restore(String backupName, String levelDirectory, String backupSaveDirectory) throws IOException { + public boolean restore(String backupFileName, String levelDirectory, String backupSaveDirectory) throws IOException { // Delete old level PrintUtil.info("Server stopped. Deleting old level ..."); File levelDirFile = new File(levelDirectory); @@ -73,10 +80,10 @@ public class PrimitiveBackupMethod implements BackupMethod { // TODO: Refactor this to the concrete BackupMethod. // Decompress archive PrintUtil.info("Decompressing archived level ..."); - ZipUtil.unzip(Paths.get(backupSaveDirectory, backupName).toString(), levelDirectory, false); + ZipUtil.unzip(Paths.get(backupSaveDirectory, backupFileName).toString(), levelDirectory, false); long endTime = System.currentTimeMillis(); PrintUtil.info(String.format("Restore complete! (%.2fs) Please restart the server manually.", (endTime - startTime) / 1000.0)); - PrintUtil.info("If you want to restart automatically after restoring, please visit the project manual at: https://github.com/keuin/KBackup-Fabric/blob/master/README.md"); + PrintUtil.info("If you want to restart automatically after restoring, please check the manual at: https://github.com/keuin/KBackup-Fabric/blob/master/README.md"); // try { // Thread.sleep(1000); @@ -85,14 +92,4 @@ public class PrimitiveBackupMethod implements BackupMethod { return true; } - - @Override - public BackupFileNameBuilder getBackupFileNameBuilder() { - return BackupFileNameBuilder.primitiveZipBackup(); - } - - @Override - public BackupFileNameFormatter getBackupFileNameFormatter() { - return BackupFileNameFormatter.primitiveZipBackup(); - } } diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/BackupFeedback.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/BackupFeedback.java new file mode 100644 index 0000000..92a9f39 --- /dev/null +++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/BackupFeedback.java @@ -0,0 +1,5 @@ +package com.keuin.kbackupfabric.operation.backup.feedback; + +public interface BackupFeedback { + String getFeedback(); +} diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/PrimitiveBackupFeedback.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/PrimitiveBackupFeedback.java new file mode 100644 index 0000000..6d7a15b --- /dev/null +++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/PrimitiveBackupFeedback.java @@ -0,0 +1,29 @@ +package com.keuin.kbackupfabric.operation.backup.feedback; + +import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getFriendlyFileSizeString; + +public class PrimitiveBackupFeedback implements BackupFeedback { + private final boolean success; + private final long backupSizeBytes; + + public PrimitiveBackupFeedback(boolean success, long backupSizeBytes) { + this.success = success; + this.backupSizeBytes = backupSizeBytes; + } + + public boolean isSuccess() { + return success; + } + + public long getBackupSizeBytes() { + return backupSizeBytes; + } + + @Override + public String getFeedback() { + if (success && backupSizeBytes >= 0) + return String.format(" File size: %s.", getFriendlyFileSizeString(backupSizeBytes)); + else + return ""; + } +} |