diff --git a/conf/core/cache.ccf b/conf/core/cache.ccf
index 87d1338a5cf70da9b551744bc154190965d4bb46..672c798d126e9c759e0c7a59a81702733aa4e7b3 100644
--- a/conf/core/cache.ccf
+++ b/conf/core/cache.ccf
@@ -1,3 +1,35 @@
+# default caching options
 jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
 jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
\ No newline at end of file
+jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+
+# Caching of the backend transactions
+jcs.region.BACKEND_UserRoles.cacheattributes.MaxObjects=100
+jcs.region.BACKEND_Users.cacheattributes.MaxObjects=100
+jcs.region.BACKEND_PermissionRules.cacheattributes.MaxObjects=1000
+
+jcs.region.BACKEND_SparseEntities.cacheattributes.MaxObjects=1000
+jcs.region.BACKEND_EntityProperties.cacheattributes.MaxObjects=1000
+jcs.region.BACKEND_EntityParents.cacheattributes.MaxObjects=1000
+jcs.region.BACKEND_SparseFileRecordsByPath.cacheattributes.MaxObjects=1000
+
+jcs.region.BACKEND_JobRules.cacheattributes.MaxObjects=100
+
+
+# PAM UserSource Caching: Cached Items expire after 60 seconds if they are not requested (idle) and after 600 seconds max.
+# PAM_UnixUserGroups
+jcs.region.PAM_UnixUserGroups.elementattributes.IsEternal=false
+jcs.region.PAM_UnixUserGroups.elementattributes.MaxLife=600
+jcs.region.PAM_UnixUserGroups.elementattributes.IdleTime=60
+
+# PAM_UnixUserExists
+jcs.region.PAM_UnixUserExists.elementattributes.IsEternal=false
+jcs.region.PAM_UnixUserExists.elementattributes.MaxLife=600
+jcs.region.PAM_UnixUserExists.elementattributes.IdleTime=60
+
+# PAM_Authentication
+jcs.region.PAM_Authentication.elementattributes.IsEternal=false
+jcs.region.PAM_Authentication.elementattributes.MaxLife=600
+jcs.region.PAM_Authentication.elementattributes.IdleTime=60
+
+
diff --git a/conf/core/log4j2-default.properties b/conf/core/log4j2-default.properties
index ab7aed268e1e1e1a4088796d68b9e065086b5958..b1697a73fe6703850865406e1441947614d00f47 100644
--- a/conf/core/log4j2-default.properties
+++ b/conf/core/log4j2-default.properties
@@ -12,6 +12,11 @@ appender.stderr.name = stderr
 appender.stderr.layout.type = PatternLayout
 appender.stderr.layout.pattern = [%d{yy-MMM-dd HH:mm:ss:SSS}] [%p] [%c{1}:%L] - %m%n
 appender.stderr.target = SYSTEM_ERR
+appender.stderr.filter.threshold.type = ThresholdFilter
+appender.stderr.filter.threshold.level = INFO
+appender.stderr.filter.threshold.onMatch = ACCEPT
+appender.stderr.filter.threshold.onMismatch = DENY
+
 
 # ${LOG_DIR}/request_errors/...log
 appender.request_errors.type = RollingRandomAccessFile
diff --git a/conf/core/server.conf b/conf/core/server.conf
index 00b3b1a33dbab19f9931424cc91b5b11f9d137e3..882c4453f1dd2f11eb36bf6a534e0ba26b249c62 100644
--- a/conf/core/server.conf
+++ b/conf/core/server.conf
@@ -50,13 +50,6 @@ BUGTRACKER_URI=
 TRANSACTION_BENCHMARK_ENABLED=true
 CACHE_CONF_LOC=./conf/core/cache.ccf
 
-RULES_CACHE_CAPACITY=100
-SPARSE_ENTITY_CACHE_CAPACITY=1000
-PROPERTIES_CACHE_CAPACITY=1000
-PARENTS_CACHE_CAPACITY=1000
-USER_ACCOUNT_CACHE_CAPACITY=100
-GROUP_CACHE_CAPACITY=100
-
 INSERT_FILES_IN_DIR_ALLOWED_DIRS=
 
 SUDO_PASSWORD=
@@ -70,4 +63,4 @@ CERTIFICATES_KEY_PASSWORD=
 CERTIFICATES_KEY_STORE_PATH=
 CERTIFICATES_KEY_STORE_PASSWORD=
 
-WEBUI_HTTP_HEADER_CACHE_MAX_AGE=28800
\ No newline at end of file
+WEBUI_HTTP_HEADER_CACHE_MAX_AGE=28800
diff --git a/makefile b/makefile
index 07d01edfd116d57cf46d1290df738626d3c5b769..53c822deac4faaa058d7b1a04329abf2eb03d0bb 100644
--- a/makefile
+++ b/makefile
@@ -4,6 +4,8 @@
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+# Copyright (C) 2019 IndiScale GmbH
+# Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as
@@ -22,6 +24,7 @@
 #
 
 SHELL:=/bin/bash
+JPDA_PORT ?= 9000
 
 compile: easy-units
 	mvn compile
@@ -33,7 +36,7 @@ run: compile
 	mvn exec:java@run
 
 run-debug: jar
-	java -Xrunjdwp:transport=dt_socket,address=0.0.0.0:9000,server=y,suspend=n -Dcaosdb.debug=true -jar target/caosdb-server-0.1-SNAPSHOT-jar-with-dependencies.jar
+	java -Xrunjdwp:transport=dt_socket,address=0.0.0.0:$(JPDA_PORT),server=y,suspend=n -Dcaosdb.debug=true -jar target/caosdb-server-0.1-SNAPSHOT-jar-with-dependencies.jar
 
 run-single:
 	java -jar target/caosdb-server-0.1-SNAPSHOT-jar-with-dependencies.jar
diff --git a/src/main/java/caosdb/server/ServerProperties.java b/src/main/java/caosdb/server/ServerProperties.java
index 929f845d8023dc9d81c62294a5318442fcfb52ea..e68016894d65a3b77e38aa2f84f48ece7db05683 100644
--- a/src/main/java/caosdb/server/ServerProperties.java
+++ b/src/main/java/caosdb/server/ServerProperties.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -90,13 +92,6 @@ public class ServerProperties extends Properties {
 
   public static final String KEY_CACHE_CONF_LOC = "CACHE_CONF_LOC";
 
-  public static final String KEY_RULES_CACHE_CAPACITY = "RULES_CACHE_CAPACITY";
-  public static final String KEY_SPARSE_ENTITY_CACHE_CAPACITY = "SPARSE_ENTITY_CACHE_CAPACITY";
-  public static final String KEY_PROPERTIES_CACHE_CAPACITY = "PROPERTIES_CACHE_CAPACITY";
-  public static final String KEY_PARENTS_CACHE_CAPACITY = "PARENTS_CACHE_CAPACITY";
-  public static final String KEY_USER_ACCOUNT_CACHE_CAPACITY = "USER_ACCOUNT_CACHE_CAPACITY";
-  public static final String KEY_GROUP_CACHE_CAPACITY = "GROUP_CACHE_CAPACITY";
-
   public static final String KEY_TRANSACTION_BENCHMARK_ENABLED = "TRANSACTION_BENCHMARK_ENABLED";
 
   public static final String KEY_INSERT_FILES_IN_DIR_ALLOWED_DIRS =
diff --git a/src/main/java/caosdb/server/accessControl/Pam.java b/src/main/java/caosdb/server/accessControl/Pam.java
index c222fb83dabe0e4ad4e99d096d33192bf65086a9..99f68faadc15c15d9404a504d15669f0c2604ea3 100644
--- a/src/main/java/caosdb/server/accessControl/Pam.java
+++ b/src/main/java/caosdb/server/accessControl/Pam.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,23 +24,38 @@
  */
 package caosdb.server.accessControl;
 
+import caosdb.server.caching.Cache;
 import java.io.File;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.shiro.authz.AuthorizationException;
 import org.jvnet.libpam.PAMException;
 import org.jvnet.libpam.UnixUser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
+/**
+ * PAM UserSource for authenticating users via the Host's pam module.
+ *
+ * <p>A User's existence check and the retrieval of a user's groups is done by the org.jvnet.libpam
+ * library.
+ *
+ * <p>The authentication of a user via the password need root-access and is therefore done by a
+ * special shell script running with root privileges on the host.
+ *
+ * @author Timm Fitschen (t.fitschen@indiscale.com)
+ */
 public class Pam implements UserSource {
 
+  private Logger logger = LogManager.getLogger(Pam.class);
+
   public static class DefaultPamScriptCaller implements PamScriptCaller {
 
-    private Logger logger = LoggerFactory.getLogger(getClass());
+    private Logger logger = LogManager.getLogger(Pam.class);
 
     private final String pam_script;
 
@@ -64,7 +81,7 @@ public class Pam implements UserSource {
 
       try {
         pam_authentication = getProcess(username, password);
-        logger.info("call pam script");
+        logger.trace("call pam script");
         return pam_authentication.waitFor() == 0;
       } catch (final IOException e) {
         throw new RuntimeException(e);
@@ -75,6 +92,11 @@ public class Pam implements UserSource {
   }
 
   public static final String DEFAULT_PAM_SCRIPT = "./misc/pam_authentication/pam_authentication.sh";
+
+  /*
+   * following constants are the names of the configuration parameters and parts of parameters in
+   * the user_sources.ini for the pam user source.
+   */
   public static final String KEY_PAM_SCRIPT = "pam_script";
   public static final String KEY_DEFAULT_USER_STATUS = "default_status";
   public static final String KEY_GROUP = "group";
@@ -83,8 +105,9 @@ public class Pam implements UserSource {
   public static final String KEY_INCLUDE = "include";
   public static final String KEY_ROLES = "roles";
   public static final String SEPARATOR = ".";
+  public static final String KEY_EMAIL = "email";
   public static final String REGEX_SPLIT_CSV = "\\s*,\\s*";
-  private static final String KEY_EMAIL = "email";
+
   private String[] EXCLUDE_USERS = null;
   private String[] INCLUDE_USERS = null;
   private String[] EXCLUDE_GROUPS = null;
@@ -92,16 +115,28 @@ public class Pam implements UserSource {
   private Map<String, String> map = null;
   private PamScriptCaller pamScriptCaller = null;
 
+  /* Caches for groups, user-existence and password validation */
+
+  private ICacheAccess<String, HashSet<String>> groupsCache = Cache.getCache("PAM_UnixUserGroups");
+  private ICacheAccess<String, Boolean> userExistsCache = Cache.getCache("PAM_UnixUserExists");
+  private ICacheAccess<String, Boolean> passwordValidCache = Cache.getCache("PAM_Authentication");
+
   @Override
   public void setMap(final Map<String, String> map) {
     this.map = map;
     this.pamScriptCaller = null;
   }
 
-  public Map<String, String> getMap() {
+  /**
+   * Return the current configuration of this user source.
+   *
+   * @return configuration.
+   */
+  private Map<String, String> getMap() {
     return this.map;
   }
 
+  /** @see {@link UserSource#resolveRolesForUsername(String)} */
   @Override
   public Set<String> resolveRolesForUsername(final String username) {
     final Set<String> resulting_roles = new HashSet<String>();
@@ -138,7 +173,40 @@ public class Pam implements UserSource {
     return resulting_roles;
   }
 
-  private static Set<String> getGroups(final String username) {
+  /**
+   * Get the UNIX groups of the user.
+   *
+   * <p>First, try to get them from the cache. Only ask the back-end if necessary and cache the
+   * results.
+   *
+   * @param username
+   * @return A user's UNIX groups.
+   */
+  private Set<String> getGroups(final String username) {
+    Set<String> cached = groupsCache.get(username);
+    if (cached != null) {
+      return cached;
+    }
+
+    Set<String> uncached = getGroupsNoCache(username);
+    if (uncached instanceof HashSet) {
+      groupsCache.put(username, (HashSet<String>) uncached);
+    } else {
+      groupsCache.put(username, new HashSet<String>(uncached));
+    }
+    return uncached;
+  }
+
+  /**
+   * Get the UNIX groups of the user directly from the back-end.
+   *
+   * <p>If the user does not exist, an empty set is returned.
+   *
+   * @param username
+   * @return A user's UNIX groups or an empty set.
+   */
+  private Set<String> getGroupsNoCache(final String username) {
+    logger.trace("Retrieving UnixGroups", username);
     if (UnixUser.exists(username)) {
       try {
         return new UnixUser(username).getGroups();
@@ -146,7 +214,7 @@ public class Pam implements UserSource {
         throw new AuthorizationException(e);
       }
     }
-    return null;
+    return new HashSet<String>();
   }
 
   @Override
@@ -154,11 +222,38 @@ public class Pam implements UserSource {
     return "PAM";
   }
 
+  /**
+   * Check if that user is known by the host's PAM.
+   *
+   * <p>Try the cache first. Only ask PAM directly if necessary and cache the results.
+   *
+   * @see {@link UserSource#isUserExisting(String)}.
+   * @return true iff the user is known.
+   */
   @Override
   public boolean isUserExisting(final String username) {
+    Boolean cached = userExistsCache.get(username);
+    if (cached != null) {
+      return cached;
+    }
+
+    boolean uncached = isUserExistingNoCache(username);
+    userExistsCache.put(username, uncached);
+    return uncached;
+  }
+
+  /**
+   * Check if that user is known by the host's PAM (without caching).
+   *
+   * @param username
+   * @return true iff the user is known.
+   */
+  private boolean isUserExistingNoCache(final String username) {
+    logger.trace("Check UnixUser.exists", username);
     return username != null && UnixUser.exists(username) && isIncorporated(username);
   }
 
+  /** @see {@link UserSource#isValid(String, String)}. */
   @Override
   public boolean isValid(final String username, final String password) {
     if (isUserExisting(username)) {
@@ -174,8 +269,40 @@ public class Pam implements UserSource {
     return this.pamScriptCaller;
   }
 
+  /**
+   * Check the validity of the password for that user by asking the pam script caller.
+   *
+   * <p>Try the cache first, only call the pam script if necessary and cache the results.
+   *
+   * @param caller
+   * @param username
+   * @param password
+   * @return true iff the password is correct.
+   */
   private boolean isValid(
       final PamScriptCaller caller, final String username, final String password) {
+    String key = "<" + password + "::" + username + ">";
+    Boolean cached = passwordValidCache.get(key);
+    if (cached != null) {
+      return cached;
+    }
+
+    boolean uncached = isValidNoCache(caller, username, password);
+    passwordValidCache.put(key, uncached);
+    return uncached;
+  }
+
+  /**
+   * Check the validity of the password for that user by asking the pam script caller.
+   *
+   * @param caller
+   * @param username
+   * @param password
+   * @return true iff the password is correct.
+   */
+  private boolean isValidNoCache(
+      final PamScriptCaller caller, final String username, final String password) {
+    logger.trace("Check Password", username);
     return caller.isValid(username, password);
   }
 
@@ -278,10 +405,15 @@ public class Pam implements UserSource {
           ret = n;
         } else if (ret != n) {
           // conflict -> ignore, go for pam-wide setting
+          ret = null;
           break;
         }
       }
     }
+
+    if (ret != null) {
+      return ret;
+    }
     // by pam-wide setting
     if (this.map.containsKey(KEY_DEFAULT_USER_STATUS)) {
       return UserStatus.valueOf(this.map.get(KEY_DEFAULT_USER_STATUS).toUpperCase());
diff --git a/src/main/java/caosdb/server/accessControl/UserSource.java b/src/main/java/caosdb/server/accessControl/UserSource.java
index 23ce7c45ce6cb9982ae5c7fac05a3a41037a5afe..0ece8d5014227916feb1c50b986aaf4d9a9bf91b 100644
--- a/src/main/java/caosdb/server/accessControl/UserSource.java
+++ b/src/main/java/caosdb/server/accessControl/UserSource.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -25,19 +27,84 @@ package caosdb.server.accessControl;
 import java.util.Map;
 import java.util.Set;
 
+/**
+ * UserSources are sources for users - i.e. they authenticate users and contain basic information
+ * about users.
+ *
+ * <p>UserSources let you
+ * <li>check if a user exists - {@link #isUserExisting(String)}
+ * <li>authenticate a user via a password - {@link #isValid(String, String)}
+ * <li>get the default {@link UserStatus} - {@link #getDefaultUserStatus(String)}
+ * <li>get the default email address - {@link #getDefaultUserEmail(String)}
+ * <li>retrieve a users roles - {@link #resolveRolesForUsername(String)} The default email and
+ *     default {@link UserStatus} might be overridden by other settings in CaosDB - that's why they
+ *     are called "default".
+ *
+ *     <p>Also, the user's roles might be overridden by the internal user source {@link
+ *     InternalUserSource}.
+ *
+ *     <p>A UserSource is configured via {@link #setMap(Map)}.
+ *
+ * @author Timm Fitschen (t.fitschen@indiscale.com)
+ */
 public interface UserSource {
 
+  /**
+   * Every UserSource has a unique name, e.g. PAM, CaosDB (which is default name of the internal
+   * user source {@link InternalUserSource}).
+   *
+   * @return name
+   */
   public String getName();
 
+  /**
+   * Check if a user exists.
+   *
+   * @param username
+   * @return true iff this user source knows a user with that name
+   */
   public boolean isUserExisting(String username);
 
+  /**
+   * Return all roles that a user is associated with.
+   *
+   * @param username
+   * @return a user's roles
+   */
   public Set<String> resolveRolesForUsername(final String username);
 
+  /**
+   * Configure this user source. The needed parameters are to be defined and documented by the
+   * implementations.
+   *
+   * @param map the configuration
+   */
   public void setMap(Map<String, String> map);
 
+  /**
+   * Return the {@link UserStatus} of that user.
+   *
+   * @param username
+   * @return The user status of that user
+   */
   public UserStatus getDefaultUserStatus(String username);
 
+  /**
+   * Return the email address of that user, or null if none is available as per this user source.
+   *
+   * <p>This method does not check if a user exists. So it will return null for unknown users.
+   *
+   * @param username
+   * @return The email address or null
+   */
   public String getDefaultUserEmail(String username);
 
+  /**
+   * Check if the user can be authenticated by the given password.
+   *
+   * @param username
+   * @param password
+   * @return true iff the password was correct.
+   */
   public boolean isValid(String username, String password);
 }
diff --git a/src/main/java/caosdb/server/caching/Cache.java b/src/main/java/caosdb/server/caching/Cache.java
new file mode 100644
index 0000000000000000000000000000000000000000..338b1d853fd0610be780362a0242193fa46eb320
--- /dev/null
+++ b/src/main/java/caosdb/server/caching/Cache.java
@@ -0,0 +1,50 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2018 Research Group Biomedical Physics,
+ * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+package caosdb.server.caching;
+
+import java.io.Serializable;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
+
+/**
+ * Caching Helper Class used for all caches in the CaosDB Server.
+ *
+ * <p>The actual work is delegated to an instance of {@link JCSCacheHelper}. However, the delegate
+ * {@link #DELEGATE} can be be overridden for testing purposes with {@link #setDelegate(Cache)}.
+ *
+ * @author Timm Fitschen (t.fitschen@indiscale.com)
+ */
+public class Cache {
+
+  /** The default cache helper delegate. */
+  private static CacheHelper DELEGATE = new JCSCacheHelper();
+
+  public static void setDelegate(CacheHelper delegate) {
+    DELEGATE = delegate;
+  }
+
+  public static final <K, V extends Serializable> ICacheAccess<K, V> getCache(String region) {
+    return DELEGATE.getCache(region);
+  }
+}
diff --git a/src/main/java/caosdb/server/caching/CacheHelper.java b/src/main/java/caosdb/server/caching/CacheHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..32c854400310959a7834fe32a6f90de9e1b584d1
--- /dev/null
+++ b/src/main/java/caosdb/server/caching/CacheHelper.java
@@ -0,0 +1,31 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+package caosdb.server.caching;
+
+import java.io.Serializable;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
+
+public interface CacheHelper {
+
+  public <K, V extends Serializable> ICacheAccess<K, V> getCache(String region);
+}
diff --git a/src/main/java/caosdb/server/caching/JCSCacheHelper.java b/src/main/java/caosdb/server/caching/JCSCacheHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..dab2b77ceaab3d0caaf49d798a4819ca890b5e82
--- /dev/null
+++ b/src/main/java/caosdb/server/caching/JCSCacheHelper.java
@@ -0,0 +1,91 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2018 Research Group Biomedical Physics,
+ * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+package caosdb.server.caching;
+
+import caosdb.server.CaosDBServer;
+import caosdb.server.ServerProperties;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.Properties;
+import org.apache.commons.jcs.JCS;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * A CacheHelper implementation which is configured statically via the {@link
+ * ServerProperties#KEY_CACHE_CONF_LOC} properties file.
+ *
+ * @author Timm Fitschen (t.fitschen@indiscale.com)
+ */
+public class JCSCacheHelper implements CacheHelper {
+
+  protected static Logger logger = LogManager.getLogger(JCSCacheHelper.class);
+
+  // A No-Operation configuration for JCS
+  private static Properties getNOPCachingProperties() {
+    Properties ret = new Properties();
+    ret.setProperty(
+        "jcs.default.cacheattributes", "org.apache.commons.jcs.engine.CompositeCacheAttributes");
+    ret.setProperty("jcs.default.cacheattributes.MaxObjects", "0");
+    return ret;
+  }
+
+  // configure JCS
+  static {
+    Properties config = null;
+    try {
+      Properties p = new Properties();
+      final InputStream is =
+          new FileInputStream(CaosDBServer.getServerProperty(ServerProperties.KEY_CACHE_CONF_LOC));
+      p.load(is);
+      is.close();
+      config = p;
+    } catch (final FileNotFoundException e) {
+      logger.error(e);
+      config = getNOPCachingProperties();
+    } catch (final IOException e) {
+      logger.error(e);
+      config = getNOPCachingProperties();
+    }
+    logger.info("Configuring JCS Caching with {}", config);
+    JCS.setConfigProperties(config);
+  }
+
+  @Override
+  public <K, V extends Serializable> ICacheAccess<K, V> getCache(final String name) {
+    final ICacheAccess<K, V> cache = JCS.getInstance(name);
+    logger.info(
+        "Caching configuration for {}:\n+----{}\n+----{}",
+        name,
+        cache.getCacheAttributes(),
+        cache.getDefaultElementAttributes());
+
+    return cache;
+  }
+}
diff --git a/src/main/java/caosdb/server/database/CacheableBackendTransaction.java b/src/main/java/caosdb/server/database/CacheableBackendTransaction.java
index 390a177fe899f89330aeb3d0959aab5bf1d52cbc..fc4c9659d9a8ea80393bebad945bd6badf9580c4 100644
--- a/src/main/java/caosdb/server/database/CacheableBackendTransaction.java
+++ b/src/main/java/caosdb/server/database/CacheableBackendTransaction.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -24,14 +26,19 @@ package caosdb.server.database;
 
 import caosdb.server.database.exceptions.TransactionException;
 import java.io.Serializable;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public abstract class CacheableBackendTransaction<K, V extends Serializable>
     extends BackendTransaction {
 
-  public abstract V executeNoCache() throws TransactionException;
-
   private Boolean cached = null;
+  private ICacheAccess<K, V> cache;
+
+  public CacheableBackendTransaction(ICacheAccess<K, V> cache) {
+    this.cache = cache;
+  }
+
+  public abstract V executeNoCache() throws TransactionException;
 
   @Override
   public final void execute() throws TransactionException {
@@ -67,8 +74,8 @@ public abstract class CacheableBackendTransaction<K, V extends Serializable>
 
   protected abstract K getKey();
 
-  protected CacheAccess<K, V> getCache() {
-    return null;
+  protected final ICacheAccess<K, V> getCache() {
+    return cache;
   }
 
   private final boolean cacheIsEnabled() {
diff --git a/src/main/java/caosdb/server/database/backend/transaction/DeleteSparseEntity.java b/src/main/java/caosdb/server/database/backend/transaction/DeleteSparseEntity.java
index 4bd6e5b9706fe743be6c924c3e1f86cb6ff83371..39deb1416c743f838bfc1b96c29fd845dbcef742 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/DeleteSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/DeleteSparseEntity.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -41,6 +43,9 @@ public class DeleteSparseEntity extends BackendTransaction {
   @Override
   protected void execute() {
     RetrieveSparseEntity.removeCached(this.entity.getId());
+    if (entity.hasFileProperties()) {
+      GetFileRecordByPath.removeCached(this.entity.getFileProperties().getPath());
+    }
 
     final DeleteSparseEntityImpl ret = getImplementation(DeleteSparseEntityImpl.class);
 
diff --git a/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java b/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java
index 195f16db5341fdcd204debbaad0217635d1fd222..8e0afcbdc50985f1fa1a939940c05f8429562c90 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,20 +24,31 @@
  */
 package caosdb.server.database.backend.transaction;
 
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.backend.interfaces.GetFileRecordByPathImpl;
 import caosdb.server.database.exceptions.TransactionException;
 import caosdb.server.database.proto.SparseEntity;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class GetFileRecordByPath extends CacheableBackendTransaction<String, SparseEntity> {
 
+  private static final ICacheAccess<String, SparseEntity> cache =
+      Cache.getCache("BACKEND_SparseFileRecordsByPath");
   private final String path;
   private SparseEntity entity;
 
   public GetFileRecordByPath(final String path) {
+    super(cache);
     this.path = path;
   }
 
+  public static void removeCached(final String path) {
+    if (path != null && cache != null) {
+      cache.remove(path);
+    }
+  }
+
   @Override
   protected String getKey() {
     return this.path;
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveParents.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveParents.java
index 5d1545d29b9bab295c9f335fe4eb083f12f748b2..5c1b0178f51496f83a4fac6a4ce3b2447abdccd5 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveParents.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveParents.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,26 +24,21 @@
  */
 package caosdb.server.database.backend.transaction;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.DatabaseUtils;
 import caosdb.server.database.backend.interfaces.RetrieveParentsImpl;
 import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.database.misc.Cache;
 import caosdb.server.database.proto.VerySparseEntity;
 import caosdb.server.entity.EntityInterface;
 import java.util.ArrayList;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrieveParents
     extends CacheableBackendTransaction<Integer, ArrayList<VerySparseEntity>> {
 
-  private static final CacheAccess<Integer, ArrayList<VerySparseEntity>> cache =
-      Cache.getCache(
-          "ParentsCache",
-          Integer.valueOf(
-              CaosDBServer.getServerProperty(ServerProperties.KEY_SPARSE_ENTITY_CACHE_CAPACITY)));
+  private static final ICacheAccess<Integer, ArrayList<VerySparseEntity>> cache =
+      Cache.getCache("BACKEND_EntityParents");
 
   /**
    * To be called by DeleteEntityProperties on execution.
@@ -54,14 +51,10 @@ public class RetrieveParents
     }
   }
 
-  @Override
-  protected CacheAccess<Integer, ArrayList<VerySparseEntity>> getCache() {
-    return cache;
-  }
-
   private final EntityInterface entity;
 
   public RetrieveParents(final EntityInterface entity) {
+    super(cache);
     this.entity = entity;
   }
 
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrievePermissionRules.java b/src/main/java/caosdb/server/database/backend/transaction/RetrievePermissionRules.java
index c0daecbc46ac90630eac83d0c7334d7da148d429..7e9925777c21a6d041759cfdade7682b85458566 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrievePermissionRules.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrievePermissionRules.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,28 +24,24 @@
  */
 package caosdb.server.database.backend.transaction;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.backend.interfaces.RetrievePermissionRulesImpl;
 import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.database.misc.Cache;
 import caosdb.server.permissions.PermissionRule;
 import java.util.HashSet;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrievePermissionRules
     extends CacheableBackendTransaction<String, HashSet<PermissionRule>> {
 
-  private static final CacheAccess<String, HashSet<PermissionRule>> cache =
-      Cache.getCache(
-          "PermissionRulesCache",
-          Integer.valueOf(
-              CaosDBServer.getServerProperty(ServerProperties.KEY_GROUP_CACHE_CAPACITY)));
+  private static final ICacheAccess<String, HashSet<PermissionRule>> cache =
+      Cache.getCache("BACKEND_PermissionRules");
   private HashSet<PermissionRule> rules;
   private final String role;
 
   public RetrievePermissionRules(final String role) {
+    super(cache);
     this.role = role;
   }
 
@@ -51,11 +49,6 @@ public class RetrievePermissionRules
     cache.remove(role);
   }
 
-  @Override
-  protected CacheAccess<String, HashSet<PermissionRule>> getCache() {
-    return cache;
-  }
-
   @Override
   public HashSet<PermissionRule> executeNoCache() throws TransactionException {
     final RetrievePermissionRulesImpl t = getImplementation(RetrievePermissionRulesImpl.class);
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveProperties.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveProperties.java
index b75d91acba76a4d97b16395701afe42ff05c5fac..650cae3676ed2b6b50f86c76a5ce92b195290fc3 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveProperties.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveProperties.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,29 +24,24 @@
  */
 package caosdb.server.database.backend.transaction;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.DatabaseUtils;
 import caosdb.server.database.backend.interfaces.RetrievePropertiesImpl;
 import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.database.misc.Cache;
 import caosdb.server.database.proto.ProtoProperty;
 import caosdb.server.entity.EntityInterface;
 import caosdb.server.entity.Role;
 import caosdb.server.entity.wrapper.Property;
 import java.util.ArrayList;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrieveProperties
     extends CacheableBackendTransaction<Integer, ArrayList<ProtoProperty>> {
 
   private final EntityInterface entity;
-  private static final CacheAccess<Integer, ArrayList<ProtoProperty>> cache =
-      Cache.getCache(
-          "PropertiesCache",
-          Integer.valueOf(
-              CaosDBServer.getServerProperty(ServerProperties.KEY_PROPERTIES_CACHE_CAPACITY)));
+  private static final ICacheAccess<Integer, ArrayList<ProtoProperty>> cache =
+      Cache.getCache("BACKEND_EntityProperties");
 
   /**
    * To be called by DeleteEntityProperties on execution.
@@ -57,12 +54,8 @@ public class RetrieveProperties
     }
   }
 
-  @Override
-  protected CacheAccess<Integer, ArrayList<ProtoProperty>> getCache() {
-    return cache;
-  }
-
   public RetrieveProperties(final EntityInterface entity) {
+    super(cache);
     this.entity = entity;
   }
 
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveRole.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveRole.java
index e45879964ef8bafad0106238073ff8c9d87e2287..5bb6150a8640f45997a4a3432ad4ac27196cd15c 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveRole.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveRole.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,36 +24,26 @@
  */
 package caosdb.server.database.backend.transaction;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
 import caosdb.server.accessControl.Role;
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.backend.interfaces.RetrieveRoleImpl;
 import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.database.misc.Cache;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrieveRole extends CacheableBackendTransaction<String, Role> {
 
-  private static final CacheAccess<String, Role> cache =
-      Cache.getCache(
-          "RolesCache",
-          Integer.valueOf(
-              CaosDBServer.getServerProperty(ServerProperties.KEY_GROUP_CACHE_CAPACITY)));
+  private static final ICacheAccess<String, Role> cache = Cache.getCache("BACKEND_UserRoles");
 
   private final String role_name;
   private Role role;
 
-  @Override
-  protected CacheAccess<String, Role> getCache() {
-    return cache;
-  }
-
   public Role getRole() {
     return this.role;
   }
 
   public RetrieveRole(final String role) {
+    super(cache);
     this.role_name = role;
   }
 
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java
index df9f58671184fb70fca99ca7707f9270f75c87a1..a91b5021f1fa722a8e8831234fc8ebc2032ba115 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,30 +24,25 @@
  */
 package caosdb.server.database.backend.transaction;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.DatabaseUtils;
 import caosdb.server.database.backend.interfaces.RetrieveSparseEntityImpl;
 import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.database.misc.Cache;
 import caosdb.server.database.proto.SparseEntity;
 import caosdb.server.entity.Entity;
 import caosdb.server.entity.EntityInterface;
 import caosdb.server.utils.EntityStatus;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrieveSparseEntity extends CacheableBackendTransaction<Integer, SparseEntity> {
 
   private final EntityInterface entity;
-  private static final CacheAccess<Integer, SparseEntity> cache =
-      Cache.getCache(
-          "SparseEntityCache",
-          Integer.valueOf(
-              CaosDBServer.getServerProperty(ServerProperties.KEY_SPARSE_ENTITY_CACHE_CAPACITY)));
+  private static final ICacheAccess<Integer, SparseEntity> cache =
+      Cache.getCache("BACKEND_SparseEntities");
 
   /**
-   * To be called by UpdateSparseEntity and DeleteEntity on execution.
+   * To be called by {@link UpdateSparseEntity} and {@link DeleteEntity} on execution.
    *
    * @param id
    */
@@ -55,17 +52,13 @@ public class RetrieveSparseEntity extends CacheableBackendTransaction<Integer, S
     }
   }
 
-  @Override
-  protected CacheAccess<Integer, SparseEntity> getCache() {
-    return cache;
-  }
-
   public RetrieveSparseEntity(final EntityInterface entity) {
+    super(cache);
     this.entity = entity;
   }
 
   public RetrieveSparseEntity(final int id) {
-    this.entity = new Entity(id);
+    this(new Entity(id));
   }
 
   @Override
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveTransactionHistory.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveTransactionHistory.java
index cb9cdd9e993b9399f2bec5c9bff7316e0754b9ed..72bc1e5b1ec3a3509cc5cbba23e38b908d4e969f 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveTransactionHistory.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveTransactionHistory.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -23,17 +25,15 @@
 package caosdb.server.database.backend.transaction;
 
 import caosdb.datetime.UTCDateTime;
-import caosdb.server.database.CacheableBackendTransaction;
+import caosdb.server.database.BackendTransaction;
 import caosdb.server.database.backend.interfaces.RetrieveTransactionHistoryImpl;
 import caosdb.server.database.exceptions.TransactionException;
 import caosdb.server.database.proto.ProtoTransactionLogMessage;
 import caosdb.server.entity.EntityInterface;
 import caosdb.server.utils.TransactionLogMessage;
 import java.util.ArrayList;
-import org.apache.commons.jcs.access.CacheAccess;
 
-public class RetrieveTransactionHistory
-    extends CacheableBackendTransaction<Integer, ArrayList<ProtoTransactionLogMessage>> {
+public class RetrieveTransactionHistory extends BackendTransaction {
 
   private final EntityInterface entity;
 
@@ -42,25 +42,13 @@ public class RetrieveTransactionHistory
   }
 
   @Override
-  protected Integer getKey() {
-    return this.entity.getId();
-  }
-
-  @Override
-  protected CacheAccess<Integer, ArrayList<ProtoTransactionLogMessage>> getCache() {
-    return null;
-  }
-
-  @Override
-  public ArrayList<ProtoTransactionLogMessage> executeNoCache() throws TransactionException {
+  protected void execute() {
     final RetrieveTransactionHistoryImpl t =
         getImplementation(RetrieveTransactionHistoryImpl.class);
-    return t.execute(getKey());
+    process(t.execute(entity.getId()));
   }
 
-  @Override
-  protected void process(final ArrayList<ProtoTransactionLogMessage> l)
-      throws TransactionException {
+  private void process(final ArrayList<ProtoTransactionLogMessage> l) throws TransactionException {
     for (final ProtoTransactionLogMessage t : l) {
       final UTCDateTime dateTime = UTCDateTime.UTCSeconds(t.seconds, t.nanos);
 
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveUser.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveUser.java
index 7492df38adfcfd24d18f1a263be5070a8916c9c8..9f27152030f5c953ee7bd4ecfff8c83d3cbc8a73 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveUser.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveUser.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,43 +24,29 @@
  */
 package caosdb.server.database.backend.transaction;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
 import caosdb.server.accessControl.Principal;
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.backend.interfaces.RetrieveUserImpl;
 import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.database.misc.Cache;
 import caosdb.server.database.proto.ProtoUser;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrieveUser extends CacheableBackendTransaction<Principal, ProtoUser> {
 
   private ProtoUser user;
-  private static final CacheAccess<Principal, ProtoUser> cache =
-      Cache.getCache(
-          "UserAccountCache",
-          Integer.valueOf(
-              CaosDBServer.getServerProperty(ServerProperties.KEY_USER_ACCOUNT_CACHE_CAPACITY)));
+  private static final ICacheAccess<Principal, ProtoUser> cache = Cache.getCache("BACKEND_Users");
   private final Principal principal;
 
-  /**
-   * To be called by DeleteSparseEntity, SetPassword, and UpdateSparseEntity on execution.
-   *
-   * @param u
-   */
+  /** To be called by DeleteSparseEntity, SetPassword, and UpdateSparseEntity on execution. */
   public static void removeCached(final Principal principal) {
     if (principal != null && cache != null) {
       cache.remove(principal);
     }
   }
 
-  @Override
-  protected CacheAccess<Principal, ProtoUser> getCache() {
-    return cache;
-  }
-
   public RetrieveUser(final Principal principal) {
+    super(cache);
     this.principal = principal;
   }
 
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RuleLoader.java b/src/main/java/caosdb/server/database/backend/transaction/RuleLoader.java
index 1a8698ac1d698946e7a3e239c03e386bc200e2b6..303029b42179a697c939767e2caf4d490a803a69 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RuleLoader.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RuleLoader.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,22 +24,22 @@
  */
 package caosdb.server.database.backend.transaction;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
+import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.backend.interfaces.RuleLoaderImpl;
 import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.database.misc.Cache;
 import caosdb.server.database.proto.Rule;
 import caosdb.server.entity.EntityInterface;
 import caosdb.server.entity.container.TransactionContainer;
 import caosdb.server.jobs.Job;
 import caosdb.server.transaction.Transaction;
 import java.util.ArrayList;
-import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RuleLoader extends CacheableBackendTransaction<String, ArrayList<Rule>> {
 
+  private static final ICacheAccess<String, ArrayList<Rule>> cache =
+      Cache.getCache("BACKEND_JobRules");
   private final Transaction<? extends TransactionContainer> transaction;
   private final EntityInterface e;
   private final Integer entity;
@@ -49,6 +51,7 @@ public class RuleLoader extends CacheableBackendTransaction<String, ArrayList<Ru
       final Integer entity,
       final EntityInterface e,
       final Transaction<? extends TransactionContainer> transaction) {
+    super(cache);
     this.domain = domain;
     this.entity = entity;
     this.e = e;
@@ -66,17 +69,6 @@ public class RuleLoader extends CacheableBackendTransaction<String, ArrayList<Ru
         + ">";
   }
 
-  @Override
-  protected CacheAccess<String, ArrayList<Rule>> getCache() {
-    return rulesCache;
-  }
-
-  private static CacheAccess<String, ArrayList<Rule>> rulesCache =
-      Cache.getCache(
-          "RulesCache",
-          Integer.valueOf(
-              CaosDBServer.getServerProperty(ServerProperties.KEY_RULES_CACHE_CAPACITY)));
-
   public ArrayList<Job> getJobs() {
     return this.jobs;
   }
diff --git a/src/main/java/caosdb/server/database/backend/transaction/UpdateSparseEntity.java b/src/main/java/caosdb/server/database/backend/transaction/UpdateSparseEntity.java
index 57d22ef226e83caf7e3b37b48b53c1025afaa93f..c6a1c7683409e0c875484e14553e4aeac2757a71 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/UpdateSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/UpdateSparseEntity.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 IndiScale GmbH
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -39,6 +41,9 @@ public class UpdateSparseEntity extends BackendTransaction {
   @Override
   public void execute() throws TransactionException {
     RetrieveSparseEntity.removeCached(this.entity.getId());
+    if (entity.hasFileProperties()) {
+      GetFileRecordByPath.removeCached(this.entity.getFileProperties().getPath());
+    }
 
     final UpdateSparseEntityImpl t = getImplementation(UpdateSparseEntityImpl.class);
 
diff --git a/src/main/java/caosdb/server/database/misc/Cache.java b/src/main/java/caosdb/server/database/misc/Cache.java
deleted file mode 100644
index 7f364d4ab3e2ddc2d3e5e0638be4fe5dfa252ccd..0000000000000000000000000000000000000000
--- a/src/main/java/caosdb/server/database/misc/Cache.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-package caosdb.server.database.misc;
-
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
-import caosdb.server.terminal.StatLabel;
-import caosdb.server.terminal.StatsPanel;
-import caosdb.server.utils.AbstractObservable;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.util.Properties;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-
-public class Cache {
-
-  static {
-    final Properties p = new Properties();
-    try {
-      final InputStream is =
-          new FileInputStream(CaosDBServer.getServerProperty(ServerProperties.KEY_CACHE_CONF_LOC));
-      p.load(is);
-      is.close();
-    } catch (final FileNotFoundException e) {
-      e.printStackTrace();
-    } catch (final IOException e) {
-      e.printStackTrace();
-    }
-    JCS.setConfigProperties(p);
-  }
-
-  public static <K, V extends Serializable> CacheAccess<K, V> getCache(
-      final String name, final int capacity) {
-    if (capacity > 0) {
-      final CacheAccess<K, V> cache = JCS.getInstance(name);
-      cache.getCacheAttributes().setMaxObjects(capacity);
-      StatsPanel.addStat(
-          name,
-          new AbstractObservable() {
-            @Override
-            public String toString() {
-              return cache.getStats();
-            };
-          });
-      StatsPanel.addStat(
-          name,
-          new StatLabel(
-              "Configuration", cache.getCacheAttributes().toString().replaceAll(",", "\n")));
-
-      return cache;
-    }
-    return null;
-  }
-}