borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
@@ -3,6 +3,7 @@ import de.micromata.borgbutler.config.BorgRepoConfig; import de.micromata.borgbutler.data.Archive; import de.micromata.borgbutler.data.Repository; import de.micromata.borgbutler.jobs.JobResult; import de.micromata.borgbutler.json.JsonUtils; import de.micromata.borgbutler.json.borg.*; import de.micromata.borgbutler.utils.DateUtils; @@ -35,10 +36,11 @@ BorgCommand command = new BorgCommand() .setParams("--version") .setDescription("Getting borg version."); String version = execute(command).getResult(); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { JobResult<String> jobResult = execute(command).getResult(); if (jobResult.getStatus() != JobResult.Status.OK) { return null; } String version = jobResult.getResultObject(); log.info("Borg version: " + version); return version; } @@ -55,10 +57,11 @@ .setCommand("info") .setParams("--json") .setDescription("Loading info of repo '" + repoConfig.getDisplayName() + "'."); String result = execute(command).getResult(); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { JobResult<String> jobResult = execute(command).getResult(); if (jobResult.getStatus() != JobResult.Status.OK) { return null; } String result = jobResult.getResultObject(); BorgRepoInfo repoInfo = JsonUtils.fromJson(BorgRepoInfo.class, result); BorgRepository borgRepository = repoInfo.getRepository(); Repository repository = new Repository() @@ -87,11 +90,12 @@ .setCommand("list") .setParams("--json") .setDescription("Loading list of archives of repo '" + repoConfig.getDisplayName() + "'."); String result = execute(command).getResult(); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { JobResult<String> jobResult = execute(command).getResult(); if (jobResult.getStatus() != JobResult.Status.OK) { log.error("Can't load archives from repo '" + repository.getName() + "'."); return; } String result = jobResult.getResultObject(); BorgRepoList repoList = JsonUtils.fromJson(BorgRepoList.class, result); if (repoList == null || CollectionUtils.isEmpty(repoList.getArchives())) { log.error("Can't load archives from repo '" + repository.getName() + "'."); @@ -128,10 +132,11 @@ .setArchive(archive.getName()) .setParams("--json") .setDescription("Loading info of archive '" + archive.getName() + "' of repo '" + repoConfig.getDisplayName() + "'."); String result = execute(command).getResult(); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { JobResult<String> jobResult = execute(command).getResult(); if (jobResult.getStatus() != JobResult.Status.OK) { return; } String result = jobResult.getResultObject(); BorgArchiveInfo archiveInfo = JsonUtils.fromJson(BorgArchiveInfo.class, result); if (archiveInfo == null) { log.error("Archive '" + command.getRepoArchive() + "' not found."); @@ -158,8 +163,7 @@ .setHostname(borgArchive.getHostname()) .setUsername(borgArchive.getUsername()) .setEnd(DateUtils.format(borgArchive.getEnd())) .setDuration(borgArchive.getDuration()) ; .setDuration(borgArchive.getDuration()); } public static List<BorgFilesystemItem> listArchiveContent(BorgRepoConfig repoConfig, Archive archive) { @@ -169,11 +173,12 @@ .setArchive(archive.getName()) .setParams("--json-lines") .setDescription("Loading list of files of archive '" + archive.getName() + "' of repo '" + repoConfig.getDisplayName() + "'."); String result = execute(command).getResult(); List<BorgFilesystemItem> content = new ArrayList<>(); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { JobResult<String> jobResult = execute(command).getResult(); if (jobResult.getStatus() != JobResult.Status.OK) { return content; } String result = jobResult.getResultObject(); try (Scanner scanner = new Scanner(result)) { while (scanner.hasNextLine()) { String json = scanner.nextLine(); borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
@@ -2,7 +2,6 @@ import de.micromata.borgbutler.config.BorgRepoConfig; import de.micromata.borgbutler.config.ConfigurationHandler; import de.micromata.borgbutler.config.Definitions; import de.micromata.borgbutler.jobs.AbstractCommandLineJob; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.environment.EnvironmentUtils; @@ -17,7 +16,7 @@ * A queue is important because Borg doesn't support parallel calls for one repository. * For each repository one single queue is allocated. */ public class BorgJob extends AbstractCommandLineJob { public class BorgJob extends AbstractCommandLineJob<String> { private Logger log = LoggerFactory.getLogger(BorgJob.class); private BorgCommand command; @@ -50,19 +49,6 @@ } @Override protected void afterSuccess() { command.setResultStatus(BorgCommand.ResultStatus.OK); command.setResponse(outputStream.toString(Definitions.STD_CHARSET)); } @Override protected void afterFailure(Exception ex) { command.setResultStatus(BorgCommand.ResultStatus.ERROR); command.setResponse(outputStream.toString(Definitions.STD_CHARSET)); log.error("Response: " + command.getAbbreviatedResponse()); } @Override protected Map<String, String> getEnvironment() throws IOException { BorgRepoConfig repoConfig = command.getRepoConfig(); if (repoConfig == null) { borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/AbstractCommandLineJob.java
@@ -18,7 +18,7 @@ * A queue is important because Borg doesn't support parallel calls for one repository. * For each repository one single queue is allocated. */ public abstract class AbstractCommandLineJob extends AbstractJob<String> { public abstract class AbstractCommandLineJob<T> extends AbstractJob<T> { private Logger log = LoggerFactory.getLogger(AbstractCommandLineJob.class); private ExecuteWatchdog watchdog; @Getter @@ -53,7 +53,7 @@ } @Override public String execute() { public JobResult<String> execute() { getCommandLineAsString(); DefaultExecutor executor = new DefaultExecutor(); if (workingDirectory != null) { @@ -91,15 +91,17 @@ : "Executing '" + commandLineAsString + "'..."; log.info(msg); this.executeStarted = true; JobResult<String> result = new JobResult<>(); try { executor.execute(commandLine, getEnvironment()); afterSuccess(); result.setStatus(JobResult.Status.OK); log.info(msg + " Done."); } catch (Exception ex) { result.setStatus(JobResult.Status.ERROR); failed(); afterFailure(ex); } return outputStream.toString(Definitions.STD_CHARSET); result.setResultObject(outputStream.toString(Definitions.STD_CHARSET)); return result; } @Override @@ -112,12 +114,6 @@ } } protected void afterSuccess() { } protected void afterFailure(Exception ex) { } protected Map<String, String> getEnvironment() throws IOException { return null; } borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/AbstractJob.java
@@ -29,7 +29,9 @@ private String statusText; @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE) private Future<T> future; // TODO: JobResult private Future<JobResult<T>> future; public void cancel() { if (this.getStatus() == Status.QUEUED) { @@ -53,7 +55,7 @@ * Waits for and gets the result. * @return */ public T getResult() { public JobResult<T> getResult() { try { return future.get(); } catch (InterruptedException | ExecutionException ex) { @@ -62,6 +64,10 @@ return null; } public T getResultObject() { return getResult().getResultObject(); } protected void failed() { if (this.status == Status.CANCELLED) { // do nothing. It's normal that cancelled jobs fail. @@ -83,7 +89,7 @@ return false; } public abstract T execute(); public abstract JobResult execute(); /** * A job is identified by this id. If a job with the same id is already queued (not yet finished), this job will borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobQueue.java
@@ -30,7 +30,7 @@ * @param job * @return The given job (if it's not already running or queued), otherwise the already running or queued job. */ public AbstractJob append(AbstractJob<T> job) { public AbstractJob append(AbstractJob job) { synchronized (queue) { for (AbstractJob queuedJob : queue) { if (Objects.equals(queuedJob.getId(), job.getId())) { @@ -83,15 +83,15 @@ } } private class CallableTask implements Callable<T> { private AbstractJob<T> job; private class CallableTask implements Callable<JobResult<T>> { private AbstractJob job; private CallableTask(AbstractJob<T> job) { private CallableTask(AbstractJob job) { this.job = job; } @Override public T call() throws Exception { public JobResult<T> call() throws Exception { if (job.isCancelledRequested()) { job.setStatus(AbstractJob.Status.CANCELLED); return null; @@ -99,7 +99,7 @@ try { log.info("Starting job: " + job.getId()); job.setStatus(AbstractJob.Status.RUNNING); T result = job.execute(); JobResult<T> result = job.execute(); if (!job.isFinished()) { // Don't overwrite status failed set by job. job.setStatus(AbstractJob.Status.DONE); borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobResult.java
New file @@ -0,0 +1,15 @@ package de.micromata.borgbutler.jobs; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; public class JobResult<T> { public enum Status {OK, ERROR} @Getter @Setter(AccessLevel.PACKAGE) private Status status; @Getter @Setter private T resultObject; } borgbutler-core/src/test/java/de/micromata/borgbutler/jobs/JobQueueTest.java
@@ -64,7 +64,7 @@ TestJob job = (TestJob) queue.getQueuedJob(5); assertEquals(AbstractJob.Status.QUEUED, job.getStatus()); String result = job1.getResult(); String result = job1.getResultObject(); assertEquals("10\n", result); assertEquals(AbstractJob.Status.DONE, job1.getStatus()); @@ -77,7 +77,7 @@ job.cancel(); assertEquals(AbstractJob.Status.CANCELLED, job.getStatus()); result = job1.getResult(); result = job1.getResultObject(); assertEquals("10\n", result); assertEquals(0, queue.getQueueSize()); @@ -118,7 +118,7 @@ assertTrue(counter > 0); assertEquals(AbstractJob.Status.CANCELLED, job.getStatus()); job = (TestJob)queue.getQueuedJob(10); assertEquals("10\n", job.getResult()); assertEquals("10\n", job.getResultObject()); List<AbstractJob> doneJobs = queue.getDoneJobs(); assertEquals(2, doneJobs.size()); check(((TestJob) doneJobs.get(0)), AbstractJob.Status.DONE, null); @@ -128,7 +128,7 @@ private void check(TestJob job, AbstractJob.Status status, String result) { assertEquals(status, job.getStatus()); if (result != null) { assertEquals(result + "\n", job.getResult()); assertEquals(result + "\n", job.getResultObject()); } } } borgbutler-core/src/test/java/de/micromata/borgbutler/jobs/TestJob.java
@@ -6,7 +6,7 @@ import java.io.File; public class TestJob extends AbstractCommandLineJob { public class TestJob extends AbstractCommandLineJob<String> { private Logger log = LoggerFactory.getLogger(TestJob.class); private int time; private File counterScript; @@ -34,11 +34,4 @@ commandLine.addArgument(String.valueOf(this.failOn)); return commandLine; } @Override protected void afterFailure(Exception ex) { if (failOn < 0 && getStatus() != Status.CANCELLED) { log.error("Error while executing script '" + getCommandLineAsString() + "': " + ex.getMessage(), ex); } } }