summaryrefslogtreecommitdiff
path: root/src/main/java/com/keuin/kbackupfabric/operation
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/keuin/kbackupfabric/operation')
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/AbstractConfirmableOperation.java20
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java105
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java27
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java92
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractAsyncOperation.java53
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractBlockingOperation.java58
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractConfirmableOperation.java11
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractSerializedOperation.java12
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncBlockingOperation.java66
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncOperation.java32
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableBlockingOperation.java39
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableOperation.java9
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Blocking.java5
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Invokable.java5
14 files changed, 496 insertions, 38 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/AbstractConfirmableOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/AbstractConfirmableOperation.java
deleted file mode 100644
index d666a34..0000000
--- a/src/main/java/com/keuin/kbackupfabric/operation/AbstractConfirmableOperation.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.keuin.kbackupfabric.operation;
-
-import com.mojang.brigadier.context.CommandContext;
-import net.minecraft.server.command.ServerCommandSource;
-
-public abstract class AbstractConfirmableOperation {
-
- public static AbstractConfirmableOperation createRestoreOperation(CommandContext<ServerCommandSource> context, String backupName) {
- return new RestoreOperation(context, backupName);
- }
-
- public static AbstractConfirmableOperation createDeleteOperation(CommandContext<ServerCommandSource> context, String backupName) {
- return new DeleteOperation(context, backupName);
- }
-
- public abstract boolean confirm();
-
- @Override
- public abstract String toString();
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
new file mode 100644
index 0000000..7d3a508
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
@@ -0,0 +1,105 @@
+package com.keuin.kbackupfabric.operation;
+
+import com.keuin.kbackupfabric.metadata.BackupMetadata;
+import com.keuin.kbackupfabric.operation.abstracts.InvokableAsyncBlockingOperation;
+import com.keuin.kbackupfabric.util.PrintUtil;
+import com.keuin.kbackupfabric.util.ZipUtil;
+import com.keuin.kbackupfabric.util.ZipUtilException;
+import com.mojang.brigadier.context.CommandContext;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.command.ServerCommandSource;
+import net.minecraft.world.World;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.keuin.kbackupfabric.util.BackupFilesystemUtil.*;
+import static com.keuin.kbackupfabric.util.PrintUtil.msgInfo;
+
+public class BackupOperation extends InvokableAsyncBlockingOperation {
+
+ private final CommandContext<ServerCommandSource> context;
+ private final String backupName;
+ private final Map<World, Boolean> oldWorldsSavingDisabled = new HashMap<>();
+ private final BackupMetadata backupMetadata;
+ private long startTime;
+
+
+ public BackupOperation(CommandContext<ServerCommandSource> context, String backupName, BackupMetadata backupMetadata) {
+ super("BackupWorker");
+ this.context = context;
+ this.backupName = backupName;
+ this.backupMetadata = backupMetadata;
+ }
+
+ @Override
+ protected void async() {
+ String backupSaveDirectory = "";
+ MinecraftServer server = context.getSource().getMinecraftServer();
+ try {
+ //// Do our main backup logic
+
+ // Create backup saving directory
+ File backupSaveDirectoryFile = getBackupSaveDirectory(server);
+ backupSaveDirectory = backupSaveDirectoryFile.getName();
+ if (!backupSaveDirectoryFile.isDirectory() && !backupSaveDirectoryFile.mkdir()) {
+ msgInfo(context, String.format("Failed to create backup saving directory: %s. Failed to backup.", backupSaveDirectory));
+ return;
+ }
+
+ // Make zip
+ String levelPath = getLevelPath(server);
+ String backupFileName = getBackupFileName(backupName);
+ PrintUtil.info(String.format("zip(srcPath=%s, destPath=%s)", levelPath, backupSaveDirectoryFile.toString()));
+ PrintUtil.info("Compressing level ...");
+ ZipUtil.makeBackupZip(levelPath, backupSaveDirectoryFile.toString(), backupFileName, backupMetadata);
+ File backupZipFile = new File(backupSaveDirectoryFile, backupFileName);
+
+ // Restore old autosave switch stat
+ server.getWorlds().forEach(world -> world.savingDisabled = oldWorldsSavingDisabled.getOrDefault(world, true));
+
+ // Print finish message: time elapsed and file size
+ long timeElapsedMillis = System.currentTimeMillis() - startTime;
+ String msgText = String.format("Backup finished. Time elapsed: %.2fs.", timeElapsedMillis / 1000.0);
+ try {
+ msgText += String.format(" File size: %s.", humanFileSize(backupZipFile.length()));
+ } catch (SecurityException ignored) {
+ }
+ PrintUtil.msgInfo(context, msgText, true);
+
+ } catch (SecurityException e) {
+ msgInfo(context, String.format("Failed to create backup saving directory: %s. Failed to backup.", backupSaveDirectory));
+ } catch (IOException | ZipUtilException e) {
+ msgInfo(context, "Failed to make zip: " + e.getMessage());
+ }
+ }
+
+ @Override
+ protected boolean sync() {
+ //// Save world, save old autosave configs
+
+ PrintUtil.broadcast(String.format("Making backup %s, please wait ...", backupName));
+
+ // Get server
+ MinecraftServer server = context.getSource().getMinecraftServer();
+
+ // Save old autosave switch stat temporally
+ oldWorldsSavingDisabled.clear();
+ server.getWorlds().forEach(world -> {
+ oldWorldsSavingDisabled.put(world, world.savingDisabled);
+ world.savingDisabled = true;
+ });
+
+ // Force to save all player data and worlds
+ PrintUtil.msgInfo(context, "Saving players ...");
+ server.getPlayerManager().saveAllPlayerData();
+ PrintUtil.msgInfo(context, "Saving worlds ...");
+ server.save(true, true, true);
+
+ // Log start time
+ startTime = System.currentTimeMillis();
+ return true;
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java
index be7734d..ee1a57e 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java
@@ -1,5 +1,7 @@
package com.keuin.kbackupfabric.operation;
+import com.keuin.kbackupfabric.operation.abstracts.InvokableAsyncBlockingOperation;
+import com.keuin.kbackupfabric.util.BackupNameSuggestionProvider;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.MinecraftServer;
@@ -14,19 +16,30 @@ import static com.keuin.kbackupfabric.util.PrintUtil.msgErr;
import static com.keuin.kbackupfabric.util.PrintUtil.msgInfo;
import static org.apache.commons.io.FileUtils.forceDelete;
-class DeleteOperation extends AbstractConfirmableOperation {
+public class DeleteOperation extends InvokableAsyncBlockingOperation {
//private static final Logger LOGGER = LogManager.getLogger();
private final String backupName;
private final CommandContext<ServerCommandSource> context;
- DeleteOperation(CommandContext<ServerCommandSource> context, String backupName) {
+ public DeleteOperation(CommandContext<ServerCommandSource> context, String backupName) {
+ super("BackupDeletingWorker");
this.backupName = backupName;
this.context = context;
}
@Override
- public boolean confirm() {
+ public String toString() {
+ return String.format("deletion of %s", backupName);
+ }
+
+ @Override
+ protected void async() {
+ delete();
+ BackupNameSuggestionProvider.updateCandidateList();
+ }
+
+ private void delete() {
MinecraftServer server = context.getSource().getMinecraftServer();
String backupFileName = getBackupFileName(backupName);
PrintUtil.info("Deleting backup " + backupName);
@@ -37,7 +50,7 @@ class DeleteOperation extends AbstractConfirmableOperation {
String msg = "Failed to delete file " + backupFileName;
PrintUtil.error(msg);
msgErr(context, msg);
- return false;
+ return;
}
try {
if (!backupFile.delete())
@@ -48,11 +61,5 @@ class DeleteOperation extends AbstractConfirmableOperation {
} while (backupFile.exists());
PrintUtil.info("Deleted backup " + backupName);
msgInfo(context, "Deleted backup " + backupName);
- return true;
- }
-
- @Override
- public String toString() {
- return String.format("deletion of %s", backupName);
}
}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
index 4b129d9..cc19627 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
@@ -1,37 +1,49 @@
package com.keuin.kbackupfabric.operation;
+import com.keuin.kbackupfabric.operation.abstracts.InvokableBlockingOperation;
import com.keuin.kbackupfabric.util.PrintUtil;
-import com.keuin.kbackupfabric.worker.RestoreWorker;
+import com.keuin.kbackupfabric.util.ZipUtil;
+import com.keuin.kbackupfabric.util.ZipUtilException;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import java.io.File;
+import java.io.IOException;
-import static com.keuin.kbackupfabric.util.BackupFilesystemUtil.*;
+import static com.keuin.kbackupfabric.util.BackupFilesystemUtil.getBackupFileName;
+import static com.keuin.kbackupfabric.util.BackupFilesystemUtil.getBackupSaveDirectory;
+import static org.apache.commons.io.FileUtils.forceDelete;
-class RestoreOperation extends AbstractConfirmableOperation {
+public class RestoreOperation extends InvokableBlockingOperation {
//private static final Logger LOGGER = LogManager.getLogger();
private final String backupName;
+ private final Thread serverThread;
+ private final String backupFilePath;
+ private final String levelDirectory;
private final CommandContext<ServerCommandSource> context;
+ private final MinecraftServer server;
- RestoreOperation(CommandContext<ServerCommandSource> context, String backupName) {
+ public RestoreOperation(CommandContext<ServerCommandSource> context, String backupFilePath, String levelDirectory, String backupName) {
+ server = context.getSource().getMinecraftServer();
this.backupName = backupName;
+ this.serverThread = server.getThread();
+ this.backupFilePath = backupFilePath;
+ this.levelDirectory = levelDirectory;
this.context = context;
}
@Override
- public boolean confirm() {
+ protected boolean blockingContext() {
// do restore to backupName
- MinecraftServer server = context.getSource().getMinecraftServer();
PrintUtil.broadcast(String.format("Restoring to previous world %s ...", backupName));
String backupFileName = getBackupFileName(backupName);
PrintUtil.debug("Backup file name: " + backupFileName);
File backupFile = new File(getBackupSaveDirectory(server), backupFileName);
- PrintUtil.msgInfo(context, "Server will shutdown in a few seconds, depended on your world size and the disk speed, the restore progress may take seconds or minutes.", true);
+ PrintUtil.msgInfo(context, "Server will shutdown in a few seconds, depending on world size and disk speed, the progress may take from seconds to minutes.", true);
PrintUtil.msgInfo(context, "Please do not force the server stop, or the level would be broken.", true);
PrintUtil.msgInfo(context, "After it shuts down, please restart the server manually.", true);
final int WAIT_SECONDS = 10;
@@ -42,7 +54,14 @@ class RestoreOperation extends AbstractConfirmableOperation {
}
}
PrintUtil.broadcast("Shutting down ...");
- RestoreWorker.invoke(server, backupFile.getPath(), getLevelPath(server));
+ //RestoreWorker worker = new RestoreWorker(server.getThread(), backupFilePath, levelDirectory);
+ Thread workerThread = new Thread(new WorkerThread(), "RestoreWorker");
+ workerThread.start();
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ignored) {
+ }
+ server.stop(false);
return true;
}
@@ -50,4 +69,61 @@ class RestoreOperation extends AbstractConfirmableOperation {
public String toString() {
return String.format("restoration from %s", backupName);
}
+
+ private class WorkerThread implements Runnable {
+
+ @Override
+ public void run() {
+ try {
+ // Wait server thread die
+ PrintUtil.info("Waiting for the server thread to exit ...");
+ while (serverThread.isAlive()) {
+ try {
+ serverThread.join();
+ } catch (InterruptedException ignored) {
+ }
+ }
+
+ PrintUtil.info("Wait for 5 seconds ...");
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException ignored) {
+ }
+
+ // Delete old level
+ PrintUtil.info("Server stopped. Deleting old level ...");
+ File levelDirFile = new File(levelDirectory);
+ long startTime = System.currentTimeMillis();
+
+ int failedCounter = 0;
+ final int MAX_RETRY_TIMES = 20;
+ while (failedCounter < MAX_RETRY_TIMES) {
+ System.gc();
+ if (!levelDirFile.delete() && levelDirFile.exists()) {
+ System.gc();
+ forceDelete(levelDirFile); // Try to force delete.
+ }
+ if (!levelDirFile.exists())
+ break;
+ ++failedCounter;
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ if (levelDirFile.exists()) {
+ PrintUtil.error(String.format("Cannot restore: failed to delete old level %s .", levelDirFile.getName()));
+ return;
+ }
+
+ // Decompress archive
+ PrintUtil.info("Decompressing archived level ...");
+ ZipUtil.unzip(backupFilePath, levelDirectory, false);
+ long endTime = System.currentTimeMillis();
+ PrintUtil.info(String.format("Restore complete! (%.2fs) Please restart the server manually.", (endTime - startTime) / 1000.0));
+ } catch (SecurityException | IOException | ZipUtilException e) {
+ PrintUtil.error("An exception occurred while restoring: " + e.getMessage());
+ }
+ }
+ }
}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractAsyncOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractAsyncOperation.java
new file mode 100644
index 0000000..f1a19de
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractAsyncOperation.java
@@ -0,0 +1,53 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+public abstract class AbstractAsyncOperation extends AbstractSerializedOperation {
+
+ private final Thread thread;
+ private final String name;
+ private final Object sync = new Object();
+
+ protected AbstractAsyncOperation(String name) {
+ this.name = name;
+ this.thread = new Thread(this::async, name);
+ }
+
+ /**
+ * Start the worker thread.
+ *
+ * @return true if succeed starting, false if already started.
+ */
+ @Override
+ protected final boolean operate() {
+ synchronized (sync) {
+ if (thread.isAlive())
+ return false;
+ if (!sync())
+ return false;
+ thread.start();
+ return true;
+ }
+ }
+
+ /**
+ * Implement your async operation here.
+ * When this method returns, the operation must finish.
+ */
+ protected abstract void async();
+
+ /**
+ * If necessary, implement your sync operations here.
+ * It will be invoked before starting the async thread.
+ */
+ protected boolean sync() {
+ return true;
+ }
+
+ public final String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return "operation " + name;
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractBlockingOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractBlockingOperation.java
new file mode 100644
index 0000000..de672cd
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractBlockingOperation.java
@@ -0,0 +1,58 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+import com.keuin.kbackupfabric.operation.abstracts.i.Blocking;
+
+public abstract class AbstractBlockingOperation extends AbstractSerializedOperation implements Blocking {
+
+ private static final Object sync = new Object();
+ private static boolean isBlocking = false;
+ private boolean wasBlocked = false;
+ private boolean noUnblocking = false;
+
+ @Override
+ protected final boolean operate() {
+ synchronized (sync) {
+ if (isBlocking) {
+ System.out.println("blocked.");
+ wasBlocked = true;
+ return false;
+ } else {
+ System.out.println("not blocked.");
+ wasBlocked = false;
+ isBlocking = true;
+ }
+ }
+ boolean exitCode = blockingContext();
+ if (!noUnblocking)
+ isBlocking = false;
+ return exitCode;
+ }
+
+ public final boolean isBlocked() {
+ return wasBlocked;
+ }
+
+ protected final void block(boolean blockState) {
+ isBlocking = blockState;
+ }
+
+ protected void noUnblocking(boolean b) {
+ noUnblocking = b;
+ }
+
+ protected boolean blockAndGet() {
+ synchronized (sync) {
+ boolean b = isBlocking;
+ isBlocking = true;
+ return b;
+ }
+ }
+
+ /**
+ * Implement your blocked operation here.
+ *
+ * @return the stat code.
+ */
+ protected abstract boolean blockingContext();
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractConfirmableOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractConfirmableOperation.java
new file mode 100644
index 0000000..0a56008
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractConfirmableOperation.java
@@ -0,0 +1,11 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+public abstract class AbstractConfirmableOperation extends AbstractSerializedOperation {
+
+ public final boolean confirm() {
+ return operate();
+ }
+
+ @Override
+ public abstract String toString();
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractSerializedOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractSerializedOperation.java
new file mode 100644
index 0000000..3168e8c
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/AbstractSerializedOperation.java
@@ -0,0 +1,12 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+public abstract class AbstractSerializedOperation {
+ /**
+ * Do your operation here.
+ * This method is not designed to be public.
+ * When this method returns, the operation must have finished.
+ *
+ * @return the stat code.
+ */
+ protected abstract boolean operate();
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncBlockingOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncBlockingOperation.java
new file mode 100644
index 0000000..6268d5a
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncBlockingOperation.java
@@ -0,0 +1,66 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+import com.keuin.kbackupfabric.operation.abstracts.i.Blocking;
+import com.keuin.kbackupfabric.operation.abstracts.i.Invokable;
+
+public abstract class InvokableAsyncBlockingOperation implements Invokable, Blocking {
+
+ private final InvokableAsyncOperation asyncOperation;
+ private final HackedBlockingOperation blockingOperation;
+
+ public InvokableAsyncBlockingOperation(String name) {
+ asyncOperation = new InvokableAsyncOperation(name) {
+ @Override
+ protected void async() {
+ InvokableAsyncBlockingOperation.this.async();
+ // When the async operation finishes, unblock
+ blockingOperation.noUnblocking(false);
+ blockingOperation.block(false);
+ }
+
+ @Override
+ protected boolean sync() {
+ return InvokableAsyncBlockingOperation.this.sync();
+ }
+ };
+
+ blockingOperation = new HackedBlockingOperation();
+ }
+
+ @Override
+ public boolean invoke() {
+ return blockingOperation.invoke();
+ }
+
+ @Override
+ public boolean isBlocked() {
+ return blockingOperation.isBlocked();
+ }
+
+ protected abstract void async();
+
+ protected boolean sync() {
+ return true;
+ }
+
+ private class HackedBlockingOperation extends InvokableBlockingOperation {
+
+ @Override
+ protected boolean blockingContext() {
+
+ noUnblocking(true);
+ return asyncOperation.invoke();
+ }
+
+ @Override
+ public void noUnblocking(boolean b) {
+ super.noUnblocking(b);
+ }
+
+ @Override
+ public void block(boolean blockState) {
+ super.block(blockState);
+ }
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncOperation.java
new file mode 100644
index 0000000..518f670
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableAsyncOperation.java
@@ -0,0 +1,32 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+public abstract class InvokableAsyncOperation extends InvokableOperation {
+
+ private final AbstractAsyncOperation asyncOperation;
+
+
+ public InvokableAsyncOperation(String name) {
+ asyncOperation = new AbstractAsyncOperation(name) {
+ @Override
+ protected void async() {
+ InvokableAsyncOperation.this.async();
+ }
+
+ @Override
+ protected boolean sync() {
+ return InvokableAsyncOperation.this.sync();
+ }
+ };
+ }
+
+ protected abstract void async();
+
+ protected boolean sync() {
+ return true;
+ }
+
+ @Override
+ protected boolean operate() {
+ return asyncOperation.operate();
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableBlockingOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableBlockingOperation.java
new file mode 100644
index 0000000..b1a3748
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableBlockingOperation.java
@@ -0,0 +1,39 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+import com.keuin.kbackupfabric.operation.abstracts.i.Blocking;
+
+public abstract class InvokableBlockingOperation extends InvokableOperation implements Blocking {
+
+ private final AbstractBlockingOperation operation = new AbstractBlockingOperation() {
+ @Override
+ protected boolean blockingContext() {
+ return InvokableBlockingOperation.this.blockingContext();
+ }
+ };
+
+ @Override
+ protected final boolean operate() {
+ return operation.operate();
+ }
+
+ /**
+ * Implement your blocked operation here.
+ *
+ * @return stat code.
+ */
+ protected abstract boolean blockingContext();
+
+ protected void block(boolean blockState) {
+ operation.block(blockState);
+ }
+
+ protected void noUnblocking(boolean b) {
+ operation.noUnblocking(b);
+ }
+
+ @Override
+ public final boolean isBlocked() {
+ return operation.isBlocked();
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableOperation.java
new file mode 100644
index 0000000..47c1ca8
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/InvokableOperation.java
@@ -0,0 +1,9 @@
+package com.keuin.kbackupfabric.operation.abstracts;
+
+import com.keuin.kbackupfabric.operation.abstracts.i.Invokable;
+
+public abstract class InvokableOperation extends AbstractSerializedOperation implements Invokable {
+ public boolean invoke() {
+ return operate();
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Blocking.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Blocking.java
new file mode 100644
index 0000000..ba1b003
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Blocking.java
@@ -0,0 +1,5 @@
+package com.keuin.kbackupfabric.operation.abstracts.i;
+
+public interface Blocking {
+ boolean isBlocked();
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Invokable.java b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Invokable.java
new file mode 100644
index 0000000..74051e3
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/abstracts/i/Invokable.java
@@ -0,0 +1,5 @@
+package com.keuin.kbackupfabric.operation.abstracts.i;
+
+public interface Invokable {
+ boolean invoke();
+}