| | |
| | | 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 |
| | |
| | | private boolean compress; |
| | | @Getter |
| | | @JsonIgnore |
| | | private STATE state = STATE.INITIAL; |
| | | private CacheState state = CacheState.INITIAL; |
| | | @Getter |
| | | private Date lastModified; |
| | | @Getter |
| | |
| | | * Removes all entries (doesn't effect the cache files!). |
| | | */ |
| | | public void clear() { |
| | | state = STATE.DIRTY; |
| | | state = CacheState.INITIAL; |
| | | } |
| | | |
| | | /** |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | 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) { |