From 6a71911b1e2712bf8dbfc02e8f94096fd03389e6 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Fri, 20 Mar 2020 23:46:07 +0100
Subject: [PATCH] EHN: versioning phases 4 & 5

---
 pom.xml                                       |  2 +-
 src/main/java/caosdb/server/CaosDBServer.java | 88 +++++++++----------
 .../caosdb/server/caching/JCSCacheHelper.java |  1 +
 .../caosdb/server/database/DatabaseUtils.java | 21 ++---
 .../implementation/MySQL/MySQLHelper.java     | 78 ++++++++--------
 .../MySQL/MySQLInsertSparseEntity.java        |  8 +-
 .../MySQL/MySQLRetrieveParents.java           | 11 ++-
 .../MySQL/MySQLRetrieveProperties.java        | 32 +++++--
 .../MySQLRetrieveQueryTemplateDefinition.java | 10 ++-
 .../MySQL/MySQLRetrieveSparseEntity.java      | 10 ++-
 .../MySQL/MySQLUpdateSparseEntity.java        | 14 +--
 .../interfaces/RetrieveParentsImpl.java       |  3 +-
 .../interfaces/RetrievePropertiesImpl.java    |  2 +-
 .../RetrieveQueryTemplateDefinitionImpl.java  |  2 +-
 .../interfaces/RetrieveSparseEntityImpl.java  |  2 +-
 .../transaction/DeleteEntityProperties.java   |  4 +-
 .../transaction/DeleteSparseEntity.java       |  2 +-
 .../transaction/InsertSparseEntity.java       |  1 +
 .../backend/transaction/RetrieveParents.java  | 17 ++--
 .../transaction/RetrieveProperties.java       | 16 ++--
 .../RetrieveQueryTemplateDefinition.java      |  3 +-
 .../transaction/RetrieveSparseEntity.java     | 18 ++--
 .../transaction/UpdateSparseEntity.java       |  4 +-
 .../database/misc/TransactionBenchmark.java   | 10 +--
 .../java/caosdb/server/entity/BaseEntity.java | 28 ------
 .../caosdb/server/entity/DeleteEntity.java    |  5 ++
 .../java/caosdb/server/entity/Entity.java     | 41 +++++----
 .../java/caosdb/server/entity/EntityID.java   | 25 ------
 .../caosdb/server/entity/EntityInterface.java | 12 +--
 .../caosdb/server/entity/NamedEntity.java     | 28 ------
 .../caosdb/server/entity/RetrieveEntity.java  | 11 ++-
 .../caosdb/server/entity/ValidEntity.java     |  1 -
 .../entity/container/DeleteContainer.java     |  5 ++
 .../entity/container/EntityByIdContainer.java |  2 +
 .../entity/container/RetrieveContainer.java   |  9 ++
 .../server/entity/wrapper/EntityWrapper.java  | 21 +++--
 .../entity/xml/EntityToElementStrategy.java   | 13 +--
 .../jobs/extension/AWIBoxLoanModel.java       | 10 ++-
 .../AbstractCaosDBServerResource.java         | 33 +------
 .../resource/PermissionRulesResource.java     |  4 +-
 .../caosdb/server/resource/RolesResource.java | 46 +++++-----
 .../caosdb/server/resource/UserResource.java  |  9 +-
 .../server/resource/UserRolesResource.java    |  4 +-
 .../resource/transaction/EntityResource.java  |  4 +-
 ...r.java => SimpleDeleteRequestHandler.java} | 24 +++--
 .../handlers/SimpleGetRequestHandler.java     | 24 ++++-
 .../caosdb/server/transaction/Insert.java     |  4 +-
 .../caosdb/server/transaction/Update.java     | 14 +--
 .../server/transaction/WriteTransaction.java  |  6 +-
 src/main/java/caosdb/server/utils/Utils.java  | 18 ----
 .../server/utils/WebinterfaceUtilsTest.java   | 11 ++-
 51 files changed, 383 insertions(+), 388 deletions(-)
 delete mode 100644 src/main/java/caosdb/server/entity/BaseEntity.java
 delete mode 100644 src/main/java/caosdb/server/entity/EntityID.java
 delete mode 100644 src/main/java/caosdb/server/entity/NamedEntity.java
 rename src/main/java/caosdb/server/resource/transaction/handlers/{IDHandler.java => SimpleDeleteRequestHandler.java} (61%)

diff --git a/pom.xml b/pom.xml
index be9279b6..989f4837 100644
--- a/pom.xml
+++ b/pom.xml
@@ -140,7 +140,7 @@
     <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-jcs-core</artifactId>
-      <version>2.1</version>
+      <version>2.2.1</version>
     </dependency>
     <dependency>
       <groupId>org.kohsuke</groupId>
diff --git a/src/main/java/caosdb/server/CaosDBServer.java b/src/main/java/caosdb/server/CaosDBServer.java
index b8924ef6..8b64fa9c 100644
--- a/src/main/java/caosdb/server/CaosDBServer.java
+++ b/src/main/java/caosdb/server/CaosDBServer.java
@@ -19,50 +19,6 @@
  */
 package caosdb.server;
 
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Properties;
-import java.util.TimeZone;
-import java.util.UUID;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.config.Ini;
-import org.apache.shiro.config.Ini.Section;
-import org.apache.shiro.config.IniSecurityManagerFactory;
-import org.apache.shiro.mgt.SecurityManager;
-import org.apache.shiro.subject.Subject;
-import org.apache.shiro.util.Factory;
-import org.apache.shiro.util.ThreadContext;
-import org.restlet.Application;
-import org.restlet.Component;
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.Restlet;
-import org.restlet.Server;
-import org.restlet.data.CookieSetting;
-import org.restlet.data.Parameter;
-import org.restlet.data.Protocol;
-import org.restlet.data.Reference;
-import org.restlet.data.ServerInfo;
-import org.restlet.data.Status;
-import org.restlet.engine.Engine;
-import org.restlet.routing.Route;
-import org.restlet.routing.Router;
-import org.restlet.routing.Template;
-import org.restlet.routing.TemplateRoute;
-import org.restlet.routing.Variable;
-import org.restlet.util.Series;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import caosdb.server.accessControl.AnonymousRealm;
 import caosdb.server.accessControl.AuthenticationUtils;
 import caosdb.server.accessControl.CaosDBAuthorizingRealm;
@@ -107,6 +63,50 @@ import caosdb.server.transaction.ChecksumUpdater;
 import caosdb.server.utils.FileUtils;
 import caosdb.server.utils.Initialization;
 import caosdb.server.utils.NullPrintStream;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.TimeZone;
+import java.util.UUID;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.config.Ini.Section;
+import org.apache.shiro.config.IniSecurityManagerFactory;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.Factory;
+import org.apache.shiro.util.ThreadContext;
+import org.restlet.Application;
+import org.restlet.Component;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.Restlet;
+import org.restlet.Server;
+import org.restlet.data.CookieSetting;
+import org.restlet.data.Parameter;
+import org.restlet.data.Protocol;
+import org.restlet.data.Reference;
+import org.restlet.data.ServerInfo;
+import org.restlet.data.Status;
+import org.restlet.engine.Engine;
+import org.restlet.routing.Route;
+import org.restlet.routing.Router;
+import org.restlet.routing.Template;
+import org.restlet.routing.TemplateRoute;
+import org.restlet.routing.Variable;
+import org.restlet.util.Series;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class CaosDBServer extends Application {
 
diff --git a/src/main/java/caosdb/server/caching/JCSCacheHelper.java b/src/main/java/caosdb/server/caching/JCSCacheHelper.java
index 1ce455a9..406e4481 100644
--- a/src/main/java/caosdb/server/caching/JCSCacheHelper.java
+++ b/src/main/java/caosdb/server/caching/JCSCacheHelper.java
@@ -88,6 +88,7 @@ public class JCSCacheHelper implements CacheHelper {
       }
       logger.info("Configuring JCS Caching with {}", config);
     }
+    JCS.shutdown();
     JCS.setConfigProperties(config);
   }
 
diff --git a/src/main/java/caosdb/server/database/DatabaseUtils.java b/src/main/java/caosdb/server/database/DatabaseUtils.java
index 3c48b9c8..9edc0347 100644
--- a/src/main/java/caosdb/server/database/DatabaseUtils.java
+++ b/src/main/java/caosdb/server/database/DatabaseUtils.java
@@ -22,12 +22,6 @@
  */
 package caosdb.server.database;
 
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import com.google.common.base.Objects;
 import caosdb.server.database.proto.FlatProperty;
 import caosdb.server.database.proto.ProtoProperty;
 import caosdb.server.database.proto.SparseEntity;
@@ -44,6 +38,12 @@ import caosdb.server.entity.StatementStatus;
 import caosdb.server.entity.wrapper.Domain;
 import caosdb.server.entity.wrapper.Parent;
 import caosdb.server.entity.wrapper.Property;
+import com.google.common.base.Objects;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
 
 public class DatabaseUtils {
 
@@ -173,12 +173,7 @@ public class DatabaseUtils {
     while (rs.next()) {
       final FlatProperty fp = new FlatProperty();
       fp.id = rs.getInt("PropertyID");
-
-      final String v = bytes2UTF8(rs.getBytes("PropertyValue"));
-      if (v != null) {
-        fp.value = v;
-      }
-
+      fp.value = bytes2UTF8(rs.getBytes("PropertyValue"));
       fp.status = bytes2UTF8(rs.getBytes("PropertyStatus"));
       fp.idx = rs.getInt("PropertyIndex");
       ret.add(fp);
@@ -224,7 +219,7 @@ public class DatabaseUtils {
     ret.version = bytes2UTF8(rs.getBytes("Version"));
     ret.versionSeconds = rs.getLong("VersionSeconds");
     ret.versionNanos = rs.getInt("VersionNanos");
-    
+
     return ret;
   }
 
diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLHelper.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLHelper.java
index 6d2a16b7..4fc50aa9 100644
--- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLHelper.java
+++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLHelper.java
@@ -22,6 +22,11 @@
  */
 package caosdb.server.database.backend.implementation.MySQL;
 
+import caosdb.server.accessControl.Principal;
+import caosdb.server.database.misc.DBHelper;
+import caosdb.server.transaction.ChecksumUpdater;
+import caosdb.server.transaction.TransactionInterface;
+import caosdb.server.transaction.WriteTransaction;
 import java.io.UnsupportedEncodingException;
 import java.sql.CallableStatement;
 import java.sql.Connection;
@@ -31,11 +36,6 @@ import java.sql.Statement;
 import java.util.HashMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import caosdb.server.accessControl.Principal;
-import caosdb.server.database.misc.DBHelper;
-import caosdb.server.transaction.ChecksumUpdater;
-import caosdb.server.transaction.TransactionInterface;
-import caosdb.server.transaction.WriteTransaction;
 
 /**
  * Provides cached statements for a MySQL back-end.
@@ -45,52 +45,50 @@ import caosdb.server.transaction.WriteTransaction;
 public class MySQLHelper implements DBHelper {
 
   private Connection connection = null;
-  
+
   private Logger logger = LoggerFactory.getLogger(getClass());
-  
-  public void initTransaction(Connection connection, WriteTransaction<?> transaction) throws SQLException {
+
+  public void initTransaction(Connection connection, WriteTransaction<?> transaction)
+      throws SQLException {
     try (CallableStatement call = connection.prepareCall("CALL set_transaction(?,?,?,?,?)")) {
-      
+
       String username = ((Principal) transaction.getTransactor().getPrincipal()).getUsername();
       String realm = ((Principal) transaction.getTransactor().getPrincipal()).getRealm();
       long seconds = transaction.getTimestamp().getUTCSeconds();
       int nanos = transaction.getTimestamp().getNanoseconds();
-      byte[] srid =  transaction.getSRID().getBytes("UTF-8");
-      
+      byte[] srid = transaction.getSRID().getBytes("UTF-8");
+
       call.setBytes(1, srid);
       call.setString(2, username);
       call.setString(3, realm);
       call.setLong(4, seconds);
       call.setInt(5, nanos);
       call.execute();
-      
+
     } catch (UnsupportedEncodingException e) {
       e.printStackTrace();
       System.exit(1);
     }
-        
-        
   }
-  
-  public Connection initConnection(TransactionInterface transaction) throws ConnectionException, SQLException {
+
+  public Connection initConnection(TransactionInterface transaction)
+      throws ConnectionException, SQLException {
     Connection connection;
-      connection = DatabaseConnectionPool.getConnection();
-      
-      if (transaction instanceof ChecksumUpdater) {
-        connection.setReadOnly(false);
-        connection.setAutoCommit(false);
-      } else if (transaction instanceof WriteTransaction) {
-        connection.setReadOnly(false);
-        connection.setAutoCommit(false);
-        initTransaction(connection, (WriteTransaction<?>) transaction);
-      } else {
-        connection.setReadOnly(false);
-        connection.setAutoCommit(true);
-      }
-      
-      
-      return connection;
-    
+    connection = DatabaseConnectionPool.getConnection();
+
+    if (transaction instanceof ChecksumUpdater) {
+      connection.setReadOnly(false);
+      connection.setAutoCommit(false);
+    } else if (transaction instanceof WriteTransaction) {
+      connection.setReadOnly(false);
+      connection.setAutoCommit(false);
+      initTransaction(connection, (WriteTransaction<?>) transaction);
+    } else {
+      connection.setReadOnly(false);
+      connection.setAutoCommit(true);
+    }
+
+    return connection;
   }
 
   public Connection getConnection() throws SQLException, ConnectionException {
@@ -102,7 +100,7 @@ public class MySQLHelper implements DBHelper {
 
   /**
    * Prepare a statement from a string. Reuse prepared statements from the cache if available.
-   * 
+   *
    * @param statement
    * @return
    * @throws SQLException
@@ -131,9 +129,7 @@ public class MySQLHelper implements DBHelper {
 
   private TransactionInterface transaction = null;
 
-  /**
-   * Make all changes permanent.
-   */
+  /** Make all changes permanent. */
   @Override
   public void commit() throws SQLException {
     if (this.connection != null
@@ -144,19 +140,17 @@ public class MySQLHelper implements DBHelper {
   }
 
   /**
-   * Reset SRID variable, close all statements, roll back to last save point and
-   * close connection.
+   * Reset SRID variable, close all statements, roll back to last save point and close connection.
    */
   @Override
   public void cleanUp() {
 
     try {
       if (this.connection != null && !this.connection.isClosed()) {
-        try (
-        Statement s = connection.createStatement()) {
+        try (Statement s = connection.createStatement()) {
           s.execute("SET @SRID = NULL");
         } catch (SQLException e) {
-            logger.error("Exception during resetting the @SRID variable.", e);
+          logger.error("Exception during resetting the @SRID variable.", e);
         }
 
         // close all cached statements (if possible)
diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java
index 2813cb17..97cfde68 100644
--- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java
@@ -22,16 +22,16 @@
  */
 package caosdb.server.database.backend.implementation.MySQL;
 
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLIntegrityConstraintViolationException;
-import java.sql.Types;
 import caosdb.server.database.DatabaseUtils;
 import caosdb.server.database.access.Access;
 import caosdb.server.database.backend.interfaces.InsertSparseEntityImpl;
 import caosdb.server.database.exceptions.IntegrityException;
 import caosdb.server.database.exceptions.TransactionException;
 import caosdb.server.database.proto.SparseEntity;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLIntegrityConstraintViolationException;
+import java.sql.Types;
 
 public class MySQLInsertSparseEntity extends MySQLTransaction implements InsertSparseEntityImpl {
 
diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java
index c1c430cf..721ba566 100644
--- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java
+++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java
@@ -30,6 +30,7 @@ import caosdb.server.database.proto.VerySparseEntity;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Types;
 import java.util.ArrayList;
 
 public class MySQLRetrieveParents extends MySQLTransaction implements RetrieveParentsImpl {
@@ -38,16 +39,22 @@ public class MySQLRetrieveParents extends MySQLTransaction implements RetrievePa
     super(access);
   }
 
-  private static final String stmtStr = "call retrieveEntityParents(?)";
+  private static final String stmtStr = "call retrieveEntityParents(?, ?)";
 
   @Override
-  public ArrayList<VerySparseEntity> execute(final Integer id) throws TransactionException {
+  public ArrayList<VerySparseEntity> execute(final Integer id, final String version)
+      throws TransactionException {
     try {
       ResultSet rs = null;
       try {
         final PreparedStatement prepareStatement = prepareStatement(stmtStr);
 
         prepareStatement.setInt(1, id);
+        if (version == null) {
+          prepareStatement.setNull(2, Types.VARBINARY);
+        } else {
+          prepareStatement.setString(2, version);
+        }
         rs = prepareStatement.executeQuery();
         return DatabaseUtils.parseParentResultSet(rs);
       } finally {
diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java
index 8b9a547b..9b6704c4 100644
--- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java
+++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java
@@ -31,6 +31,7 @@ import caosdb.server.database.proto.ProtoProperty;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Types;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -40,15 +41,17 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
     super(access);
   }
 
-  private static final String stmtStr = "call retrieveEntityProperties(?,?)";
-  private static final String stmtStr2 = "call retrieveOverrides(?,?)";
+  private static final String stmtStr = "call retrieveEntityProperties(?,?,?)";
+  private static final String stmtStr2 = "call retrieveOverrides(?,?,?)";
 
   @Override
-  public ArrayList<ProtoProperty> execute(final Integer entity) throws TransactionException {
+  public ArrayList<ProtoProperty> execute(final Integer entity, final String version)
+      throws TransactionException {
     try {
       final PreparedStatement prepareStatement = prepareStatement(stmtStr);
 
-      final List<FlatProperty> props = retrieveFlatPropertiesStage1(0, entity, prepareStatement);
+      final List<FlatProperty> props =
+          retrieveFlatPropertiesStage1(0, entity, version, prepareStatement);
 
       final ArrayList<ProtoProperty> protos = new ArrayList<ProtoProperty>();
       for (final FlatProperty p : props) {
@@ -56,7 +59,7 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
         proto.property = p;
 
         final List<FlatProperty> subProps =
-            retrieveFlatPropertiesStage1(entity, p.id, prepareStatement);
+            retrieveFlatPropertiesStage1(entity, p.id, version, prepareStatement);
 
         proto.subProperties = subProps;
 
@@ -71,7 +74,10 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
   }
 
   private List<FlatProperty> retrieveFlatPropertiesStage1(
-      final Integer domain, final Integer entity, final PreparedStatement stmt)
+      final Integer domain,
+      final Integer entity,
+      final String version,
+      final PreparedStatement stmt)
       throws SQLException, ConnectionException {
     ResultSet rs = null;
     try {
@@ -82,6 +88,12 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
       }
 
       stmt.setInt(2, entity);
+      if (version == null) {
+        stmt.setNull(3, Types.VARBINARY);
+      } else {
+        stmt.setString(3, version);
+      }
+
       long t1 = System.currentTimeMillis();
       rs = stmt.executeQuery();
       long t2 = System.currentTimeMillis();
@@ -91,7 +103,7 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
 
       final PreparedStatement stmt2 = prepareStatement(stmtStr2);
 
-      retrieveOverrides(domain, entity, stmt2, props);
+      retrieveOverrides(domain, entity, version, stmt2, props);
 
       return props;
     } finally {
@@ -104,6 +116,7 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
   private void retrieveOverrides(
       final Integer domain,
       final Integer entity,
+      final String version,
       final PreparedStatement stmt2,
       final List<FlatProperty> props)
       throws SQLException {
@@ -112,6 +125,11 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
     try {
       stmt2.setInt(1, domain);
       stmt2.setInt(2, entity);
+      if (version == null) {
+        stmt2.setNull(3, Types.VARBINARY);
+      } else {
+        stmt2.setString(3, version);
+      }
       long t1 = System.currentTimeMillis();
       rs = stmt2.executeQuery();
       long t2 = System.currentTimeMillis();
diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java
index 92f2cd5f..c6d88ec9 100644
--- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java
+++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java
@@ -28,6 +28,7 @@ import caosdb.server.database.exceptions.TransactionException;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Types;
 
 public class MySQLRetrieveQueryTemplateDefinition extends MySQLTransaction
     implements RetrieveQueryTemplateDefinitionImpl {
@@ -37,14 +38,19 @@ public class MySQLRetrieveQueryTemplateDefinition extends MySQLTransaction
   }
 
   public static final String STMT_RETRIEVE_QUERY_TEMPLATE_DEF =
-      "SELECT definition FROM query_template_def WHERE id=?";
+      "call retrieveQueryTemplateDef(?,?)";
 
   @Override
-  public String retrieve(final Integer id) {
+  public String retrieve(final Integer id, final String version) {
     try {
 
       final PreparedStatement stmt = prepareStatement(STMT_RETRIEVE_QUERY_TEMPLATE_DEF);
       stmt.setInt(1, id);
+      if (version == null) {
+        stmt.setNull(2, Types.VARBINARY);
+      } else {
+        stmt.setString(2, version);
+      }
       final ResultSet rs = stmt.executeQuery();
       if (rs.next()) {
         return rs.getString("definition");
diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java
index 749b0b91..42e35b67 100644
--- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java
@@ -30,6 +30,7 @@ import caosdb.server.database.proto.SparseEntity;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Types;
 
 /**
  * Retrieve a single SparseEntity by id.
@@ -43,14 +44,19 @@ public class MySQLRetrieveSparseEntity extends MySQLTransaction
     super(access);
   }
 
-  private static final String stmtStr = "call retrieveEntity(?)";
+  private static final String stmtStr = "call retrieveEntity(?,?)";
 
   @Override
-  public SparseEntity execute(final int id) throws TransactionException {
+  public SparseEntity execute(final int id, final String version) throws TransactionException {
     try {
       final PreparedStatement preparedStatement = prepareStatement(stmtStr);
 
       preparedStatement.setInt(1, id);
+      if (version == null) {
+        preparedStatement.setNull(2, Types.VARBINARY);
+      } else {
+        preparedStatement.setString(2, version);
+      }
       final ResultSet rs = preparedStatement.executeQuery();
       try {
         if (rs.next()) {
diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java
index 50070478..30497b2d 100644
--- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java
@@ -22,17 +22,17 @@
  */
 package caosdb.server.database.backend.implementation.MySQL;
 
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.SQLIntegrityConstraintViolationException;
-import java.sql.Types;
 import caosdb.server.database.DatabaseUtils;
 import caosdb.server.database.access.Access;
 import caosdb.server.database.backend.interfaces.UpdateSparseEntityImpl;
 import caosdb.server.database.exceptions.IntegrityException;
 import caosdb.server.database.exceptions.TransactionException;
 import caosdb.server.database.proto.SparseEntity;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLIntegrityConstraintViolationException;
+import java.sql.Types;
 
 public class MySQLUpdateSparseEntity extends MySQLTransaction implements UpdateSparseEntityImpl {
 
@@ -78,8 +78,8 @@ public class MySQLUpdateSparseEntity extends MySQLTransaction implements UpdateS
       updateEntityStmt.setString(6, spe.collection);
       updateEntityStmt.setString(7, spe.acl);
       ResultSet rs = updateEntityStmt.executeQuery();
-      
-      if(rs.next()) {
+
+      if (rs.next()) {
         spe.version = DatabaseUtils.bytes2UTF8(rs.getBytes("Version"));
       }
 
diff --git a/src/main/java/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java b/src/main/java/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java
index 551ee962..9dfb8cf5 100644
--- a/src/main/java/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java
+++ b/src/main/java/caosdb/server/database/backend/interfaces/RetrieveParentsImpl.java
@@ -28,5 +28,6 @@ import java.util.ArrayList;
 
 public interface RetrieveParentsImpl extends BackendTransactionImpl {
 
-  public ArrayList<VerySparseEntity> execute(Integer id) throws TransactionException;
+  public ArrayList<VerySparseEntity> execute(Integer id, String version)
+      throws TransactionException;
 }
diff --git a/src/main/java/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java b/src/main/java/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java
index 3c8449f7..b9a15a52 100644
--- a/src/main/java/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java
+++ b/src/main/java/caosdb/server/database/backend/interfaces/RetrievePropertiesImpl.java
@@ -28,5 +28,5 @@ import java.util.ArrayList;
 
 public interface RetrievePropertiesImpl extends BackendTransactionImpl {
 
-  public ArrayList<ProtoProperty> execute(Integer id) throws TransactionException;
+  public ArrayList<ProtoProperty> execute(Integer id, String version) throws TransactionException;
 }
diff --git a/src/main/java/caosdb/server/database/backend/interfaces/RetrieveQueryTemplateDefinitionImpl.java b/src/main/java/caosdb/server/database/backend/interfaces/RetrieveQueryTemplateDefinitionImpl.java
index fee860ca..cda33604 100644
--- a/src/main/java/caosdb/server/database/backend/interfaces/RetrieveQueryTemplateDefinitionImpl.java
+++ b/src/main/java/caosdb/server/database/backend/interfaces/RetrieveQueryTemplateDefinitionImpl.java
@@ -24,5 +24,5 @@ package caosdb.server.database.backend.interfaces;
 
 public interface RetrieveQueryTemplateDefinitionImpl extends BackendTransactionImpl {
 
-  public String retrieve(final Integer id);
+  public String retrieve(Integer id, String version);
 }
diff --git a/src/main/java/caosdb/server/database/backend/interfaces/RetrieveSparseEntityImpl.java b/src/main/java/caosdb/server/database/backend/interfaces/RetrieveSparseEntityImpl.java
index 82a534c0..5b6978f8 100644
--- a/src/main/java/caosdb/server/database/backend/interfaces/RetrieveSparseEntityImpl.java
+++ b/src/main/java/caosdb/server/database/backend/interfaces/RetrieveSparseEntityImpl.java
@@ -27,5 +27,5 @@ import caosdb.server.database.proto.SparseEntity;
 
 public interface RetrieveSparseEntityImpl extends BackendTransactionImpl {
 
-  public SparseEntity execute(int id) throws TransactionException;
+  public SparseEntity execute(int id, String version) throws TransactionException;
 }
diff --git a/src/main/java/caosdb/server/database/backend/transaction/DeleteEntityProperties.java b/src/main/java/caosdb/server/database/backend/transaction/DeleteEntityProperties.java
index 15ace2b9..984ca5eb 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/DeleteEntityProperties.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/DeleteEntityProperties.java
@@ -40,8 +40,8 @@ public class DeleteEntityProperties extends BackendTransaction {
 
   @Override
   public void execute() {
-    RetrieveProperties.removeCached(this.entity.getId());
-    RetrieveParents.removeCached(this.entity.getId());
+    RetrieveProperties.removeCached(this.entity.getIdVersion());
+    RetrieveParents.removeCached(this.entity.getIdVersion());
 
     final DeleteEntityPropertiesImpl ret = getImplementation(DeleteEntityPropertiesImpl.class);
 
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 39deb141..c732d25c 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/DeleteSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/DeleteSparseEntity.java
@@ -42,7 +42,7 @@ public class DeleteSparseEntity extends BackendTransaction {
 
   @Override
   protected void execute() {
-    RetrieveSparseEntity.removeCached(this.entity.getId());
+    RetrieveSparseEntity.removeCached(this.entity.getIdVersion());
     if (entity.hasFileProperties()) {
       GetFileRecordByPath.removeCached(this.entity.getFileProperties().getPath());
     }
diff --git a/src/main/java/caosdb/server/database/backend/transaction/InsertSparseEntity.java b/src/main/java/caosdb/server/database/backend/transaction/InsertSparseEntity.java
index c6e2b9dd..c59f912a 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/InsertSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/InsertSparseEntity.java
@@ -23,6 +23,7 @@
 package caosdb.server.database.backend.transaction;
 
 import static caosdb.server.transaction.Transaction.ERROR_INTEGRITY_VIOLATION;
+
 import caosdb.server.database.BackendTransaction;
 import caosdb.server.database.backend.interfaces.InsertSparseEntityImpl;
 import caosdb.server.database.exceptions.IntegrityException;
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 5c1b0178..fbb257f7 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveParents.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveParents.java
@@ -35,9 +35,9 @@ import java.util.ArrayList;
 import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrieveParents
-    extends CacheableBackendTransaction<Integer, ArrayList<VerySparseEntity>> {
+    extends CacheableBackendTransaction<String, ArrayList<VerySparseEntity>> {
 
-  private static final ICacheAccess<Integer, ArrayList<VerySparseEntity>> cache =
+  private static final ICacheAccess<String, ArrayList<VerySparseEntity>> cache =
       Cache.getCache("BACKEND_EntityParents");
 
   /**
@@ -45,9 +45,9 @@ public class RetrieveParents
    *
    * @param id
    */
-  public static void removeCached(final Integer id) {
-    if (id != null && cache != null) {
-      cache.remove(id);
+  public static void removeCached(final String idVersion) {
+    if (idVersion != null && cache != null) {
+      cache.remove(idVersion);
     }
   }
 
@@ -61,8 +61,7 @@ public class RetrieveParents
   @Override
   public ArrayList<VerySparseEntity> executeNoCache() throws TransactionException {
     final RetrieveParentsImpl t = getImplementation(RetrieveParentsImpl.class);
-    final Integer key = getKey();
-    return t.execute(key);
+    return t.execute(this.entity.getId(), this.entity.getVersion());
   }
 
   @Override
@@ -72,7 +71,7 @@ public class RetrieveParents
   }
 
   @Override
-  protected Integer getKey() {
-    return this.entity.getId();
+  protected String getKey() {
+    return this.entity.getIdVersion();
   }
 }
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 487feb56..c0bcb8e8 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveProperties.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveProperties.java
@@ -37,11 +37,11 @@ import java.util.ArrayList;
 import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
 public class RetrieveProperties
-    extends CacheableBackendTransaction<Integer, ArrayList<ProtoProperty>> {
+    extends CacheableBackendTransaction<String, ArrayList<ProtoProperty>> {
 
   private final EntityInterface entity;
   public static final String CACHE_REGION = "BACKEND_EntityProperties";
-  private static final ICacheAccess<Integer, ArrayList<ProtoProperty>> cache =
+  private static final ICacheAccess<String, ArrayList<ProtoProperty>> cache =
       Cache.getCache(CACHE_REGION);
 
   /**
@@ -49,9 +49,9 @@ public class RetrieveProperties
    *
    * @param id
    */
-  protected static void removeCached(final Integer id) {
-    if (id != null && cache != null) {
-      cache.remove(id);
+  protected static void removeCached(final String idVersion) {
+    if (idVersion != null && cache != null) {
+      cache.remove(idVersion);
     }
   }
 
@@ -63,7 +63,7 @@ public class RetrieveProperties
   @Override
   public ArrayList<ProtoProperty> executeNoCache() throws TransactionException {
     final RetrievePropertiesImpl t = getImplementation(RetrievePropertiesImpl.class);
-    return t.execute(getKey());
+    return t.execute(this.entity.getId(), this.entity.getVersion());
   }
 
   @Override
@@ -98,7 +98,7 @@ public class RetrieveProperties
   }
 
   @Override
-  protected Integer getKey() {
-    return this.entity.getId();
+  protected String getKey() {
+    return this.entity.getIdVersion();
   }
 }
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveQueryTemplateDefinition.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveQueryTemplateDefinition.java
index 208c7439..b3dfb146 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveQueryTemplateDefinition.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveQueryTemplateDefinition.java
@@ -39,6 +39,7 @@ public class RetrieveQueryTemplateDefinition extends BackendTransaction {
   protected void execute() throws TransactionException {
     final RetrieveQueryTemplateDefinitionImpl t =
         getImplementation(RetrieveQueryTemplateDefinitionImpl.class);
-    this.entity.setQueryTemplateDefinition(t.retrieve(this.entity.getId()));
+    this.entity.setQueryTemplateDefinition(
+        t.retrieve(this.entity.getId(), this.entity.getVersion()));
   }
 }
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 a91b5021..db6b38bd 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveSparseEntity.java
@@ -35,20 +35,20 @@ import caosdb.server.entity.EntityInterface;
 import caosdb.server.utils.EntityStatus;
 import org.apache.commons.jcs.access.behavior.ICacheAccess;
 
-public class RetrieveSparseEntity extends CacheableBackendTransaction<Integer, SparseEntity> {
+public class RetrieveSparseEntity extends CacheableBackendTransaction<String, SparseEntity> {
 
   private final EntityInterface entity;
-  private static final ICacheAccess<Integer, SparseEntity> cache =
+  private static final ICacheAccess<String, SparseEntity> cache =
       Cache.getCache("BACKEND_SparseEntities");
 
   /**
    * To be called by {@link UpdateSparseEntity} and {@link DeleteEntity} on execution.
    *
-   * @param id
+   * @param idVersion
    */
-  public static void removeCached(final Integer id) {
-    if (id != null && cache != null) {
-      cache.remove(id);
+  public static void removeCached(final String idVersion) {
+    if (idVersion != null && cache != null) {
+      cache.remove(idVersion);
     }
   }
 
@@ -64,7 +64,7 @@ public class RetrieveSparseEntity extends CacheableBackendTransaction<Integer, S
   @Override
   public SparseEntity executeNoCache() throws TransactionException {
     final RetrieveSparseEntityImpl t = getImplementation(RetrieveSparseEntityImpl.class);
-    final SparseEntity ret = t.execute(getKey());
+    final SparseEntity ret = t.execute(getEntity().getId(), getEntity().getVersion());
     if (ret == null) {
       this.entity.setEntityStatus(EntityStatus.NONEXISTENT);
     }
@@ -78,8 +78,8 @@ public class RetrieveSparseEntity extends CacheableBackendTransaction<Integer, S
   }
 
   @Override
-  protected Integer getKey() {
-    return this.entity.getId();
+  protected String getKey() {
+    return this.entity.getIdVersion();
   }
 
   public EntityInterface getEntity() {
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 281c2f21..c3149a76 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/UpdateSparseEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/UpdateSparseEntity.java
@@ -40,7 +40,7 @@ public class UpdateSparseEntity extends BackendTransaction {
 
   @Override
   public void execute() throws TransactionException {
-    RetrieveSparseEntity.removeCached(this.entity.getId());
+    RetrieveSparseEntity.removeCached(this.entity.getIdVersion());
     if (entity.hasFileProperties()) {
       GetFileRecordByPath.removeCached(this.entity.getFileProperties().getPath());
     }
@@ -50,7 +50,7 @@ public class UpdateSparseEntity extends BackendTransaction {
     final SparseEntity spe = this.entity.getSparseEntity();
 
     t.execute(spe);
-    
+
     this.entity.setVersion(spe.version);
   }
 }
diff --git a/src/main/java/caosdb/server/database/misc/TransactionBenchmark.java b/src/main/java/caosdb/server/database/misc/TransactionBenchmark.java
index 2662b884..d68c82f5 100644
--- a/src/main/java/caosdb/server/database/misc/TransactionBenchmark.java
+++ b/src/main/java/caosdb/server/database/misc/TransactionBenchmark.java
@@ -22,6 +22,11 @@
  */
 package caosdb.server.database.misc;
 
+import caosdb.server.CaosDBServer;
+import caosdb.server.ServerProperties;
+import caosdb.server.utils.CronJob;
+import caosdb.server.utils.Info;
+import caosdb.server.utils.ServerStat;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -34,11 +39,6 @@ import java.util.Map.Entry;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.jdom2.Element;
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
-import caosdb.server.utils.CronJob;
-import caosdb.server.utils.Info;
-import caosdb.server.utils.ServerStat;
 
 class Counter implements Serializable {
   private static final long serialVersionUID = 8679355597595634790L;
diff --git a/src/main/java/caosdb/server/entity/BaseEntity.java b/src/main/java/caosdb/server/entity/BaseEntity.java
deleted file mode 100644
index 62d4873b..00000000
--- a/src/main/java/caosdb/server/entity/BaseEntity.java
+++ /dev/null
@@ -1,28 +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.entity;
-
-class BaseEntity {
-
-  EntityID id = null;
-}
diff --git a/src/main/java/caosdb/server/entity/DeleteEntity.java b/src/main/java/caosdb/server/entity/DeleteEntity.java
index 29b6a3a0..f31fbb47 100644
--- a/src/main/java/caosdb/server/entity/DeleteEntity.java
+++ b/src/main/java/caosdb/server/entity/DeleteEntity.java
@@ -27,4 +27,9 @@ public class DeleteEntity extends Entity {
   public DeleteEntity(final int id) {
     super(id);
   }
+
+  public DeleteEntity(int id, String version) {
+    super(id);
+    setVersion(version);
+  }
 }
diff --git a/src/main/java/caosdb/server/entity/Entity.java b/src/main/java/caosdb/server/entity/Entity.java
index b37ae2d1..c1579fb0 100644
--- a/src/main/java/caosdb/server/entity/Entity.java
+++ b/src/main/java/caosdb/server/entity/Entity.java
@@ -22,17 +22,6 @@
  */
 package caosdb.server.entity;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authz.AuthorizationException;
-import org.apache.shiro.authz.Permission;
-import org.apache.shiro.subject.Subject;
-import org.jdom2.Element;
 import caosdb.datetime.UTCDateTime;
 import caosdb.server.CaosDBException;
 import caosdb.server.database.proto.SparseEntity;
@@ -59,6 +48,17 @@ import caosdb.server.utils.EntityStatus;
 import caosdb.server.utils.ServerMessages;
 import caosdb.server.utils.TransactionLogMessage;
 import caosdb.unit.Unit;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.subject.Subject;
+import org.jdom2.Element;
 
 public class Entity extends AbstractObservable implements EntityInterface {
 
@@ -1068,7 +1068,9 @@ public class Entity extends AbstractObservable implements EntityInterface {
     this.setRole(spe.role);
     setEntityACL(spe.acl);
     this.version = spe.version;
-    this.versionDate = UTCDateTime.UTCSeconds(spe.versionSeconds, spe.versionNanos);
+    if (spe.versionSeconds != null) {
+      this.versionDate = UTCDateTime.UTCSeconds(spe.versionSeconds, spe.versionNanos);
+    }
 
     if (!isNameOverride()) {
       setName(spe.name);
@@ -1137,12 +1139,12 @@ public class Entity extends AbstractObservable implements EntityInterface {
   public boolean hasVersionDate() {
     return this.versionDate != null;
   }
-  
+
   @Override
   public void setVersion(String version) {
     this.version = version;
   }
-  
+
   @Override
   public void setVersionDate(Long versionSeconds, Integer versionNanos) {
     this.versionDate = UTCDateTime.UTCSeconds(versionSeconds, versionNanos);
@@ -1153,4 +1155,13 @@ public class Entity extends AbstractObservable implements EntityInterface {
     this.versionDate = versionDate;
   }
 
-}
\ No newline at end of file
+  @Override
+  public String getIdVersion() {
+    if (!this.hasId()) {
+      return null;
+    } else if (this.hasVersion()) {
+      return new StringBuilder().append(getId()).append(getVersion()).toString();
+    }
+    return getId().toString();
+  }
+}
diff --git a/src/main/java/caosdb/server/entity/EntityID.java b/src/main/java/caosdb/server/entity/EntityID.java
deleted file mode 100644
index fbfb83c8..00000000
--- a/src/main/java/caosdb/server/entity/EntityID.java
+++ /dev/null
@@ -1,25 +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.entity;
-
-public class EntityID {}
diff --git a/src/main/java/caosdb/server/entity/EntityInterface.java b/src/main/java/caosdb/server/entity/EntityInterface.java
index 7d8faaf9..a39a43d6 100644
--- a/src/main/java/caosdb/server/entity/EntityInterface.java
+++ b/src/main/java/caosdb/server/entity/EntityInterface.java
@@ -22,9 +22,6 @@
  */
 package caosdb.server.entity;
 
-import java.util.List;
-import org.apache.shiro.authz.Permission;
-import org.apache.shiro.subject.Subject;
 import caosdb.datetime.UTCDateTime;
 import caosdb.server.database.proto.SparseEntity;
 import caosdb.server.database.proto.VerySparseEntity;
@@ -41,6 +38,9 @@ import caosdb.server.permissions.EntityACL;
 import caosdb.server.utils.Observable;
 import caosdb.server.utils.TransactionLogMessage;
 import caosdb.unit.Unit;
+import java.util.List;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.subject.Subject;
 
 public interface EntityInterface
     extends JobTarget, Observable, ToElementable, WriteEntity, TransactionEntity {
@@ -51,6 +51,8 @@ public interface EntityInterface
 
   public abstract Integer getId();
 
+  public abstract String getIdVersion();
+
   public abstract void setId(Integer id);
 
   public abstract boolean hasId();
@@ -183,9 +185,9 @@ public interface EntityInterface
   public abstract String getQueryTemplateDefinition();
 
   public abstract void setQueryTemplateDefinition(String query);
-  
+
   public abstract UTCDateTime getVersionDate();
-  
+
   public abstract String getVersion();
 
   public abstract boolean hasVersion();
diff --git a/src/main/java/caosdb/server/entity/NamedEntity.java b/src/main/java/caosdb/server/entity/NamedEntity.java
deleted file mode 100644
index 76ba79a3..00000000
--- a/src/main/java/caosdb/server/entity/NamedEntity.java
+++ /dev/null
@@ -1,28 +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.entity;
-
-class NamedEntity extends BaseEntity {
-
-  String name = null;
-}
diff --git a/src/main/java/caosdb/server/entity/RetrieveEntity.java b/src/main/java/caosdb/server/entity/RetrieveEntity.java
index 638bc1fa..64b99a2f 100644
--- a/src/main/java/caosdb/server/entity/RetrieveEntity.java
+++ b/src/main/java/caosdb/server/entity/RetrieveEntity.java
@@ -31,5 +31,14 @@ public class RetrieveEntity extends Entity {
   public RetrieveEntity(final String name) {
     super(name);
   }
-  
+
+  public RetrieveEntity(int id, String version) {
+    super(id);
+    this.setVersion(version);
+  }
+
+  public RetrieveEntity(String name, String version) {
+    super(name);
+    this.setVersion(version);
+  }
 }
diff --git a/src/main/java/caosdb/server/entity/ValidEntity.java b/src/main/java/caosdb/server/entity/ValidEntity.java
index cec1fbf6..d2c8b519 100644
--- a/src/main/java/caosdb/server/entity/ValidEntity.java
+++ b/src/main/java/caosdb/server/entity/ValidEntity.java
@@ -27,5 +27,4 @@ public class ValidEntity extends Entity {
   public ValidEntity(final int id) {
     super(id);
   }
-  
 }
diff --git a/src/main/java/caosdb/server/entity/container/DeleteContainer.java b/src/main/java/caosdb/server/entity/container/DeleteContainer.java
index c219ee5e..c3d57bc6 100644
--- a/src/main/java/caosdb/server/entity/container/DeleteContainer.java
+++ b/src/main/java/caosdb/server/entity/container/DeleteContainer.java
@@ -42,4 +42,9 @@ public class DeleteContainer extends EntityByIdContainer {
   public void add(final int id) {
     add(new DeleteEntity(id));
   }
+
+  @Override
+  public void add(int id, String version) {
+    add(new DeleteEntity(id, version));
+  }
 }
diff --git a/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java b/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java
index 1bfda202..29a0978b 100644
--- a/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java
+++ b/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java
@@ -37,4 +37,6 @@ public abstract class EntityByIdContainer extends TransactionContainer {
   }
 
   public abstract void add(int id);
+
+  public abstract void add(int id, String version);
 }
diff --git a/src/main/java/caosdb/server/entity/container/RetrieveContainer.java b/src/main/java/caosdb/server/entity/container/RetrieveContainer.java
index 9b4f7364..5b205bc2 100644
--- a/src/main/java/caosdb/server/entity/container/RetrieveContainer.java
+++ b/src/main/java/caosdb/server/entity/container/RetrieveContainer.java
@@ -46,4 +46,13 @@ public class RetrieveContainer extends EntityByIdContainer {
   public void add(final String name) {
     add(new RetrieveEntity(name));
   }
+
+  public void add(final String name, String version) {
+    add(new RetrieveEntity(name, version));
+  }
+
+  @Override
+  public void add(int id, String version) {
+    add(new RetrieveEntity(id, version));
+  }
 }
diff --git a/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java b/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java
index dac6cbc8..85719dc6 100644
--- a/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java
+++ b/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java
@@ -22,12 +22,6 @@
  */
 package caosdb.server.entity.wrapper;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.apache.shiro.authz.Permission;
-import org.apache.shiro.subject.Subject;
-import org.jdom2.Element;
 import caosdb.datetime.UTCDateTime;
 import caosdb.server.database.proto.SparseEntity;
 import caosdb.server.database.proto.VerySparseEntity;
@@ -48,6 +42,12 @@ import caosdb.server.utils.EntityStatus;
 import caosdb.server.utils.Observer;
 import caosdb.server.utils.TransactionLogMessage;
 import caosdb.unit.Unit;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.subject.Subject;
+import org.jdom2.Element;
 
 public class EntityWrapper implements EntityInterface {
 
@@ -572,12 +572,12 @@ public class EntityWrapper implements EntityInterface {
   public boolean hasVersionDate() {
     return this.entity.hasVersionDate();
   }
-  
+
   @Override
   public void setVersion(String version) {
     this.entity.setVersion(version);
   }
-  
+
   @Override
   public void setVersionDate(Long versionSeconds, Integer versionNanos) {
     this.entity.setVersionDate(versionSeconds, versionNanos);
@@ -587,4 +587,9 @@ public class EntityWrapper implements EntityInterface {
   public void setVersionDate(UTCDateTime versionDate) {
     this.entity.setVersionDate(versionDate);
   }
+
+  @Override
+  public String getIdVersion() {
+    return this.entity.getIdVersion();
+  }
 }
diff --git a/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java b/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java
index 5d7840dd..0697c076 100644
--- a/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java
+++ b/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java
@@ -22,16 +22,16 @@
  */
 package caosdb.server.entity.xml;
 
+import caosdb.server.entity.EntityInterface;
+import caosdb.server.entity.Message;
+import caosdb.server.utils.EntityStatus;
+import caosdb.server.utils.TransactionLogMessage;
 import java.util.Comparator;
 import java.util.TimeZone;
 import org.apache.shiro.SecurityUtils;
 import org.jdom2.Content;
 import org.jdom2.Content.CType;
 import org.jdom2.Element;
-import caosdb.server.entity.EntityInterface;
-import caosdb.server.entity.Message;
-import caosdb.server.utils.EntityStatus;
-import caosdb.server.utils.TransactionLogMessage;
 
 public class EntityToElementStrategy implements ToElementStrategy {
 
@@ -54,8 +54,9 @@ public class EntityToElementStrategy implements ToElementStrategy {
     if (setFieldStrategy.isToBeSet("version") && entity.hasVersion()) {
       element.setAttribute("version", entity.getVersion());
     }
-    if(setFieldStrategy.isToBeSet("versionDate") && entity.hasVersionDate()) {
-      element.setAttribute("versionDate", entity.getVersionDate().toDateTimeString(TimeZone.getDefault())); 
+    if (setFieldStrategy.isToBeSet("versionDate") && entity.hasVersionDate()) {
+      element.setAttribute(
+          "versionDate", entity.getVersionDate().toDateTimeString(TimeZone.getDefault()));
     }
     if (setFieldStrategy.isToBeSet("cuid") && entity.hasCuid()) {
       element.setAttribute("cuid", entity.getCuid());
diff --git a/src/main/java/caosdb/server/jobs/extension/AWIBoxLoanModel.java b/src/main/java/caosdb/server/jobs/extension/AWIBoxLoanModel.java
index 60f35565..280b4132 100644
--- a/src/main/java/caosdb/server/jobs/extension/AWIBoxLoanModel.java
+++ b/src/main/java/caosdb/server/jobs/extension/AWIBoxLoanModel.java
@@ -1,6 +1,5 @@
 package caosdb.server.jobs.extension;
 
-import java.util.Objects;
 import caosdb.server.CaosDBServer;
 import caosdb.server.database.exceptions.EntityDoesNotExistException;
 import caosdb.server.database.exceptions.EntityWasNotUniqueException;
@@ -8,7 +7,7 @@ import caosdb.server.entity.EntityInterface;
 import caosdb.server.entity.Role;
 import caosdb.server.entity.wrapper.Property;
 import caosdb.server.jobs.ContainerJob;
-import caosdb.server.utils.Utils;
+import java.util.Objects;
 
 public abstract class AWIBoxLoanModel extends ContainerJob {
 
@@ -63,9 +62,12 @@ public abstract class AWIBoxLoanModel extends ContainerJob {
 
   Integer getIdOf(String string) {
     String id = CaosDBServer.getServerProperty("EXT_AWI_" + string.toUpperCase() + "_ID");
-    if (id != null && Utils.isNonNullInteger(id)) {
-      return new Integer(id);
+    try {
+      if (id != null) return Integer.parseInt(id);
+    } catch (NumberFormatException e) {
+      // not a number
     }
+
     String name = CaosDBServer.getServerProperty("EXT_AWI_" + string.toUpperCase() + "_NAME");
     if (name == null || name.isEmpty()) {
       name = string;
diff --git a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java
index ea4e65f0..44cfdcc8 100644
--- a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java
+++ b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java
@@ -23,7 +23,6 @@
  */
 package caosdb.server.resource;
 
-import static caosdb.server.utils.Utils.isNonNullInteger;
 import static java.net.URLDecoder.decode;
 
 import caosdb.server.CaosDBException;
@@ -39,7 +38,6 @@ import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -78,9 +76,7 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
   private static final XMLParser xmlparser = new XMLParser();
   protected String sRID = null; // Server side request ID
   private String cRID = null; // Client side request ID
-  private String[] requestedItems = null;
-  private ArrayList<Integer> requestedIDs = new ArrayList<Integer>();
-  private ArrayList<String> requestedNames = new ArrayList<String>();
+  private String[] requestedItems = {};
   private WebinterfaceUtils utils;
 
   /** Return the {@link WebinterfaceUtils} instance for this resource. */
@@ -142,21 +138,6 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
       }
 
       this.requestedItems = specifier.split("&");
-      for (final String requestedItem : this.requestedItems) {
-        if (isNonNullInteger(requestedItem)) {
-          final int id = Integer.parseInt(requestedItem);
-          if (id > 0) {
-            getRequestedIDs().add(id);
-          }
-        } else if (requestedItem.equalsIgnoreCase("all")) {
-          getRequestedNames().clear();
-          getRequestedIDs().clear();
-          getRequestedNames().add("all");
-          break;
-        } else {
-          getRequestedNames().add(requestedItem);
-        }
-      }
     }
 
     // flags
@@ -430,16 +411,8 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
     }
   }
 
-  public ArrayList<Integer> getRequestedIDs() {
-    return this.requestedIDs;
-  }
-
-  public ArrayList<String> getRequestedNames() {
-    return this.requestedNames;
-  }
-
-  public void setRequestedNames(final ArrayList<String> requestedNames) {
-    this.requestedNames = requestedNames;
+  public String[] getRequestedItems() {
+    return this.requestedItems;
   }
 
   public HashMap<String, String> getFlags() {
diff --git a/src/main/java/caosdb/server/resource/PermissionRulesResource.java b/src/main/java/caosdb/server/resource/PermissionRulesResource.java
index 1610ba37..dba1797a 100644
--- a/src/main/java/caosdb/server/resource/PermissionRulesResource.java
+++ b/src/main/java/caosdb/server/resource/PermissionRulesResource.java
@@ -46,7 +46,7 @@ public class PermissionRulesResource extends AbstractCaosDBServerResource {
   protected Representation httpGetInChildClass()
       throws ConnectionException, IOException, SQLException, CaosDBException,
           NoSuchAlgorithmException, Exception {
-    final String role = getRequestedNames().get(0);
+    final String role = getRequestedItems()[0];
 
     getUser().checkPermission(ACMPermissions.PERMISSION_RETRIEVE_ROLE_PERMISSIONS(role));
 
@@ -73,7 +73,7 @@ public class PermissionRulesResource extends AbstractCaosDBServerResource {
   public Representation httpPutInChildClass(final Representation entity) throws Exception {
     final Element root = parseEntity(entity).getRootElement();
 
-    final String role = getRequestedNames().get(0);
+    final String role = getRequestedItems()[0];
     final HashSet<PermissionRule> rules = new HashSet<PermissionRule>();
 
     for (final Element e : root.getChildren()) {
diff --git a/src/main/java/caosdb/server/resource/RolesResource.java b/src/main/java/caosdb/server/resource/RolesResource.java
index ef9b30f5..0f1b01e3 100644
--- a/src/main/java/caosdb/server/resource/RolesResource.java
+++ b/src/main/java/caosdb/server/resource/RolesResource.java
@@ -52,8 +52,8 @@ public class RolesResource extends AbstractCaosDBServerResource {
     final Element root = generateRootElement();
     final Document document = new Document();
 
-    if (!getRequestedNames().isEmpty()) {
-      final String name = getRequestedNames().get(0);
+    if (getRequestedItems().length > 0) {
+      final String name = getRequestedItems()[0];
       if (name != null) {
         getUser().checkPermission(ACMPermissions.PERMISSION_RETRIEVE_ROLE_DESCRIPTION(name));
         final RetrieveRoleTransaction t = new RetrieveRoleTransaction(name);
@@ -78,8 +78,8 @@ public class RolesResource extends AbstractCaosDBServerResource {
   protected Representation httpDeleteInChildClass()
       throws ConnectionException, SQLException, CaosDBException, IOException,
           NoSuchAlgorithmException, Exception {
-    if (!getRequestedNames().isEmpty()) {
-      final String name = getRequestedNames().get(0);
+    if (getRequestedItems().length > 0) {
+      final String name = getRequestedItems()[0];
       if (name != null) {
         final DeleteRoleTransaction t = new DeleteRoleTransaction(name);
         try {
@@ -133,26 +133,28 @@ public class RolesResource extends AbstractCaosDBServerResource {
   protected Representation httpPutInChildClass(final Representation entity)
       throws ConnectionException, JDOMException, Exception, xmlNotWellFormedException {
 
-    final String name = getRequestedNames().get(0);
-    String description = null;
+    if (getRequestedItems().length > 0) {
+      final String name = getRequestedItems()[0];
+      String description = null;
 
-    final Form f = new Form(entity);
-    if (!f.isEmpty()) {
-      description = f.getFirstValue("role_description");
-    }
+      final Form f = new Form(entity);
+      if (!f.isEmpty()) {
+        description = f.getFirstValue("role_description");
+      }
 
-    if (name != null && description != null) {
-      final Role role = new Role();
-      role.name = name;
-      role.description = description;
-      final UpdateRoleTransaction t = new UpdateRoleTransaction(role);
-      try {
-        t.execute();
-      } catch (final Message m) {
-        if (m == ServerMessages.ROLE_DOES_NOT_EXIST) {
-          return error(m, Status.CLIENT_ERROR_NOT_FOUND);
-        } else {
-          throw m;
+      if (name != null && description != null) {
+        final Role role = new Role();
+        role.name = name;
+        role.description = description;
+        final UpdateRoleTransaction t = new UpdateRoleTransaction(role);
+        try {
+          t.execute();
+        } catch (final Message m) {
+          if (m == ServerMessages.ROLE_DOES_NOT_EXIST) {
+            return error(m, Status.CLIENT_ERROR_NOT_FOUND);
+          } else {
+            throw m;
+          }
         }
       }
     }
diff --git a/src/main/java/caosdb/server/resource/UserResource.java b/src/main/java/caosdb/server/resource/UserResource.java
index b77ff8a4..7dc9111e 100644
--- a/src/main/java/caosdb/server/resource/UserResource.java
+++ b/src/main/java/caosdb/server/resource/UserResource.java
@@ -60,9 +60,9 @@ public class UserResource extends AbstractCaosDBServerResource {
     final Document doc = new Document();
     final Element rootElem = generateRootElement();
 
-    if (!getRequestedNames().isEmpty()) {
+    if (getRequestedItems().length > 0) {
       try {
-        final String username = getRequestedNames().get(0);
+        final String username = getRequestedItems()[0];
         final String realm =
             (getRequestAttributes().containsKey("realm")
                 ? (String) getRequestAttributes().get("realm")
@@ -92,7 +92,7 @@ public class UserResource extends AbstractCaosDBServerResource {
 
     try {
       final Form form = new Form(entity);
-      final String username = getRequestedNames().get(0);
+      final String username = getRequestedItems()[0];
       final String realm =
           (getRequestAttributes().containsKey("realm")
               ? (String) getRequestAttributes().get("realm")
@@ -187,7 +187,8 @@ public class UserResource extends AbstractCaosDBServerResource {
     final Document doc = new Document();
     final Element rootElem = generateRootElement();
 
-    final DeleteUserTransaction t = new DeleteUserTransaction(getRequestedNames().get(0));
+    final String username = getRequestedItems()[0];
+    final DeleteUserTransaction t = new DeleteUserTransaction(username);
     try {
       t.execute();
     } catch (final Message m) {
diff --git a/src/main/java/caosdb/server/resource/UserRolesResource.java b/src/main/java/caosdb/server/resource/UserRolesResource.java
index 27e14715..46d51ca4 100644
--- a/src/main/java/caosdb/server/resource/UserRolesResource.java
+++ b/src/main/java/caosdb/server/resource/UserRolesResource.java
@@ -47,7 +47,7 @@ public class UserRolesResource extends AbstractCaosDBServerResource {
   protected Representation httpGetInChildClass()
       throws ConnectionException, IOException, SQLException, CaosDBException,
           NoSuchAlgorithmException, Exception {
-    final String user = getRequestedNames().get(0);
+    final String user = getRequestedItems()[0];
     final String realm =
         (getRequestAttributes().get("realm") != null
             ? (String) getRequestAttributes().get("realm")
@@ -73,7 +73,7 @@ public class UserRolesResource extends AbstractCaosDBServerResource {
   @Override
   protected Representation httpPutInChildClass(final Representation entity)
       throws ConnectionException, JDOMException, Exception, xmlNotWellFormedException {
-    final String user = getRequestedNames().get(0);
+    final String user = getRequestedItems()[0];
     final String realm =
         (getRequestAttributes().get("realm") != null
             ? (String) getRequestAttributes().get("realm")
diff --git a/src/main/java/caosdb/server/resource/transaction/EntityResource.java b/src/main/java/caosdb/server/resource/transaction/EntityResource.java
index dc25bcff..70e7bdf7 100644
--- a/src/main/java/caosdb/server/resource/transaction/EntityResource.java
+++ b/src/main/java/caosdb/server/resource/transaction/EntityResource.java
@@ -30,8 +30,8 @@ import caosdb.server.entity.container.RetrieveContainer;
 import caosdb.server.entity.container.UpdateContainer;
 import caosdb.server.resource.AbstractCaosDBServerResource;
 import caosdb.server.resource.transaction.handlers.FileUploadHandler;
-import caosdb.server.resource.transaction.handlers.IDHandler;
 import caosdb.server.resource.transaction.handlers.RequestHandler;
+import caosdb.server.resource.transaction.handlers.SimpleDeleteRequestHandler;
 import caosdb.server.resource.transaction.handlers.SimpleGetRequestHandler;
 import caosdb.server.resource.transaction.handlers.SimpleWriteHandler;
 import caosdb.server.transaction.Delete;
@@ -72,7 +72,7 @@ public class EntityResource extends AbstractCaosDBServerResource {
   }
 
   protected RequestHandler<DeleteContainer> getDeleteRequestHandler() {
-    return new IDHandler<DeleteContainer>();
+    return new SimpleDeleteRequestHandler();
   }
 
   protected RequestHandler<InsertContainer> getPostRequestHandler() {
diff --git a/src/main/java/caosdb/server/resource/transaction/handlers/IDHandler.java b/src/main/java/caosdb/server/resource/transaction/handlers/SimpleDeleteRequestHandler.java
similarity index 61%
rename from src/main/java/caosdb/server/resource/transaction/handlers/IDHandler.java
rename to src/main/java/caosdb/server/resource/transaction/handlers/SimpleDeleteRequestHandler.java
index e641ed41..586d9085 100644
--- a/src/main/java/caosdb/server/resource/transaction/handlers/IDHandler.java
+++ b/src/main/java/caosdb/server/resource/transaction/handlers/SimpleDeleteRequestHandler.java
@@ -22,15 +22,29 @@
  */
 package caosdb.server.resource.transaction.handlers;
 
-import caosdb.server.entity.container.EntityByIdContainer;
+import caosdb.server.entity.container.DeleteContainer;
 import caosdb.server.resource.transaction.EntityResource;
 
-public class IDHandler<T extends EntityByIdContainer> extends RequestHandler<T> {
+public class SimpleDeleteRequestHandler extends RequestHandler<DeleteContainer> {
 
   @Override
-  public void handle(final EntityResource t, final T container) throws Exception {
-    for (final int id : t.getRequestedIDs()) {
-      container.add(id);
+  public void handle(final EntityResource t, final DeleteContainer container) throws Exception {
+    for (final String item : t.getRequestedItems()) {
+      String[] elem = item.split("@", 1);
+      Integer id = null;
+      String version = null;
+      try {
+        id = Integer.parseInt(elem[0]);
+      } catch (NumberFormatException e) {
+        // pass
+      }
+      if (elem.length > 1) {
+        version = elem[1];
+      }
+
+      if (id != null) {
+        container.add(id, version);
+      }
     }
   }
 }
diff --git a/src/main/java/caosdb/server/resource/transaction/handlers/SimpleGetRequestHandler.java b/src/main/java/caosdb/server/resource/transaction/handlers/SimpleGetRequestHandler.java
index 8fbb9d25..18c89d46 100644
--- a/src/main/java/caosdb/server/resource/transaction/handlers/SimpleGetRequestHandler.java
+++ b/src/main/java/caosdb/server/resource/transaction/handlers/SimpleGetRequestHandler.java
@@ -25,13 +25,29 @@ package caosdb.server.resource.transaction.handlers;
 import caosdb.server.entity.container.RetrieveContainer;
 import caosdb.server.resource.transaction.EntityResource;
 
-public class SimpleGetRequestHandler extends IDHandler<RetrieveContainer> {
+public class SimpleGetRequestHandler extends RequestHandler<RetrieveContainer> {
 
   @Override
   public void handle(final EntityResource t, final RetrieveContainer container) throws Exception {
-    super.handle(t, container);
-    for (final String name : t.getRequestedNames()) {
-      container.add(name);
+    for (final String item : t.getRequestedItems()) {
+      String[] elem = item.split("@", 2);
+      Integer id = null;
+      String name = null;
+      String version = null;
+      try {
+        id = Integer.parseInt(elem[0]);
+      } catch (NumberFormatException e) {
+        name = elem[0];
+      }
+      if (elem.length > 1) {
+        version = elem[1];
+      }
+
+      if (id != null) {
+        container.add(id, version);
+      } else {
+        container.add(name);
+      }
     }
   }
 }
diff --git a/src/main/java/caosdb/server/transaction/Insert.java b/src/main/java/caosdb/server/transaction/Insert.java
index ca7d20fe..18eb5f2c 100644
--- a/src/main/java/caosdb/server/transaction/Insert.java
+++ b/src/main/java/caosdb/server/transaction/Insert.java
@@ -22,7 +22,6 @@
  */
 package caosdb.server.transaction;
 
-import org.apache.shiro.SecurityUtils;
 import caosdb.server.database.access.Access;
 import caosdb.server.database.backend.transaction.InsertEntity;
 import caosdb.server.entity.EntityInterface;
@@ -32,6 +31,7 @@ import caosdb.server.entity.container.TransactionContainer;
 import caosdb.server.permissions.EntityACL;
 import caosdb.server.utils.EntityStatus;
 import caosdb.server.utils.ServerMessages;
+import org.apache.shiro.SecurityUtils;
 
 public class Insert extends WriteTransaction<InsertContainer> {
 
@@ -102,7 +102,7 @@ public class Insert extends WriteTransaction<InsertContainer> {
 
   public void insert(final TransactionContainer container, final Access access) throws Exception {
     if (container.getStatus().ordinal() >= EntityStatus.QUALIFIED.ordinal()) {
-      for(EntityInterface e : container) {
+      for (EntityInterface e : container) {
         e.setVersionDate(this.getTimestamp());
       }
       execute(new InsertEntity(container), access);
diff --git a/src/main/java/caosdb/server/transaction/Update.java b/src/main/java/caosdb/server/transaction/Update.java
index deba71ac..6a48aaac 100644
--- a/src/main/java/caosdb/server/transaction/Update.java
+++ b/src/main/java/caosdb/server/transaction/Update.java
@@ -22,12 +22,6 @@
  */
 package caosdb.server.transaction;
 
-import java.io.IOException;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.shiro.authz.AuthorizationException;
-import com.google.common.base.Objects;
 import caosdb.server.CaosDBException;
 import caosdb.server.database.access.Access;
 import caosdb.server.database.backend.transaction.RetrieveFullEntity;
@@ -44,6 +38,12 @@ import caosdb.server.permissions.EntityPermission;
 import caosdb.server.permissions.Permission;
 import caosdb.server.utils.EntityStatus;
 import caosdb.server.utils.ServerMessages;
+import com.google.common.base.Objects;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.shiro.authz.AuthorizationException;
 
 public class Update extends WriteTransaction<UpdateContainer> {
 
@@ -170,7 +170,7 @@ public class Update extends WriteTransaction<UpdateContainer> {
 
   private void update(final TransactionContainer container, final Access access) throws Exception {
     if (container.getStatus().ordinal() >= EntityStatus.QUALIFIED.ordinal()) {
-      for(EntityInterface e: container) {
+      for (EntityInterface e : container) {
         e.setVersionDate(getTimestamp());
       }
       execute(new UpdateEntity(container), access);
diff --git a/src/main/java/caosdb/server/transaction/WriteTransaction.java b/src/main/java/caosdb/server/transaction/WriteTransaction.java
index 5161f460..dd2a5817 100644
--- a/src/main/java/caosdb/server/transaction/WriteTransaction.java
+++ b/src/main/java/caosdb/server/transaction/WriteTransaction.java
@@ -37,9 +37,9 @@ public abstract class WriteTransaction<C extends TransactionContainer> extends T
     // acquire strong access. No other thread can have access until
     // it this strong access is released.
     setAccess(getMonitor().acquireStrongAccess(this));
-    
+
     // set SRID
-    
+
   }
 
   @Override
@@ -69,6 +69,6 @@ public abstract class WriteTransaction<C extends TransactionContainer> extends T
   }
 
   public String getSRID() {
-    return getContainer().getRequestId(); 
+    return getContainer().getRequestId();
   }
 }
diff --git a/src/main/java/caosdb/server/utils/Utils.java b/src/main/java/caosdb/server/utils/Utils.java
index 6c48906a..007b8f48 100644
--- a/src/main/java/caosdb/server/utils/Utils.java
+++ b/src/main/java/caosdb/server/utils/Utils.java
@@ -51,24 +51,6 @@ public class Utils {
   /** Secure random number generator, for secret random numbers. */
   private static final SecureRandom srand = new SecureRandom();
 
-  /**
-   * Check whether obj is non-null and can be parsed to an integer.
-   *
-   * @param obj The object to check.
-   * @return true if obj is not null and obj.toString() can be parsed as an integer
-   */
-  public static boolean isNonNullInteger(final Object obj) {
-    if (obj == null) {
-      return false;
-    }
-    try {
-      Integer.parseInt(obj.toString());
-    } catch (final NumberFormatException e) {
-      return false;
-    }
-    return true;
-  }
-
   /**
    * Regular expression pattern that checks a mail for RFC822 compliance.
    *
diff --git a/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java b/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java
index 4ff5d718..518f8c0b 100644
--- a/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java
+++ b/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java
@@ -5,6 +5,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
 import caosdb.server.CaosDBServer;
+import caosdb.server.ServerProperties;
 import java.io.IOException;
 import org.junit.BeforeClass;
 import org.junit.Rule;
@@ -25,8 +26,16 @@ public class WebinterfaceUtilsTest {
   public void testGetWebinterfaceReference() {
     WebinterfaceUtils utils = new WebinterfaceUtils(new Reference("https://host:2345/some_path"));
     String buildNumber = utils.getBuildNumber();
+    String contextRoot =
+        CaosDBServer.getServerProperties().getProperty(ServerProperties.KEY_CONTEXT_ROOT);
     String ref = utils.getWebinterfaceURI("sub");
-    assertEquals("https://host:2345/webinterface/" + buildNumber + "/sub", ref);
+    assertEquals(
+        "https://host:2345"
+            + (contextRoot == null || contextRoot.equals("") ? "" : contextRoot)
+            + "/webinterface/"
+            + buildNumber
+            + "/sub",
+        ref);
   }
 
   @Test
-- 
GitLab