From 1537fb95a9977a162dc29e2487c4020e96b43074 Mon Sep 17 00:00:00 2001
From: Kai Reinhard <K.Reinhard@micromata.de>
Date: Mon, 10 Dec 2018 04:19:02 +0000
Subject: [PATCH] Last modifications (untested) before migrating to Apache jcs.

---
 borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractCache.java         |  127 +++++++++++++++++++++++-------------------
 borgbutler-core/src/main/java/de/micromata/borgbutler/cache/CacheState.java            |   33 +++++++++++
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java               |    2 
 borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractElementsCache.java |    2 
 4 files changed, 106 insertions(+), 58 deletions(-)

diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractCache.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractCache.java
index d89de91..4072ebd 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractCache.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractCache.java
@@ -21,11 +21,6 @@
     private static final String CACHE_FILE_EXTENSION = "json";
     private static final String CACHE_FILE_ZIP_EXTENSION = ".gz";
 
-    /**
-     * INITIAL - on startup (not yet read), DIRTY - modifications not written, SAVED - content written to file.
-     */
-    protected enum STATE {INITIAL, DIRTY, SAVED}
-
     @JsonIgnore
     protected File cacheFile;
     @JsonIgnore
@@ -33,7 +28,7 @@
     private boolean compress;
     @Getter
     @JsonIgnore
-    private STATE state = STATE.INITIAL;
+    private CacheState state = CacheState.INITIAL;
     @Getter
     private Date lastModified;
     @Getter
@@ -43,7 +38,7 @@
      * Removes all entries (doesn't effect the cache files!).
      */
     public void clear() {
-        state = STATE.DIRTY;
+        state = CacheState.INITIAL;
     }
 
     /**
@@ -56,76 +51,94 @@
                 cacheFile.delete();
             }
             clear();
-            state = STATE.SAVED;
         }
     }
 
     protected void setDirty() {
-        state = STATE.DIRTY;
+        state = CacheState.DIRTY;
     }
 
     public void read() {
-        try {
-            if (!cacheFile.exists()) {
-                // Cache file doesn't exist. Nothing to read.
-                state = STATE.DIRTY; // Needed to save cache to file.
+        if (state == CacheState.LOADING_FROM_CACHE_FILE) {
+            // Already in progress, nothing to do.
+            synchronized (this) {
+                // Wait and do nothing.
                 return;
             }
-            log.info("Parsing cache file '" + cacheFile.getAbsolutePath() + "'.");
-            String json;
-            if (compress) {
-                try (GzipCompressorInputStream in = new GzipCompressorInputStream(new FileInputStream(cacheFile))) {
-                    StringWriter writer = new StringWriter();
-                    IOUtils.copy(in, writer, Definitions.STD_CHARSET);
-                    json = writer.toString();
+        }
+        synchronized (this) {
+            try {
+                state = CacheState.LOADING_FROM_CACHE_FILE;
+                if (!cacheFile.exists()) {
+                    // Cache file doesn't exist. Nothing to read.
+                    state = CacheState.DIRTY; // Needed to save cache to file.
+                    return;
                 }
-            } else {
-                json = FileUtils.readFileToString(cacheFile, Definitions.STD_CHARSET);
+                log.info("Parsing cache file '" + cacheFile.getAbsolutePath() + "'.");
+                String json;
+                if (compress) {
+                    try (GzipCompressorInputStream in = new GzipCompressorInputStream(new FileInputStream(cacheFile))) {
+                        StringWriter writer = new StringWriter();
+                        IOUtils.copy(in, writer, Definitions.STD_CHARSET);
+                        json = writer.toString();
+                    }
+                } else {
+                    json = FileUtils.readFileToString(cacheFile, Definitions.STD_CHARSET);
+                }
+                AbstractCache readCache = JsonUtils.fromJson(this.getClass(), json);
+                if (readCache != null) {
+                    this.lastModified = readCache.lastModified;
+                    this.created = readCache.created;
+                    update(readCache);
+                    this.state = CacheState.SAVED; // State of cache is updated from cache file.
+                } else {
+                    log.error("Error while parsing cache: " + cacheFile.getAbsolutePath());
+                    this.state = CacheState.DIRTY; // Needed to save cache to file.
+                }
+            } catch (IOException ex) {
+                log.error("Error while trying to read cache file '" + cacheFile.getAbsolutePath() + "': "
+                        + ex.getMessage(), ex);
+                this.state = CacheState.DIRTY; // Needed to save cache to file.
             }
-            AbstractCache readCache = JsonUtils.fromJson(this.getClass(), json);
-            if (readCache != null) {
-                this.lastModified = readCache.lastModified;
-                this.created = readCache.created;
-                this.state = STATE.SAVED; // State of cache is updated from cache file.
-                update(readCache);
-            } else {
-                log.error("Error while parsing cache: " + cacheFile.getAbsolutePath());
-                this.state = STATE.DIRTY; // Needed to save cache to file.
-            }
-        } catch (IOException ex) {
-            log.error("Error while trying to read cache file '" + cacheFile.getAbsolutePath() + "': "
-                    + ex.getMessage(), ex);
-            this.state = STATE.DIRTY; // Needed to save cache to file.
         }
     }
 
     protected abstract void update(AbstractCache readCache);
 
     public void save() {
-        if (this.state == STATE.SAVED || this.state == STATE.INITIAL) {
+        if (this.state == CacheState.SAVED || this.state == CacheState.INITIAL) {
             log.info("Cache file is up to date (nothing to save): " + cacheFile);
             return;
         }
-        log.info("Saving to cache file: " + cacheFile);
-        if (created == null) {
-            created = lastModified = new Date();
-        } else {
-            lastModified = new Date();
-        }
-        String json = JsonUtils.toJson(this);
-        try {
-            if (this.compress) {
-                try (GzipCompressorOutputStream out = new GzipCompressorOutputStream(new FileOutputStream(cacheFile))) {
-                    IOUtils.copy(new StringReader(json), out, Definitions.STD_CHARSET);
-                }
-            } else {
-                FileUtils.write(cacheFile, json, Definitions.STD_CHARSET);
+        if (state == CacheState.SAVING) {
+            // Already in progress, nothing to do.
+            synchronized (this) {
+                // Wait and do nothing.
+                return;
             }
-            this.state = STATE.SAVED;
-        } catch (IOException ex) {
-            log.error("Error while trying to write cache file '" + cacheFile.getAbsolutePath() + "': "
-                    + ex.getMessage(), ex);
-            this.state = STATE.DIRTY;
+        }
+        synchronized (this) {
+            log.info("Saving to cache file: " + cacheFile);
+            if (created == null) {
+                created = lastModified = new Date();
+            } else {
+                lastModified = new Date();
+            }
+            String json = JsonUtils.toJson(this);
+            try {
+                if (this.compress) {
+                    try (GzipCompressorOutputStream out = new GzipCompressorOutputStream(new FileOutputStream(cacheFile))) {
+                        IOUtils.copy(new StringReader(json), out, Definitions.STD_CHARSET);
+                    }
+                } else {
+                    FileUtils.write(cacheFile, json, Definitions.STD_CHARSET);
+                }
+                this.state = CacheState.SAVED;
+            } catch (IOException ex) {
+                log.error("Error while trying to write cache file '" + cacheFile.getAbsolutePath() + "': "
+                        + ex.getMessage(), ex);
+                this.state = CacheState.DIRTY;
+            }
         }
     }
 
@@ -145,7 +158,7 @@
         if (this.compress)
             filename = filename + CACHE_FILE_ZIP_EXTENSION;
         cacheFile = new File(cacheDir, filename);
-        this.state = STATE.INITIAL;
+        this.state = CacheState.INITIAL;
     }
 
     public static boolean isCacheFile(File file) {
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractElementsCache.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractElementsCache.java
index 67c2604..93dc1bb 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractElementsCache.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/AbstractElementsCache.java
@@ -19,7 +19,7 @@
         if (identifier == null) {
             return null;
         }
-        if (getState() == STATE.INITIAL) {
+        if (getState() == CacheState.INITIAL) {
             read();
         }
         for (T element : elements.values()) {
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/CacheState.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/CacheState.java
new file mode 100644
index 0000000..87a6771
--- /dev/null
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/CacheState.java
@@ -0,0 +1,33 @@
+package de.micromata.borgbutler.cache;
+
+/**
+ * ,
+ * PARSING - , DIRTY - , SAVED -
+ */
+public enum CacheState {
+    /**
+     * On startup or directly after {@link AbstractCache#clear()} is called. (not yet read).
+     */
+    INITIAL,
+    /**
+     * Cache is been loaded (with borg command).
+     */
+    LOADING_FROM_BORG,
+    /**
+     * Cache is beeing loaded from filesystem.
+     */
+    LOADING_FROM_CACHE_FILE,
+    /**
+     * Modifications done but not yet written.
+     */
+    DIRTY,
+    /**
+     * Save to cache file is in progress.
+     */
+    SAVING,
+    /**
+     * Content has been written to file, no modifications done after. Cache file is up-to-date.
+     */
+    SAVED
+
+}
\ No newline at end of file
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
index 2bcd91d..3963b57 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
@@ -1,5 +1,6 @@
 package de.micromata.borgbutler.server;
 
+import de.micromata.borgbutler.cache.ButlerCache;
 import de.micromata.borgbutler.server.jetty.JettyServer;
 import de.micromata.borgbutler.server.user.SingleUserManager;
 import de.micromata.borgbutler.server.user.UserManager;
@@ -104,6 +105,7 @@
         }
         log.info("Shutting down BorgButler web server...");
         server.stop();
+        ButlerCache.getInstance().save();
     }
 
     private static void printHelp(Options options) {

--
Gitblit v1.10.0