Skip to content

Commit

Permalink
initial implementation for CacheManager #77
Browse files Browse the repository at this point in the history
  • Loading branch information
rsteph-de committed Apr 12, 2024
1 parent 65e1521 commit f4e4bd5
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 10 deletions.
39 changes: 29 additions & 10 deletions jspdocportal-diskcache/pom.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mycore.jspdocportal</groupId>
<artifactId>jspdocportal-parent</artifactId>
<version>2023.06-SNAPSHOT</version>
</parent>
<artifactId>jspdocportal-diskcache</artifactId>
<name>jspdocportal-diskcache</name>
<description>Cacheing and generation of derived files</description>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mycore.jspdocportal</groupId>
<artifactId>jspdocportal-parent</artifactId>
<version>2023.06-SNAPSHOT</version>
</parent>
<artifactId>jspdocportal-diskcache</artifactId>
<name>jspdocportal-diskcache</name>
<description>Cacheing and generation of derived files</description>
<dependencies>
<dependency>
<groupId>org.mycore</groupId>
<artifactId>mycore-base</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mycore.jspdocportal</groupId>
<artifactId>jspdocportal-bom</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package org.mycore.jspdocportal.diskcache;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.BiConsumer;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mycore.common.config.annotation.MCRInstance;
import org.mycore.common.config.annotation.MCRPostConstruction;
import org.mycore.common.config.annotation.MCRProperty;
import org.mycore.common.events.MCRShutdownHandler;
import org.mycore.jspdocportal.diskcache.disklru.DiskLruCache;
import org.mycore.jspdocportal.diskcache.disklru.DiskLruCache.Value;

public class MCRDiskcacheConfig {

/** The logger */
private static Logger LOGGER = LogManager.getLogger(MCRDiskcacheConfig.class);

private static int DISK_LRUCACHE_VALUE_COUNT = 1;

private String id;
private Path baseDir;

//TODO "defaultName" in MCRInstance
@MCRInstance(name="Generator", valueClass=BiConsumer.class)
private BiConsumer<String, Path> generator;

@MCRProperty(name = "FileName", defaultName = "MCR.Diskcache.Default.FileName")
private String fileName;
@MCRProperty(name = "MimeType", defaultName = "MCR.Diskcache.Default.MimeType")
private String mimeType;

private long livespanInMillis;
private long maxSizeInBytes;

//not directly supported, could be removed later
private int maxCount;
private int version;

private DiskLruCache cache;

@MCRProperty(name = "BaseDir", defaultName = "MCR.Diskcache.Default.BaseDir")
public void setBaseDir(String dir) {
baseDir = Paths.get(dir);
}

@MCRProperty(name = "LivespanInMillis", defaultName = "MCR.Diskcache.Default.LivespanInMillis")
public void setLivespanInMillis(String sLivespanInMillis) {
this.livespanInMillis = Long.parseLong(sLivespanInMillis);
}

@MCRProperty(name = "MaxSizeInBytes", defaultName = "MCR.Diskcache.Default.MaxSizeInBytes")
public void setMaxSizeInBytes(String sMaxSizeInBytes) {
this.maxSizeInBytes = Long.parseLong(sMaxSizeInBytes);
}

@MCRProperty(name = "MaxCount", defaultName = "MCR.Diskcache.Default.MaxCount")
public void setMaxCount(String sMaxCount) {
this.maxCount = Integer.parseInt(sMaxCount);
}

//Version des Caches -> beim Setzen einer neuen Nummer wird der Cache gelöscht
@MCRProperty(name = "Version", defaultName = "MCR.Diskcache.Default.Version")
public void setVersion(String sVersion) {
this.version = Integer.parseInt(sVersion);
}

@MCRPostConstruction
public void init(String property) {
id = property.substring(property.lastIndexOf(".") + 1);
try {
cache = DiskLruCache.open(baseDir, version, DISK_LRUCACHE_VALUE_COUNT, maxSizeInBytes);
MCRShutdownHandler.getInstance().addCloseable(new MCRDiskLruCacheClosable(cache));
} catch (IOException e) {
LOGGER.error(e);
}
}

public String getId() {
return id;
}

public Path getBaseDir() {
return baseDir;
}

public String getFileName() {
return fileName;
}

public String getMimeType() {
return mimeType;
}

public long getLivespanInMillis() {
return livespanInMillis;
}

public long getMaxSizeInBytes() {
return maxSizeInBytes;
}

public long getMaxCount() {
return maxCount;
}

public DiskLruCache getCache() {
return cache;
}

private Value getFromCache(DiskLruCache cache, String key) {
try {
Value v = cache.get(key);
if (v != null) {
Path p = v.getFile(1);
if (Files.getLastModifiedTime(p).toMillis() < System.currentTimeMillis() - livespanInMillis) {
cache.remove(key);
return null;
}
}
return v;
} catch (IOException e) {
LOGGER.error(e);
}
return null;
}

public Path retrieveCachedFile(String objectId) {
Value v = getFromCache(cache, objectId);
Path p = v.getFile(0);
if (p == null) {
//TODO recreate FileObject and add it to Cache
}
return p;
}

public void removeCachedFile(String objectId) {
try {
cache.remove(objectId);
} catch (IOException e) {
LOGGER.error("Could not remove object " + objectId + " from cache " + getId(), e);
}
}

class MCRDiskLruCacheClosable implements MCRShutdownHandler.Closeable {
private DiskLruCache cache;

public MCRDiskLruCacheClosable(DiskLruCache cache) {
this.cache = cache;
}

@Override
public void prepareClose() {
}

@Override
public int getPriority() {
return Integer.MIN_VALUE;
}

@Override
public void close() {
String cacheId = cache.getDirectory().getFileName().toString();
LOGGER.info("Shutting down DiskCache " + cacheId);
try {
cache.flush();
cache.close();
} catch (IOException e) {
LOGGER.error("Error closing cache " + cacheId, e);
}

}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.mycore.jspdocportal.diskcache;

import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.mycore.common.config.MCRConfiguration2;

public class MCRDiskcacheManager {
private static final MCRDiskcacheManager SINGLETON = new MCRDiskcacheManager();
private static final String MCR_PROPERTY_CONFIG_PREFIX = "MCR.Diskcache.Cache.";

private Map<String, MCRDiskcacheConfig> caches = new HashMap<>();

private MCRDiskcacheManager() {
MCRConfiguration2.getString("MCR.Diskcache.EnabledCaches").ifPresent(x -> {
Arrays.asList(x.split(",")).forEach(c -> {
caches.put(c,
MCRConfiguration2.<MCRDiskcacheConfig>getInstanceOf(MCR_PROPERTY_CONFIG_PREFIX + c)
.orElseThrow(
() -> MCRConfiguration2.createConfigurationException("MCR_PROPERTY_CONFIG_PREFIX" + c)));
});
});
}

public static MCRDiskcacheManager instance() {
return SINGLETON;
}

public Map<String, MCRDiskcacheConfig> getCaches() {
return caches;
}

public Path retrieveCachedFile(String cacheId, String objectId) {
Path p = caches.get(cacheId).retrieveCachedFile(objectId);
return p;

}

public void removeCachedFile(String cacheId, String objectId) {
caches.get(cacheId).removeCachedFile(objectId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.mycore.jspdocportal.diskcache.generator;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.BiConsumer;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* Simple Generator as Demonstrator for DiskLRUCache
* It simply saves the cache key as value.
*
* @author Robert Stephan
*/

public class SimpleGenerator implements BiConsumer<String, Path> {
private static Logger LOGGER = LogManager.getLogger(SimpleGenerator.class);

@Override
public void accept(String t, Path p) {
try {
Files.writeString(p, t);
} catch (IOException e) {
LOGGER.error(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
MCR.Diskcache.EnabledCaches=hello,iiif-manifest,dv-mets

MCR.Diskcache.Default.FileName=cached.xml
MCR.Diskcache.Default.MimeType=application/xml
MCR.Diskcache.Default.BaseDir=%MCR.datadir%/diskcaches
MCR.Diskcache.Default.LivespanInMillis=3600000
MCR.Diskcache.Default.MaxSizeInBytes=50000000
MCR.Diskcache.Default.MaxCount=50
MCR.Diskcache.Default.Version=1
##ToDo not Supported by @MCRInstance-Annotation
#MCR.Diskcache.Default.Generator=org.mycore.jspdocportal.diskcache.generator.SimpleGenerator

MCR.Diskcache.Cache.iiif-manifest.FileName=/manifest
MCR.Diskcache.Cache.iiif-manifest.MimeType=application/json

MCR.Diskcache.Cache.dv-mets.FileName=%%id%%_dv.mets.xml
MCR.Diskcache.Cache.iiif-manifest.MimeType=application/xml

MCR.Diskcache.Cache.hello.FileName=hello
MCR.Diskcache.Cache.hello.MimeType=application/text
MCR.Diskcache.Cache.hello.Generator=org.mycore.jspdocportal.diskcache.generator.SimpleGenerator

0 comments on commit f4e4bd5

Please sign in to comment.