From 0e9b77935f31eb9c3d4ba6f06a3dd36eedee8330 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Thu, 2 Jan 2020 17:19:23 +0100
Subject: [PATCH] WIP: refactoring xml serialization

---
 CHANGELOG.md                                  |   1 +
 pom.xml                                       |   7 +-
 .../xml/EntityXMLConverterHelper.java         | 233 +++++++++
 .../server/converter/xml/XMLParser.java       |  65 +++
 .../entity/container/DeleteContainer.java     |   6 +-
 .../entity/container/EntityByIdContainer.java |   4 +-
 .../entity/container/InsertContainer.java     |   6 +-
 .../entity/container/RetrieveContainer.java   |   6 +-
 .../container/TransactionContainer.java       |  19 +-
 .../entity/container/UpdateContainer.java     |   6 +-
 .../entity/container/WritableContainer.java   |   6 +-
 .../AbstractCaosDBServerResource.java         | 393 +--------------
 .../resource/AuthenticationResource.java      |  60 +--
 .../server/resource/DefaultResource.java      |   6 +-
 .../server/resource/EntityOwnerResource.java  |  12 -
 .../server/resource/FileSystemResource.java   |  25 +-
 .../caosdb/server/resource/InfoResource.java  |  10 +-
 .../server/resource/JdomRepresentation.java   |  22 +-
 .../server/resource/LogoutResource.java       |   6 +-
 .../resource/PermissionRulesResource.java     |  18 +-
 .../caosdb/server/resource/RolesResource.java |  22 +-
 .../server/resource/ScriptingResource.java    |  26 +-
 .../server/resource/ServerLogsResource.java   |   8 +-
 .../resource/ServerPropertiesResource.java    |   8 +-
 .../server/resource/SharedFileResource.java   |  11 +-
 .../server/resource/ThumbnailsResource.java   |   7 +-
 .../caosdb/server/resource/UserResource.java  |  20 +-
 .../server/resource/UserRolesResource.java    |  18 +-
 .../server/resource/XMLServerResource.java    | 475 ++++++++++++++++++
 .../resource/transaction/EntityResource.java  |  66 +--
 .../handlers/SimpleWriteHandler.java          |   4 +-
 .../server/permissions/EntityACLTest.java     |  10 +-
 .../TestAbstractCaosDBServerResource.java     |  17 +-
 33 files changed, 963 insertions(+), 640 deletions(-)
 create mode 100644 src/main/java/caosdb/server/converter/xml/EntityXMLConverterHelper.java
 create mode 100644 src/main/java/caosdb/server/converter/xml/XMLParser.java
 create mode 100644 src/main/java/caosdb/server/resource/XMLServerResource.java

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6898772f..ed30234e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - The sever by default now only serves TLS 1.2 and 1.3, all previous versions
   have been disabled in the default settings.  Make sure that your clients
   (especially the Python client) are up to date.
+* Update of Restlet library to 2.4.2
 
 ### Deprecated
 
diff --git a/pom.xml b/pom.xml
index ada34032..502b5bab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,6 +31,7 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.build.testSourceDirectory>src/test/java</project.build.testSourceDirectory>
+    <restlet-version>2.4.2</restlet-version>
   </properties>
   <repositories>
     <repository>
@@ -80,12 +81,12 @@
     <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet</artifactId>
-      <version>2.3.12</version>
+      <version>${restlet-version}</version>
     </dependency>
     <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.fileupload</artifactId>
-      <version>2.3.12</version>
+      <version>${restlet-version}</version>
     </dependency>
     <dependency>
       <groupId>mysql</groupId>
@@ -120,7 +121,7 @@
     <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.jetty</artifactId>
-      <version>2.3.12</version>
+      <version>${restlet-version}</version>
     </dependency>
     <dependency>
       <groupId>org.apache.commons</groupId>
diff --git a/src/main/java/caosdb/server/converter/xml/EntityXMLConverterHelper.java b/src/main/java/caosdb/server/converter/xml/EntityXMLConverterHelper.java
new file mode 100644
index 00000000..5b425e8d
--- /dev/null
+++ b/src/main/java/caosdb/server/converter/xml/EntityXMLConverterHelper.java
@@ -0,0 +1,233 @@
+package caosdb.server.converter.xml;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.jdom2.ProcessingInstruction;
+import org.restlet.data.MediaType;
+import org.restlet.engine.converter.ConverterHelper;
+import org.restlet.engine.resource.VariantInfo;
+import org.restlet.representation.Representation;
+import org.restlet.representation.Variant;
+import org.restlet.resource.Resource;
+import caosdb.server.accessControl.AuthenticationUtils;
+import caosdb.server.accessControl.Principal;
+import caosdb.server.accessControl.UserSources;
+import caosdb.server.entity.Entity;
+import caosdb.server.entity.EntityInterface;
+import caosdb.server.entity.container.Container;
+import caosdb.server.entity.container.TransactionContainer;
+import caosdb.server.resource.JdomRepresentation;
+
+public class EntityXMLConverterHelper extends ConverterHelper {
+  
+  private static final VariantInfo VARIANT_TEXT_XML = new VariantInfo(MediaType.TEXT_XML);
+  private static final VariantInfo VARIANT_APPLICATION_XML = new VariantInfo(MediaType.APPLICATION_XML);
+  private static final List<Class<?>> objectClasses = Collections.singletonList(TransactionContainer.class);
+  private static final XMLParser xmlParser = new XMLParser();
+  
+  @Override
+  public List<Class<?>> getObjectClasses(Variant source) {
+    return objectClasses;
+  }
+
+  @Override
+  public List<VariantInfo> getVariants(Class<?> source) throws IOException {
+    List<VariantInfo> result = null;
+
+    if (source != null && TransactionContainer.class.isAssignableFrom(source)) {
+        result = addVariant(result, VARIANT_TEXT_XML);
+        result = addVariant(result, VARIANT_APPLICATION_XML);
+    }
+
+    return result;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public <T> T toObject(Representation source, Class<T> target, Resource resource)
+      throws IOException {
+    Document xml;
+    try {
+      xml = xmlParser.parse(source.getStream());
+    } catch (JDOMException e) {
+      throw new IOException(e);
+    }
+    return (T) createContainer(xml, resource.getAttribute("srid"), resource.getRequest().getDate().getTime(), SecurityUtils.getSubject());
+  }
+
+  private Container<? extends EntityInterface> createContainer(Document xml, String sRID, long timestamp, Subject owner) {
+    TransactionContainer result = new TransactionContainer( owner, timestamp, sRID);
+    for (Element e : xml.getRootElement().getChildren()) {
+      result.add(new Entity(e));
+    }
+    return result;
+  }
+
+  @Override
+  public Representation toRepresentation(Object source, Variant target, Resource resource)
+      throws IOException {
+    return toJdomRepresentation((TransactionContainer) source, resource);
+  }
+  
+  private Representation toJdomRepresentation(TransactionContainer container, Resource resource) {
+    Document doc = new Document(generateRootElement(container, resource));
+    
+    String xsl = resource.getAttribute("xsl");
+    if(xsl != null) {
+      addStyleSheet(doc, xsl);
+    }
+
+    return new JdomRepresentation(doc, "  ");
+  }
+  
+  /** adds the xslt processing instruction to the document. */
+  private void addStyleSheet(Document document, String xslPath) {
+    final ProcessingInstruction pi =
+        new ProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"" + xslPath + "\" ");
+    document.getContent().add(0, pi);
+  }
+  
+  /**
+   * Creates the XML root.
+   *
+   * <p>The XML root node contains:
+   *
+   * <p>
+   *
+   * <ul>
+   *   <li>User info as per addUserInfo
+   *   <li>The sRID (server-side request ID)
+   *   <li>A timestamp
+   *   <li>The URI to this resource.
+   */
+  protected Element generateRootElement(TransactionContainer container, Resource resource) {
+    final Element retRoot = new Element("Response");
+    
+    addUserInfo(retRoot, container.getOwner());
+    retRoot.setAttribute("srid", container.getRequestId());
+    retRoot.setAttribute("timestamp", container.getTimestamp().toString());
+    retRoot.setAttribute("baseuri", resource.getRootRef().toString());
+    return retRoot;
+  }
+
+  /**
+   * Add the user info to the Response Element.
+   *
+   * @param retRoot
+   * @param user
+   */
+  private void addUserInfo(Element retRoot, Subject user) {
+
+    if (user != null && user.isAuthenticated()) {
+      Element userInfo = new Element("UserInfo");
+      if (!user.getPrincipal().equals(AuthenticationUtils.ANONYMOUS_USER.getPrincipal())) {
+        // TODO: deprecated
+        addNameAndRealm(retRoot, user);
+
+        // this is the new, correct way
+        addNameAndRealm(userInfo, user);
+      }
+
+      addRoles(userInfo, user);
+      retRoot.addContent(userInfo);
+    }
+  }
+
+  /**
+   * Add all roles of the current user to the user info, like this:
+   * `<UserInfo><Roles><Role>role1</Role><Role>role2</Role>...</Roles></UserInfo>`
+   *
+   * @param userInfo
+   * @param user
+   */
+  private void addRoles(Element userInfo, Subject user) {
+    Collection<String> roles = UserSources.resolve(user.getPrincipals());
+    if (roles == null) return;
+    Element rs = new Element("Roles");
+    for (String role : roles) {
+      Element r = new Element("Role");
+      r.addContent(role);
+      rs.addContent(r);
+    }
+    userInfo.addContent(rs);
+  }
+
+  /**
+   * Add the username and the realm of the current user to the user info (as attributes).
+   *
+   * @param userInfo
+   */
+  private void addNameAndRealm(Element userInfo, Subject user) {
+    userInfo.setAttribute("username", ((Principal) user.getPrincipal()).getUsername());
+    userInfo.setAttribute("realm", ((Principal) user.getPrincipal()).getRealm());
+  }
+
+  /*
+   **********************************************************************
+   * The following function is stolen from {@link
+   * org.restlet.engine.converter.StatusInfoHtmlConverter} and adapted.
+   * 
+   * Licensed under Apache 2.0.
+   * 
+   * Author: Manuel Boillod.
+   * Copyright 2005-2019 Talend
+   * ********************************************************************
+   */
+  /**
+   * Indicates if the given variant is compatible with the media types supported by this converter.
+   * 
+   * @param variant The variant.
+   * @return True if the given variant is compatible with the media types supported by this
+   *         converter.
+   */
+  protected boolean isCompatible(Variant variant) {
+    return (variant != null) && (VARIANT_TEXT_XML.isCompatible(variant)
+        || VARIANT_APPLICATION_XML.isCompatible(variant));
+  }
+
+  /*
+   **********************************************************************
+   * The following function is stolen from {@link
+   * org.restlet.engine.converter.StatusInfoHtmlConverter} and adapted.
+   * 
+   * Licensed under Apache 2.0.
+   * 
+   * Author: Manuel Boillod.
+   * Copyright 2005-2019 Talend
+   * ********************************************************************
+   */
+  @Override
+  public float score(Object source, Variant target, Resource resource) {
+    float result = -1.0F;
+
+    if (source instanceof Container && isCompatible(target)) {
+      result = 1.0F;
+    }
+
+    return result;
+  }
+
+  /*
+   **********************************************************************
+   * The following function is stolen from {@link
+   * org.restlet.engine.converter.StatusInfoHtmlConverter} and adapted.
+   * 
+   * Licensed under Apache 2.0.
+   * 
+   * Author: Manuel Boillod.
+   * Copyright 2005-2019 Talend
+   * ********************************************************************
+   */
+  @Override
+  public <T> float score(Representation source, Class<T> target, Resource resource) {
+    return -1.0F;
+  }
+
+}
diff --git a/src/main/java/caosdb/server/converter/xml/XMLParser.java b/src/main/java/caosdb/server/converter/xml/XMLParser.java
new file mode 100644
index 00000000..cd966043
--- /dev/null
+++ b/src/main/java/caosdb/server/converter/xml/XMLParser.java
@@ -0,0 +1,65 @@
+package caosdb.server.converter.xml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import org.jdom2.Document;
+import org.jdom2.JDOMException;
+import org.jdom2.input.SAXBuilder;
+
+public class XMLParser {
+  
+    private final LinkedList<SAXBuilder> pool = new LinkedList<SAXBuilder>();
+    private final int max = 25;
+    private final int init = 5;
+    private final int min = 5;
+
+    private SAXBuilder getSAXBuilder() {
+      try {
+        synchronized (this.pool) {
+          return this.pool.removeFirst();
+        }
+      } catch (final NoSuchElementException e) {
+      }
+      preLoad(this.min);
+      return new SAXBuilder();
+    }
+
+    private void release(final SAXBuilder sb) {
+      synchronized (this.pool) {
+        if (this.pool.size() <= this.max) {
+          this.pool.add(sb);
+        }
+      }
+    }
+
+    public XMLParser() {
+      preLoad(this.init);
+    }
+
+    public Document parse(final InputStream is) throws JDOMException, IOException {
+      final SAXBuilder sb = getSAXBuilder();
+      Document ret;
+      try {
+        ret = sb.build(is);
+      } finally {
+        release(sb);
+      }
+      return ret;
+    }
+
+    public void preLoad(final int i) {
+      final Thread t =
+          new Thread() {
+            @Override
+            public void run() {
+              for (int j = 0; j < i; j++) {
+                final SAXBuilder sb = new SAXBuilder();
+                release(sb);
+              }
+            }
+          };
+      t.start();
+    }
+  }
diff --git a/src/main/java/caosdb/server/entity/container/DeleteContainer.java b/src/main/java/caosdb/server/entity/container/DeleteContainer.java
index c219ee5e..907e6930 100644
--- a/src/main/java/caosdb/server/entity/container/DeleteContainer.java
+++ b/src/main/java/caosdb/server/entity/container/DeleteContainer.java
@@ -22,9 +22,9 @@
  */
 package caosdb.server.entity.container;
 
-import caosdb.server.entity.DeleteEntity;
-import java.util.HashMap;
+import java.util.Map;
 import org.apache.shiro.subject.Subject;
+import caosdb.server.entity.DeleteEntity;
 
 public class DeleteContainer extends EntityByIdContainer {
 
@@ -34,7 +34,7 @@ public class DeleteContainer extends EntityByIdContainer {
       final Subject user,
       final Long timestamp,
       final String srid,
-      final HashMap<String, String> flags) {
+      final Map<String, String> flags) {
     super(user, timestamp, srid, flags);
   }
 
diff --git a/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java b/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java
index 1bfda202..cbcb93e9 100644
--- a/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java
+++ b/src/main/java/caosdb/server/entity/container/EntityByIdContainer.java
@@ -22,7 +22,7 @@
  */
 package caosdb.server.entity.container;
 
-import java.util.HashMap;
+import java.util.Map;
 import org.apache.shiro.subject.Subject;
 
 public abstract class EntityByIdContainer extends TransactionContainer {
@@ -32,7 +32,7 @@ public abstract class EntityByIdContainer extends TransactionContainer {
       final Subject user,
       final Long timestamp,
       final String srid,
-      final HashMap<String, String> flags) {
+      final Map<String, String> flags) {
     super(user, timestamp, srid, flags);
   }
 
diff --git a/src/main/java/caosdb/server/entity/container/InsertContainer.java b/src/main/java/caosdb/server/entity/container/InsertContainer.java
index 6810e053..2d7bd2a2 100644
--- a/src/main/java/caosdb/server/entity/container/InsertContainer.java
+++ b/src/main/java/caosdb/server/entity/container/InsertContainer.java
@@ -22,10 +22,10 @@
  */
 package caosdb.server.entity.container;
 
-import caosdb.server.entity.InsertEntity;
-import java.util.HashMap;
+import java.util.Map;
 import org.apache.shiro.subject.Subject;
 import org.jdom2.Element;
+import caosdb.server.entity.InsertEntity;
 
 public class InsertContainer extends WritableContainer {
 
@@ -33,7 +33,7 @@ public class InsertContainer extends WritableContainer {
       final Subject user,
       final Long timestamp,
       final String srid,
-      final HashMap<String, String> flags) {
+      final Map<String, String> flags) {
     super(user, timestamp, srid, flags);
   }
 
diff --git a/src/main/java/caosdb/server/entity/container/RetrieveContainer.java b/src/main/java/caosdb/server/entity/container/RetrieveContainer.java
index 9b4f7364..04e67d1d 100644
--- a/src/main/java/caosdb/server/entity/container/RetrieveContainer.java
+++ b/src/main/java/caosdb/server/entity/container/RetrieveContainer.java
@@ -22,9 +22,9 @@
  */
 package caosdb.server.entity.container;
 
-import caosdb.server.entity.RetrieveEntity;
-import java.util.HashMap;
+import java.util.Map;
 import org.apache.shiro.subject.Subject;
+import caosdb.server.entity.RetrieveEntity;
 
 public class RetrieveContainer extends EntityByIdContainer {
 
@@ -34,7 +34,7 @@ public class RetrieveContainer extends EntityByIdContainer {
       final Subject user,
       final Long timestamp,
       final String srid,
-      final HashMap<String, String> flags) {
+      final Map<String, String> flags) {
     super(user, timestamp, srid, flags);
   }
 
diff --git a/src/main/java/caosdb/server/entity/container/TransactionContainer.java b/src/main/java/caosdb/server/entity/container/TransactionContainer.java
index ea4cc02e..31143759 100644
--- a/src/main/java/caosdb/server/entity/container/TransactionContainer.java
+++ b/src/main/java/caosdb/server/entity/container/TransactionContainer.java
@@ -22,6 +22,12 @@
  */
 package caosdb.server.entity.container;
 
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.apache.shiro.subject.Subject;
+import org.jdom2.Element;
 import caosdb.server.CaosDBServer;
 import caosdb.server.database.misc.TransactionBenchmark;
 import caosdb.server.entity.Entity;
@@ -30,11 +36,6 @@ import caosdb.server.entity.FileProperties;
 import caosdb.server.entity.xml.ToElementable;
 import caosdb.server.jobs.JobTarget;
 import caosdb.server.utils.EntityStatus;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import org.apache.shiro.subject.Subject;
-import org.jdom2.Element;
 
 public class TransactionContainer extends Container<Entity> implements ToElementable, JobTarget {
 
@@ -57,7 +58,7 @@ public class TransactionContainer extends Container<Entity> implements ToElement
       final Subject user,
       final Long timestamp,
       final String srid,
-      final HashMap<String, String> flags) {
+      final Map<String, String> flags) {
     this(user, timestamp, srid);
     setFlags(flags);
   }
@@ -88,9 +89,9 @@ public class TransactionContainer extends Container<Entity> implements ToElement
     this.messages.add(m);
   }
 
-  private HashMap<String, String> flags = null;
+  private Map<String, String> flags = null;
 
-  public HashMap<String, String> getFlags() {
+  public Map<String, String> getFlags() {
     return this.flags;
   }
 
@@ -174,7 +175,7 @@ public class TransactionContainer extends Container<Entity> implements ToElement
     return null;
   }
 
-  public void setFlags(final HashMap<String, String> flags) {
+  public void setFlags(final Map<String, String> flags) {
     this.flags = flags;
   }
 
diff --git a/src/main/java/caosdb/server/entity/container/UpdateContainer.java b/src/main/java/caosdb/server/entity/container/UpdateContainer.java
index 843e70cf..f09159a2 100644
--- a/src/main/java/caosdb/server/entity/container/UpdateContainer.java
+++ b/src/main/java/caosdb/server/entity/container/UpdateContainer.java
@@ -22,10 +22,10 @@
  */
 package caosdb.server.entity.container;
 
-import caosdb.server.entity.UpdateEntity;
-import java.util.HashMap;
+import java.util.Map;
 import org.apache.shiro.subject.Subject;
 import org.jdom2.Element;
+import caosdb.server.entity.UpdateEntity;
 
 public class UpdateContainer extends WritableContainer {
 
@@ -35,7 +35,7 @@ public class UpdateContainer extends WritableContainer {
       final Subject user,
       final Long timestamp,
       final String srid,
-      final HashMap<String, String> flags) {
+      final Map<String, String> flags) {
     super(user, timestamp, srid, flags);
   }
 
diff --git a/src/main/java/caosdb/server/entity/container/WritableContainer.java b/src/main/java/caosdb/server/entity/container/WritableContainer.java
index 3000aa5a..623bea6c 100644
--- a/src/main/java/caosdb/server/entity/container/WritableContainer.java
+++ b/src/main/java/caosdb/server/entity/container/WritableContainer.java
@@ -22,10 +22,10 @@
  */
 package caosdb.server.entity.container;
 
-import caosdb.server.entity.FileProperties;
-import java.util.HashMap;
+import java.util.Map;
 import org.apache.shiro.subject.Subject;
 import org.jdom2.Element;
+import caosdb.server.entity.FileProperties;
 
 public abstract class WritableContainer extends TransactionContainer {
   private static final long serialVersionUID = -4097777313518959519L;
@@ -34,7 +34,7 @@ public abstract class WritableContainer extends TransactionContainer {
       final Subject user,
       final Long timestamp,
       final String srid,
-      final HashMap<String, String> flags) {
+      final Map<String, String> flags) {
     super(user, timestamp, srid, flags);
   }
 
diff --git a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java
index ea4e65f0..95f9b014 100644
--- a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java
+++ b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java
@@ -25,46 +25,16 @@ package caosdb.server.resource;
 
 import static caosdb.server.utils.Utils.isNonNullInteger;
 import static java.net.URLDecoder.decode;
-
-import caosdb.server.CaosDBException;
-import caosdb.server.accessControl.AuthenticationUtils;
-import caosdb.server.accessControl.Principal;
-import caosdb.server.accessControl.UserSources;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.entity.Message;
-import caosdb.server.utils.ServerMessages;
-import caosdb.server.utils.WebinterfaceUtils;
-import java.io.IOException;
-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;
-import java.util.NoSuchElementException;
-import java.util.logging.Level;
-import org.apache.commons.fileupload.FileUploadException;
+import java.util.Map;
 import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.AuthenticationException;
-import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.subject.Subject;
-import org.jdom2.Document;
-import org.jdom2.Element;
-import org.jdom2.JDOMException;
-import org.jdom2.input.SAXBuilder;
 import org.restlet.data.Form;
-import org.restlet.data.Header;
 import org.restlet.data.Parameter;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.resource.Delete;
-import org.restlet.resource.Get;
-import org.restlet.resource.Post;
-import org.restlet.resource.Put;
 import org.restlet.resource.ServerResource;
-import org.restlet.util.Series;
+import caosdb.server.utils.WebinterfaceUtils;
 
 /**
  * Class is still under construction.
@@ -73,11 +43,8 @@ import org.restlet.util.Series;
  */
 public abstract class AbstractCaosDBServerResource extends ServerResource {
 
-  private final HashMap<String, String> flags = new HashMap<String, String>();
+  private final Map<String, String> flags = new HashMap<String, String>();
   private Long timestamp = null;
-  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>();
@@ -88,19 +55,6 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
     return this.utils;
   }
 
-  public static class xmlNotWellFormedException extends Exception {
-    private static final long serialVersionUID = -6836378704013776849L;
-  }
-
-  /**
-   * Returns the (probably unique) server request ID.
-   *
-   * @return The server request ID.
-   */
-  public String getSRID() {
-    return this.sRID;
-  }
-
   public Long getTimestamp() {
     return this.timestamp;
   }
@@ -116,6 +70,8 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
    */
   @Override
   protected void doInit() {
+    
+    // wrap the request entity into an entity with proper logging
     if (getRequestEntity().isTransient() && !getRequestEntity().isEmpty()) {
       final ReReadableRepresentation r = new ReReadableRepresentation(getRequestEntity());
       getRequest().setEntity(r);
@@ -124,12 +80,8 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
     this.utils = WebinterfaceUtils.getInstance(getHostRef());
 
     this.timestamp = getRequest().getDate().getTime();
-
-    this.sRID = getRequest().getAttributes().get("SRID").toString();
-
-    final Series<Header> headers = getRequest().getHeaders();
-
-    this.setCRID(headers.getFirstValue("crequestid"));
+    
+    this.setAttribute("xsl", getXSLScript());
 
     String specifier = (String) getRequestAttributes().get("specifier");
     if (specifier != null && !specifier.equals("")) {
@@ -174,260 +126,12 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
   @Override
   protected void doRelease() {}
 
-  /**
-   * Creates the XML root.
-   *
-   * <p>The XML root node contains:
-   *
-   * <p>
-   *
-   * <ul>
-   *   <li>User info as per addUserInfo
-   *   <li>The sRID (server-side request ID)
-   *   <li>A timestamp
-   *   <li>The URI to this resource.
-   */
-  protected Element generateRootElement() {
-    final Element retRoot = new Element("Response");
-
-    addUserInfo(retRoot, getUser());
-    retRoot.setAttribute("srid", getSRID());
-    if (this.getCRID() != null) {
-      retRoot.setAttribute("crid", this.getCRID());
-    }
-    retRoot.setAttribute("timestamp", getTimestamp().toString());
-    retRoot.setAttribute("baseuri", getRootRef().toString());
-    return retRoot;
-  }
-
-  /**
-   * Add the user info to the Response Element.
-   *
-   * @param retRoot
-   * @param user
-   */
-  private void addUserInfo(Element retRoot, Subject user) {
-
-    if (user != null && user.isAuthenticated()) {
-      Element userInfo = new Element("UserInfo");
-      if (!user.getPrincipal().equals(AuthenticationUtils.ANONYMOUS_USER.getPrincipal())) {
-        // TODO: deprecated
-        addNameAndRealm(retRoot, user);
-
-        // this is the new, correct way
-        addNameAndRealm(userInfo, user);
-      }
-
-      addRoles(userInfo, user);
-      retRoot.addContent(userInfo);
-    }
-  }
-
-  /**
-   * Add all roles of the current user to the user info, like this:
-   * `<UserInfo><Roles><Role>role1</Role><Role>role2</Role>...</Roles></UserInfo>`
-   *
-   * @param userInfo
-   * @param user
-   */
-  private void addRoles(Element userInfo, Subject user) {
-    Collection<String> roles = UserSources.resolve(user.getPrincipals());
-    if (roles == null) return;
-    Element rs = new Element("Roles");
-    for (String role : roles) {
-      Element r = new Element("Role");
-      r.addContent(role);
-      rs.addContent(r);
-    }
-    userInfo.addContent(rs);
-  }
-
-  /**
-   * Add the username and the realm of the current user to the user info (as attributes).
-   *
-   * @param userInfo
-   */
-  private void addNameAndRealm(Element userInfo, Subject user) {
-    userInfo.setAttribute("username", ((Principal) user.getPrincipal()).getUsername());
-    userInfo.setAttribute("realm", ((Principal) user.getPrincipal()).getRealm());
-  }
-
-  @Get
-  public Representation httpGet() {
-    try {
-      return httpGetInChildClass();
-    } catch (final Throwable t) {
-      return handleThrowable(t);
-    }
-  }
-
-  protected abstract Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception;
-
-  @Post
-  public Representation httpPost(final Representation entity) {
-    try {
-      return httpPostInChildClass(entity);
-    } catch (final Throwable t) {
-      return handleThrowable(t);
-    }
-  }
-
-  @Put
-  public Representation httpPut(final Representation entity) {
-    try {
-      // catch empty post entity.
-      if (entity == null) {
-        return error(ServerMessages.REQUEST_BODY_EMPTY, Status.CLIENT_ERROR_BAD_REQUEST);
-      } else {
-        return httpPutInChildClass(entity);
-      }
-    } catch (final Throwable t) {
-      return handleThrowable(t);
-    }
-  }
-
-  protected Representation httpPutInChildClass(final Representation entity)
-      throws ConnectionException, JDOMException, Exception, xmlNotWellFormedException {
-    getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
-    return null;
-  }
-
-  protected Representation httpDeleteInChildClass()
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, Exception {
-    getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
-    return null;
-  }
-
-  @Delete
-  public Representation httpDelete() {
-    try {
-      return httpDeleteInChildClass();
-    } catch (final Throwable t) {
-      return handleThrowable(t);
-    }
-  }
-
-  protected Representation httpPostInChildClass(final Representation entity)
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, xmlNotWellFormedException, JDOMException, Exception {
-    getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
-    return null;
-  }
-
-  public Document parseEntity(final Representation entity)
-      throws xmlNotWellFormedException, IOException {
-    return parseEntity(entity.getStream());
-  }
-
-  public Document parseEntity(final InputStream stream)
-      throws xmlNotWellFormedException, IOException {
-    try {
-      return xmlparser.parse(stream);
-    } catch (final JDOMException e) {
-      throw new xmlNotWellFormedException();
-    }
-  }
-
   protected String getXSLScript() {
     return this.utils.getWebinterfaceURI("webcaosdb.xsl");
   }
 
-  /** Wrap an element for an "OK" response. */
-  protected JdomRepresentation ok(Element root) {
-    return ok(new Document(root));
-  }
-
-  /**
-   * Return a JDomRepresentation of the document and leave the {@link Response}'s {@link Status}
-   * where it is - which is usually 200 - OK when this method happens to be called.
-   */
-  protected JdomRepresentation ok(final Document doc) {
-    return new JdomRepresentation(doc, "  ", getXSLScript());
-  }
-
-  /**
-   * Return a Representation containing the error message and set the {@link Response}'s {@link
-   * Status}.
-   *
-   * @param m - the error message.
-   * @param status - the response status
-   * @return A Representation of the error.
-   */
-  protected Representation error(final Message m, final Status status) {
-    final Document doc = new Document();
-    final Element root = generateRootElement();
-    root.addContent(m.toElement().setName("Error"));
-    doc.setRootElement(root);
-    return error(new JdomRepresentation(doc, "  ", getXSLScript()), status);
-  }
-
-  protected Representation error(Representation entity, Status status) {
-    getResponse().setStatus(status);
-    return entity;
-  }
-
-  protected Representation error(final Message m) {
-    return error(m, Status.SERVER_ERROR_INTERNAL);
-  }
-
-  protected Representation error(final Status status) {
-    return error((Representation) null, status);
-  }
-
-  /**
-   * Return a Representation containing the warning message but leave the {@link Response}'s {@link
-   * Status} where it is - which is usually 200 - OK when this method happens to be called.
-   *
-   * @param m - the warning message.
-   * @return A Representation of the warning.
-   */
-  protected JdomRepresentation warning(final Message m) {
-    final Document doc = new Document();
-    final Element root = generateRootElement();
-    root.addContent(m.toElement().setName("Warning"));
-    doc.setRootElement(root);
-    return new JdomRepresentation(doc, "  ", getXSLScript());
-  }
-
-  protected Representation noWellFormedNess() {
-    return error(ServerMessages.REQUEST_BODY_NOT_WELLFORMED);
-  }
-
-  protected Representation emptyEntity() {
-    return error(ServerMessages.REQUEST_BODY_EMPTY);
-  }
-
-  protected Representation connectionFailed() {
-    return error(ServerMessages.CANNOT_CONNECT_TO_DATABASE);
-  }
-
-  public Representation handleThrowable(final Throwable t) {
-    try {
-      getRequest().getAttributes().put("THROWN", t);
-      throw t;
-    } catch (final AuthenticationException e) {
-      getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN);
-      return null;
-    } catch (final AuthorizationException e) {
-      getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN);
-      return null;
-    } catch (final Message m) {
-      return error(m, Status.CLIENT_ERROR_BAD_REQUEST);
-    } catch (final FileUploadException e) {
-      return error(ServerMessages.FILE_UPLOAD_FAILED);
-    } catch (final ConnectionException e) {
-      return connectionFailed();
-    } catch (final xmlNotWellFormedException e) {
-      return noWellFormedNess();
-    } catch (final JDOMException e) {
-      return noWellFormedNess();
-    } catch (final Throwable e) {
-      getLogger().log(Level.SEVERE, "UNKNOWN ERROR", e);
-      return error(ServerMessages.UNKNOWN_ERROR(getSRID()));
-    }
+  protected String getSRID() {
+    return getRequest().getAttributes().get("SRID").toString();
   }
 
   public ArrayList<Integer> getRequestedIDs() {
@@ -442,83 +146,8 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
     this.requestedNames = requestedNames;
   }
 
-  public HashMap<String, String> getFlags() {
+  public Map<String, String> getFlags() {
     return this.flags;
   }
-
-  protected Element generateRootElement(Element... elements) {
-    Element root = generateRootElement();
-    for (Element e : elements) {
-      root.addContent(e);
-    }
-    return root;
-  }
-
-  /**
-   * Returns the client request ID, which can be set by the client.
-   *
-   * @return The cRID.
-   */
-  public String getCRID() {
-    return cRID;
-  }
-
-  public void setCRID(String cRID) {
-    this.cRID = cRID;
-  }
-
-  public static class XMLParser {
-    private final LinkedList<SAXBuilder> pool = new LinkedList<SAXBuilder>();
-    private final int max = 25;
-    private final int init = 5;
-    private final int min = 5;
-
-    private SAXBuilder getSAXBuilder() {
-      try {
-        synchronized (this.pool) {
-          return this.pool.removeFirst();
-        }
-      } catch (final NoSuchElementException e) {
-      }
-      preLoad(this.min);
-      return new SAXBuilder();
-    }
-
-    private void release(final SAXBuilder sb) {
-      synchronized (this.pool) {
-        if (this.pool.size() <= this.max) {
-          this.pool.add(sb);
-        }
-      }
-    }
-
-    public XMLParser() {
-      preLoad(this.init);
-    }
-
-    public Document parse(final InputStream is) throws JDOMException, IOException {
-      final SAXBuilder sb = getSAXBuilder();
-      Document ret;
-      try {
-        ret = sb.build(is);
-      } finally {
-        release(sb);
-      }
-      return ret;
-    }
-
-    public void preLoad(final int i) {
-      final Thread t =
-          new Thread() {
-            @Override
-            public void run() {
-              for (int j = 0; j < i; j++) {
-                final SAXBuilder sb = new SAXBuilder();
-                release(sb);
-              }
-            }
-          };
-      t.start();
-    }
-  }
+  
 }
diff --git a/src/main/java/caosdb/server/resource/AuthenticationResource.java b/src/main/java/caosdb/server/resource/AuthenticationResource.java
index 11643907..4da79219 100644
--- a/src/main/java/caosdb/server/resource/AuthenticationResource.java
+++ b/src/main/java/caosdb/server/resource/AuthenticationResource.java
@@ -22,13 +22,6 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBException;
-import caosdb.server.accessControl.AuthenticationUtils;
-import caosdb.server.accessControl.RealmUsernamePasswordToken;
-import caosdb.server.accessControl.UserSources;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.entity.xml.ToElementable;
-import caosdb.server.utils.ServerMessages;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
@@ -38,48 +31,39 @@ import org.apache.shiro.authc.AccountException;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.CredentialsException;
 import org.apache.shiro.subject.Subject;
-import org.jdom2.Document;
-import org.jdom2.Element;
-import org.jdom2.JDOMException;
 import org.restlet.data.Form;
 import org.restlet.data.Reference;
 import org.restlet.data.Status;
 import org.restlet.representation.Representation;
+import org.restlet.resource.Delete;
+import org.restlet.resource.Post;
+import caosdb.server.CaosDBException;
+import caosdb.server.accessControl.AuthenticationUtils;
+import caosdb.server.accessControl.RealmUsernamePasswordToken;
+import caosdb.server.accessControl.UserSources;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.entity.Message;
+import caosdb.server.utils.ServerMessages;
 
 public class AuthenticationResource extends AbstractCaosDBServerResource {
 
-  /** Returns single "Login" element. XSLT will create a form. */
-  @Override
-  protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
-    final Document doc = new Document();
-    final Element rootElem = generateRootElement();
-    doc.setRootElement(rootElem);
-
-    final Element loginElem = new Element("Login");
-    rootElem.addContent(loginElem);
-
-    return ok(doc);
-  }
-
-  @Override
-  protected Representation httpDeleteInChildClass()
+  @Delete
+  public Message logout()
       throws ConnectionException, SQLException, CaosDBException, IOException,
           NoSuchAlgorithmException, Exception {
     final Subject user = SecurityUtils.getSubject();
     if (user.isAuthenticated()) {
       user.logout();
       getResponse().getCookieSettings().addAll(AuthenticationUtils.getLogoutCookies());
-      return success(ServerMessages.LOGOUT_INFO);
+      return ServerMessages.LOGOUT_INFO;
     }
+
     getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN);
     return null;
   }
 
-  @Override
-  protected Representation httpPostInChildClass(final Representation entity)
-      throws ConnectionException, JDOMException, Exception, xmlNotWellFormedException {
+  @Post
+  public Message login(final Representation entity) {
 
     getUser().logout();
 
@@ -106,7 +90,7 @@ public class AuthenticationResource extends AbstractCaosDBServerResource {
         if (referrerRef != null && !"logout".equals(referrerRef.getLastSegment())) {
           getResponse().redirectSeeOther(referrerRef);
         }
-        return success(null);
+        return null;
 
       } catch (final CredentialsException e) {
         getLogger().log(Level.INFO, "LOGIN_FAILED", e);
@@ -121,16 +105,4 @@ public class AuthenticationResource extends AbstractCaosDBServerResource {
     return null;
   }
 
-  private JdomRepresentation success(final ToElementable msg) {
-
-    final Document doc = new Document();
-    final Element rootElem = generateRootElement();
-    doc.setRootElement(rootElem);
-
-    if (msg != null) {
-      msg.addToElement(rootElem);
-    }
-
-    return ok(doc);
-  }
 }
diff --git a/src/main/java/caosdb/server/resource/DefaultResource.java b/src/main/java/caosdb/server/resource/DefaultResource.java
index e26171f0..a199f986 100644
--- a/src/main/java/caosdb/server/resource/DefaultResource.java
+++ b/src/main/java/caosdb/server/resource/DefaultResource.java
@@ -22,16 +22,16 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBException;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
 import org.jdom2.Document;
 import org.jdom2.Element;
 import org.restlet.representation.Representation;
+import caosdb.server.CaosDBException;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 
-public class DefaultResource extends AbstractCaosDBServerResource {
+public class DefaultResource extends  XMLServerResource {
 
   private Element responseBody = null;
 
diff --git a/src/main/java/caosdb/server/resource/EntityOwnerResource.java b/src/main/java/caosdb/server/resource/EntityOwnerResource.java
index 5841eeb5..d4e58f1c 100644
--- a/src/main/java/caosdb/server/resource/EntityOwnerResource.java
+++ b/src/main/java/caosdb/server/resource/EntityOwnerResource.java
@@ -22,20 +22,8 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.entity.container.RetrieveContainer;
 import caosdb.server.resource.transaction.EntityResource;
-import caosdb.server.resource.transaction.handlers.RequestHandler;
-import caosdb.server.resource.transaction.handlers.RetriveOwnerRequestHandler;
 
 public class EntityOwnerResource extends EntityResource {
 
-  public EntityOwnerResource() {
-    // only retrieval is allowed
-    super(true, false, false, false);
-  }
-
-  @Override
-  protected RequestHandler<RetrieveContainer> getGetRequestHandler() {
-    return new RetriveOwnerRequestHandler();
-  }
 }
diff --git a/src/main/java/caosdb/server/resource/FileSystemResource.java b/src/main/java/caosdb/server/resource/FileSystemResource.java
index 37f0e9ff..8b78d617 100644
--- a/src/main/java/caosdb/server/resource/FileSystemResource.java
+++ b/src/main/java/caosdb/server/resource/FileSystemResource.java
@@ -24,7 +24,17 @@ package caosdb.server.resource;
 
 import static caosdb.server.FileSystem.getFromFileSystem;
 import static java.net.URLDecoder.decode;
-
+import java.io.File;
+import java.io.IOException;
+import org.jdom2.Attribute;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.restlet.data.Disposition;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.representation.FileRepresentation;
+import org.restlet.representation.Representation;
 import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 import caosdb.server.database.exceptions.EntityDoesNotExistException;
 import caosdb.server.database.misc.TransactionBenchmark;
@@ -39,17 +49,6 @@ import caosdb.server.transaction.RetrieveSparseEntityByPath;
 import caosdb.server.transaction.Transaction;
 import caosdb.server.utils.FileUtils;
 import caosdb.server.utils.ServerMessages;
-import java.io.File;
-import java.io.IOException;
-import org.jdom2.Attribute;
-import org.jdom2.Document;
-import org.jdom2.Element;
-import org.jdom2.JDOMException;
-import org.restlet.data.Disposition;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.FileRepresentation;
-import org.restlet.representation.Representation;
 
 /**
  * Download files via GET method from the file system directly without making the detour through the
@@ -57,7 +56,7 @@ import org.restlet.representation.Representation;
  *
  * @author Timm Fitschen
  */
-public class FileSystemResource extends AbstractCaosDBServerResource {
+public class FileSystemResource extends  XMLServerResource {
 
   public static Message ORPHANED_FILE_WARNING =
       new Message(
diff --git a/src/main/java/caosdb/server/resource/InfoResource.java b/src/main/java/caosdb/server/resource/InfoResource.java
index 924d6698..d706e9c6 100644
--- a/src/main/java/caosdb/server/resource/InfoResource.java
+++ b/src/main/java/caosdb/server/resource/InfoResource.java
@@ -22,17 +22,17 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.database.misc.TransactionBenchmark;
-import caosdb.server.utils.FlagInfo;
-import caosdb.server.utils.Info;
 import org.jdom2.Document;
 import org.jdom2.Element;
 import org.jdom2.JDOMException;
 import org.restlet.representation.Representation;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.database.misc.TransactionBenchmark;
+import caosdb.server.utils.FlagInfo;
+import caosdb.server.utils.Info;
 
 /** This class represents the information retrieved by /Info requests (only GET) to CaosDB. */
-public class InfoResource extends AbstractCaosDBServerResource {
+public class InfoResource extends  XMLServerResource {
 
   /**
    * The response to the HTTP GET request is generated here.
diff --git a/src/main/java/caosdb/server/resource/JdomRepresentation.java b/src/main/java/caosdb/server/resource/JdomRepresentation.java
index 04fbdac3..984bcc71 100644
--- a/src/main/java/caosdb/server/resource/JdomRepresentation.java
+++ b/src/main/java/caosdb/server/resource/JdomRepresentation.java
@@ -22,17 +22,13 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.Writer;
 import org.jdom2.Document;
-import org.jdom2.ProcessingInstruction;
 import org.jdom2.output.Format;
 import org.jdom2.output.XMLOutputter;
 import org.restlet.data.MediaType;
-import org.restlet.data.Reference;
 import org.restlet.representation.WriterRepresentation;
 
 /**
@@ -64,27 +60,13 @@ public class JdomRepresentation extends WriterRepresentation {
    * @param indent Usually a number of whitespaces for better human readbility.
    * @param xslPath A String containing a meaningful path to a xslt file.
    */
-  public JdomRepresentation(final Document document, final String indent, final String xslPath) {
+  public JdomRepresentation(final Document document, final String indent) {
     super(MediaType.TEXT_XML);
     this.indent = indent;
     this.document = document;
-    if (xslPath != null && document != null) {
-      addStyleSheet(document, xslPath);
-    }
-  }
-
-  public static final String getWebUIRef(final Reference reference) {
-    return reference.getHostIdentifier()
-        + CaosDBServer.getServerProperty(ServerProperties.KEY_CONTEXT_ROOT)
-        + "/webinterface/";
   }
 
-  /** adds the xslt processing instruction to the document. */
-  protected final void addStyleSheet(Document document, String xslPath) {
-    final ProcessingInstruction pi =
-        new ProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"" + xslPath + "\" ");
-    document.getContent().add(0, pi);
-  }
+  
 
   @Override
   public void write(final Writer writer) throws IOException {
diff --git a/src/main/java/caosdb/server/resource/LogoutResource.java b/src/main/java/caosdb/server/resource/LogoutResource.java
index 79489413..6c734d45 100644
--- a/src/main/java/caosdb/server/resource/LogoutResource.java
+++ b/src/main/java/caosdb/server/resource/LogoutResource.java
@@ -22,14 +22,14 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBException;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
 import org.restlet.representation.Representation;
+import caosdb.server.CaosDBException;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 
-public class LogoutResource extends AuthenticationResource {
+public class LogoutResource extends  XMLServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
diff --git a/src/main/java/caosdb/server/resource/PermissionRulesResource.java b/src/main/java/caosdb/server/resource/PermissionRulesResource.java
index 1610ba37..bcb6539a 100644
--- a/src/main/java/caosdb/server/resource/PermissionRulesResource.java
+++ b/src/main/java/caosdb/server/resource/PermissionRulesResource.java
@@ -22,14 +22,6 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBException;
-import caosdb.server.accessControl.ACMPermissions;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.entity.Message;
-import caosdb.server.permissions.PermissionRule;
-import caosdb.server.transaction.RetrievePermissionRulesTransaction;
-import caosdb.server.transaction.UpdatePermissionRulesTransaction;
-import caosdb.server.utils.ServerMessages;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
@@ -39,8 +31,16 @@ import org.jdom2.Element;
 import org.restlet.data.Status;
 import org.restlet.representation.Representation;
 import org.restlet.representation.StringRepresentation;
+import caosdb.server.CaosDBException;
+import caosdb.server.accessControl.ACMPermissions;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.entity.Message;
+import caosdb.server.permissions.PermissionRule;
+import caosdb.server.transaction.RetrievePermissionRulesTransaction;
+import caosdb.server.transaction.UpdatePermissionRulesTransaction;
+import caosdb.server.utils.ServerMessages;
 
-public class PermissionRulesResource extends AbstractCaosDBServerResource {
+public class PermissionRulesResource extends  XMLServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
diff --git a/src/main/java/caosdb/server/resource/RolesResource.java b/src/main/java/caosdb/server/resource/RolesResource.java
index ef9b30f5..fc7d092e 100644
--- a/src/main/java/caosdb/server/resource/RolesResource.java
+++ b/src/main/java/caosdb/server/resource/RolesResource.java
@@ -22,16 +22,6 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBException;
-import caosdb.server.accessControl.ACMPermissions;
-import caosdb.server.accessControl.Role;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.entity.Message;
-import caosdb.server.transaction.DeleteRoleTransaction;
-import caosdb.server.transaction.InsertRoleTransaction;
-import caosdb.server.transaction.RetrieveRoleTransaction;
-import caosdb.server.transaction.UpdateRoleTransaction;
-import caosdb.server.utils.ServerMessages;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
@@ -42,8 +32,18 @@ import org.restlet.data.Form;
 import org.restlet.data.Status;
 import org.restlet.representation.Representation;
 import org.restlet.representation.StringRepresentation;
+import caosdb.server.CaosDBException;
+import caosdb.server.accessControl.ACMPermissions;
+import caosdb.server.accessControl.Role;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.entity.Message;
+import caosdb.server.transaction.DeleteRoleTransaction;
+import caosdb.server.transaction.InsertRoleTransaction;
+import caosdb.server.transaction.RetrieveRoleTransaction;
+import caosdb.server.transaction.UpdateRoleTransaction;
+import caosdb.server.utils.ServerMessages;
 
-public class RolesResource extends AbstractCaosDBServerResource {
+public class RolesResource extends  XMLServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
diff --git a/src/main/java/caosdb/server/resource/ScriptingResource.java b/src/main/java/caosdb/server/resource/ScriptingResource.java
index b23a9593..45e13f2b 100644
--- a/src/main/java/caosdb/server/resource/ScriptingResource.java
+++ b/src/main/java/caosdb/server/resource/ScriptingResource.java
@@ -24,18 +24,6 @@
 
 package caosdb.server.resource;
 
-import caosdb.server.FileSystem;
-import caosdb.server.accessControl.Principal;
-import caosdb.server.accessControl.SessionToken;
-import caosdb.server.accessControl.UserSources;
-import caosdb.server.entity.FileProperties;
-import caosdb.server.entity.Message;
-import caosdb.server.scripting.CallerSerializer;
-import caosdb.server.scripting.ServerSideScriptingCaller;
-import caosdb.server.utils.Serializer;
-import caosdb.server.utils.ServerMessages;
-import caosdb.server.utils.Utils;
-import com.ibm.icu.text.Collator;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
@@ -57,8 +45,20 @@ import org.restlet.data.Status;
 import org.restlet.engine.header.ContentType;
 import org.restlet.ext.fileupload.RestletFileUpload;
 import org.restlet.representation.Representation;
+import com.ibm.icu.text.Collator;
+import caosdb.server.FileSystem;
+import caosdb.server.accessControl.Principal;
+import caosdb.server.accessControl.SessionToken;
+import caosdb.server.accessControl.UserSources;
+import caosdb.server.entity.FileProperties;
+import caosdb.server.entity.Message;
+import caosdb.server.scripting.CallerSerializer;
+import caosdb.server.scripting.ServerSideScriptingCaller;
+import caosdb.server.utils.Serializer;
+import caosdb.server.utils.ServerMessages;
+import caosdb.server.utils.Utils;
 
-public class ScriptingResource extends AbstractCaosDBServerResource {
+public class ScriptingResource extends  XMLServerResource {
 
   private ServerSideScriptingCaller caller;
   private Collection<FileProperties> deleteFiles = new LinkedList<>();
diff --git a/src/main/java/caosdb/server/resource/ServerLogsResource.java b/src/main/java/caosdb/server/resource/ServerLogsResource.java
index b63de6e0..b9e72b63 100644
--- a/src/main/java/caosdb/server/resource/ServerLogsResource.java
+++ b/src/main/java/caosdb/server/resource/ServerLogsResource.java
@@ -22,9 +22,6 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBException;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.transaction.RetrieveLogRecordTransaction;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
@@ -36,8 +33,11 @@ import org.restlet.data.Form;
 import org.restlet.data.MediaType;
 import org.restlet.representation.Representation;
 import org.restlet.representation.StringRepresentation;
+import caosdb.server.CaosDBException;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.transaction.RetrieveLogRecordTransaction;
 
-public class ServerLogsResource extends AbstractCaosDBServerResource {
+public class ServerLogsResource extends  XMLServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
diff --git a/src/main/java/caosdb/server/resource/ServerPropertiesResource.java b/src/main/java/caosdb/server/resource/ServerPropertiesResource.java
index 347919d9..d69a0668 100644
--- a/src/main/java/caosdb/server/resource/ServerPropertiesResource.java
+++ b/src/main/java/caosdb/server/resource/ServerPropertiesResource.java
@@ -1,14 +1,14 @@
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerPropertiesSerializer;
-import caosdb.server.accessControl.ACMPermissions;
 import org.restlet.data.Form;
 import org.restlet.data.Parameter;
 import org.restlet.data.Status;
 import org.restlet.representation.Representation;
+import caosdb.server.CaosDBServer;
+import caosdb.server.ServerPropertiesSerializer;
+import caosdb.server.accessControl.ACMPermissions;
 
-public class ServerPropertiesResource extends AbstractCaosDBServerResource {
+public class ServerPropertiesResource extends  XMLServerResource {
 
   @Override
   protected void doInit() {
diff --git a/src/main/java/caosdb/server/resource/SharedFileResource.java b/src/main/java/caosdb/server/resource/SharedFileResource.java
index ffdce05b..bded689b 100644
--- a/src/main/java/caosdb/server/resource/SharedFileResource.java
+++ b/src/main/java/caosdb/server/resource/SharedFileResource.java
@@ -25,11 +25,6 @@
 package caosdb.server.resource;
 
 import static java.net.URLDecoder.decode;
-
-import caosdb.server.FileSystem;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.utils.FileUtils;
-import caosdb.server.utils.ServerMessages;
 import java.io.File;
 import java.io.IOException;
 import org.jdom2.JDOMException;
@@ -38,13 +33,17 @@ import org.restlet.data.MediaType;
 import org.restlet.data.Status;
 import org.restlet.representation.FileRepresentation;
 import org.restlet.representation.Representation;
+import caosdb.server.FileSystem;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.utils.FileUtils;
+import caosdb.server.utils.ServerMessages;
 
 /**
  * Download temporary files via GET method only.
  *
  * @author Daniel Hornung
  */
-public class SharedFileResource extends AbstractCaosDBServerResource {
+public class SharedFileResource extends  XMLServerResource {
 
   /**
    * Download a File from the tempfiles folder. Only one File per Request.
diff --git a/src/main/java/caosdb/server/resource/ThumbnailsResource.java b/src/main/java/caosdb/server/resource/ThumbnailsResource.java
index e08378c5..cde3b9f0 100644
--- a/src/main/java/caosdb/server/resource/ThumbnailsResource.java
+++ b/src/main/java/caosdb/server/resource/ThumbnailsResource.java
@@ -23,9 +23,6 @@
 package caosdb.server.resource;
 
 import static caosdb.server.FileSystem.getFromFileSystem;
-
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.utils.ServerMessages;
 import java.io.File;
 import java.io.IOException;
 import org.jdom2.JDOMException;
@@ -34,8 +31,10 @@ import org.restlet.data.MediaType;
 import org.restlet.data.Status;
 import org.restlet.representation.FileRepresentation;
 import org.restlet.representation.Representation;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.utils.ServerMessages;
 
-public class ThumbnailsResource extends AbstractCaosDBServerResource {
+public class ThumbnailsResource extends  XMLServerResource {
 
   /**
    * Download a File from the CaosDBFileSystem. Only one File per Request.
diff --git a/src/main/java/caosdb/server/resource/UserResource.java b/src/main/java/caosdb/server/resource/UserResource.java
index b77ff8a4..f84ff0c3 100644
--- a/src/main/java/caosdb/server/resource/UserResource.java
+++ b/src/main/java/caosdb/server/resource/UserResource.java
@@ -22,6 +22,15 @@
  */
 package caosdb.server.resource;
 
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.sql.SQLException;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.restlet.data.Form;
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
 import caosdb.server.CaosDBException;
 import caosdb.server.CaosDBServer;
 import caosdb.server.ServerProperties;
@@ -35,22 +44,13 @@ import caosdb.server.transaction.InsertUserTransaction;
 import caosdb.server.transaction.RetrieveUserTransaction;
 import caosdb.server.transaction.UpdateUserTransaction;
 import caosdb.server.utils.ServerMessages;
-import java.io.IOException;
-import java.security.NoSuchAlgorithmException;
-import java.sql.SQLException;
-import org.jdom2.Document;
-import org.jdom2.Element;
-import org.jdom2.JDOMException;
-import org.restlet.data.Form;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
 
 /**
  * This class handles requests for Users.
  *
  * @author Timm Fitschen
  */
-public class UserResource extends AbstractCaosDBServerResource {
+public class UserResource extends  XMLServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
diff --git a/src/main/java/caosdb/server/resource/UserRolesResource.java b/src/main/java/caosdb/server/resource/UserRolesResource.java
index 27e14715..0b129062 100644
--- a/src/main/java/caosdb/server/resource/UserRolesResource.java
+++ b/src/main/java/caosdb/server/resource/UserRolesResource.java
@@ -22,14 +22,6 @@
  */
 package caosdb.server.resource;
 
-import caosdb.server.CaosDBException;
-import caosdb.server.accessControl.ACMPermissions;
-import caosdb.server.accessControl.UserSources;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.entity.Message;
-import caosdb.server.transaction.RetrieveUserRolesTransaction;
-import caosdb.server.transaction.UpdateUserRolesTransaction;
-import caosdb.server.utils.ServerMessages;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
@@ -40,8 +32,16 @@ import org.jdom2.Element;
 import org.jdom2.JDOMException;
 import org.restlet.data.Status;
 import org.restlet.representation.Representation;
+import caosdb.server.CaosDBException;
+import caosdb.server.accessControl.ACMPermissions;
+import caosdb.server.accessControl.UserSources;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.entity.Message;
+import caosdb.server.transaction.RetrieveUserRolesTransaction;
+import caosdb.server.transaction.UpdateUserRolesTransaction;
+import caosdb.server.utils.ServerMessages;
 
-public class UserRolesResource extends AbstractCaosDBServerResource {
+public class UserRolesResource extends XMLServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
diff --git a/src/main/java/caosdb/server/resource/XMLServerResource.java b/src/main/java/caosdb/server/resource/XMLServerResource.java
new file mode 100644
index 00000000..b0668268
--- /dev/null
+++ b/src/main/java/caosdb/server/resource/XMLServerResource.java
@@ -0,0 +1,475 @@
+/*
+ * ** 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
+ *
+ * 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.resource;
+
+import static caosdb.server.utils.Utils.isNonNullInteger;
+import static java.net.URLDecoder.decode;
+import java.io.IOException;
+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.logging.Level;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.subject.Subject;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.restlet.data.Form;
+import org.restlet.data.Header;
+import org.restlet.data.Parameter;
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Delete;
+import org.restlet.resource.Get;
+import org.restlet.resource.Post;
+import org.restlet.resource.Put;
+import org.restlet.util.Series;
+import caosdb.server.CaosDBException;
+import caosdb.server.accessControl.AuthenticationUtils;
+import caosdb.server.accessControl.Principal;
+import caosdb.server.accessControl.UserSources;
+import caosdb.server.converter.xml.XMLParser;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.entity.Message;
+import caosdb.server.utils.ServerMessages;
+import caosdb.server.utils.WebinterfaceUtils;
+
+/**
+ * Class is still under construction.
+ *
+ * @author Timm Fitschen
+ */
+public abstract class XMLServerResource extends AbstractCaosDBServerResource {
+
+  private final HashMap<String, String> flags = new HashMap<String, String>();
+  private Long timestamp = null;
+  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 WebinterfaceUtils utils;
+
+  /** Return the {@link WebinterfaceUtils} instance for this resource. */
+  @Override
+  public WebinterfaceUtils getUtils() {
+    return this.utils;
+  }
+
+  public static class xmlNotWellFormedException extends Exception {
+    private static final long serialVersionUID = -6836378704013776849L;
+  }
+
+  /**
+   * Returns the (probably unique) server request ID.
+   *
+   * @return The server request ID.
+   */
+  @Override
+  public String getSRID() {
+    return this.sRID;
+  }
+
+  @Override
+  public Long getTimestamp() {
+    return this.timestamp;
+  }
+
+  @Override
+  public Subject getUser() {
+    Subject ret = SecurityUtils.getSubject();
+    return ret;
+  }
+
+  /**
+   * Setup method, called by {@link org.restlet.resource.Resource#init(org.restlet.Context,
+   * org.restlet.Request, org.restlet.Response)}.
+   */
+  @Override
+  protected void doInit() {
+    if (getRequestEntity().isTransient() && !getRequestEntity().isEmpty()) {
+      final ReReadableRepresentation r = new ReReadableRepresentation(getRequestEntity());
+      getRequest().setEntity(r);
+    }
+
+    this.utils = WebinterfaceUtils.getInstance(getHostRef());
+
+    this.timestamp = getRequest().getDate().getTime();
+
+    this.sRID = getRequest().getAttributes().get("SRID").toString();
+
+    final Series<Header> headers = getRequest().getHeaders();
+
+    this.setCRID(headers.getFirstValue("crequestid"));
+
+    String specifier = (String) getRequestAttributes().get("specifier");
+    if (specifier != null && !specifier.equals("")) {
+      try {
+        specifier = decode(specifier, "UTF-8");
+      } catch (final UnsupportedEncodingException e) {
+        // this should never happen
+        e.printStackTrace();
+        System.exit(1);
+      }
+
+      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
+    final Form queryAsForm = getRequest().getResourceRef().getQueryAsForm(true);
+    if (queryAsForm != null) {
+      for (final Parameter p : queryAsForm) {
+        getFlags()
+            .put(
+                p.getName(),
+                (p.getValue() == null || p.getValue().isEmpty() ? null : p.getValue()));
+      }
+    }
+  }
+
+  @Override
+  protected void doRelease() {}
+
+  /**
+   * Creates the XML root.
+   *
+   * <p>The XML root node contains:
+   *
+   * <p>
+   *
+   * <ul>
+   *   <li>User info as per addUserInfo
+   *   <li>The sRID (server-side request ID)
+   *   <li>A timestamp
+   *   <li>The URI to this resource.
+   */
+  protected Element generateRootElement() {
+    final Element retRoot = new Element("Response");
+
+    addUserInfo(retRoot, getUser());
+    retRoot.setAttribute("srid", getSRID());
+    if (this.getCRID() != null) {
+      retRoot.setAttribute("crid", this.getCRID());
+    }
+    retRoot.setAttribute("timestamp", getTimestamp().toString());
+    retRoot.setAttribute("baseuri", getRootRef().toString());
+    return retRoot;
+  }
+
+  /**
+   * Add the user info to the Response Element.
+   *
+   * @param retRoot
+   * @param user
+   */
+  private void addUserInfo(Element retRoot, Subject user) {
+
+    if (user != null && user.isAuthenticated()) {
+      Element userInfo = new Element("UserInfo");
+      if (!user.getPrincipal().equals(AuthenticationUtils.ANONYMOUS_USER.getPrincipal())) {
+        // TODO: deprecated
+        addNameAndRealm(retRoot, user);
+
+        // this is the new, correct way
+        addNameAndRealm(userInfo, user);
+      }
+
+      addRoles(userInfo, user);
+      retRoot.addContent(userInfo);
+    }
+  }
+
+  /**
+   * Add all roles of the current user to the user info, like this:
+   * `<UserInfo><Roles><Role>role1</Role><Role>role2</Role>...</Roles></UserInfo>`
+   *
+   * @param userInfo
+   * @param user
+   */
+  private void addRoles(Element userInfo, Subject user) {
+    Collection<String> roles = UserSources.resolve(user.getPrincipals());
+    if (roles == null) return;
+    Element rs = new Element("Roles");
+    for (String role : roles) {
+      Element r = new Element("Role");
+      r.addContent(role);
+      rs.addContent(r);
+    }
+    userInfo.addContent(rs);
+  }
+
+  /**
+   * Add the username and the realm of the current user to the user info (as attributes).
+   *
+   * @param userInfo
+   */
+  private void addNameAndRealm(Element userInfo, Subject user) {
+    userInfo.setAttribute("username", ((Principal) user.getPrincipal()).getUsername());
+    userInfo.setAttribute("realm", ((Principal) user.getPrincipal()).getRealm());
+  }
+
+  @Get
+  public Representation httpGet() {
+    try {
+      return httpGetInChildClass();
+    } catch (final Throwable t) {
+      return handleThrowable(t);
+    }
+  }
+
+  protected abstract Representation httpGetInChildClass()
+      throws ConnectionException, IOException, SQLException, CaosDBException,
+          NoSuchAlgorithmException, Exception;
+
+  @Post
+  public Representation httpPost(final Representation entity) {
+    try {
+      return httpPostInChildClass(entity);
+    } catch (final Throwable t) {
+      return handleThrowable(t);
+    }
+  }
+
+  @Put
+  public Representation httpPut(final Representation entity) {
+    try {
+      // catch empty post entity.
+      if (entity == null) {
+        return error(ServerMessages.REQUEST_BODY_EMPTY, Status.CLIENT_ERROR_BAD_REQUEST);
+      } else {
+        return httpPutInChildClass(entity);
+      }
+    } catch (final Throwable t) {
+      return handleThrowable(t);
+    }
+  }
+
+  protected Representation httpPutInChildClass(final Representation entity)
+      throws ConnectionException, JDOMException, Exception, xmlNotWellFormedException {
+    getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
+    return null;
+  }
+
+  protected Representation httpDeleteInChildClass()
+      throws ConnectionException, SQLException, CaosDBException, IOException,
+          NoSuchAlgorithmException, Exception {
+    getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
+    return null;
+  }
+
+  @Delete
+  public Representation httpDelete() {
+    try {
+      return httpDeleteInChildClass();
+    } catch (final Throwable t) {
+      return handleThrowable(t);
+    }
+  }
+
+  protected Representation httpPostInChildClass(final Representation entity)
+      throws ConnectionException, SQLException, CaosDBException, IOException,
+          NoSuchAlgorithmException, xmlNotWellFormedException, JDOMException, Exception {
+    getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
+    return null;
+  }
+
+  public Document parseEntity(final Representation entity)
+      throws xmlNotWellFormedException, IOException {
+    return parseEntity(entity.getStream());
+  }
+
+  public Document parseEntity(final InputStream stream)
+      throws xmlNotWellFormedException, IOException {
+    try {
+      return xmlparser.parse(stream);
+    } catch (final JDOMException e) {
+      throw new xmlNotWellFormedException();
+    }
+  }
+
+  @Override
+  protected String getXSLScript() {
+    return this.utils.getWebinterfaceURI("webcaosdb.xsl");
+  }
+
+  /** Wrap an element for an "OK" response. */
+  protected JdomRepresentation ok(Element root) {
+    return ok(new Document(root));
+  }
+
+  /**
+   * Return a JDomRepresentation of the document and leave the {@link Response}'s {@link Status}
+   * where it is - which is usually 200 - OK when this method happens to be called.
+   */
+  protected JdomRepresentation ok(final Document doc) {
+    return new JdomRepresentation(doc, "  ");
+  }
+
+  /**
+   * Return a Representation containing the error message and set the {@link Response}'s {@link
+   * Status}.
+   *
+   * @param m - the error message.
+   * @param status - the response status
+   * @return A Representation of the error.
+   */
+  protected Representation error(final Message m, final Status status) {
+    final Document doc = new Document();
+    final Element root = generateRootElement();
+    root.addContent(m.toElement().setName("Error"));
+    doc.setRootElement(root);
+    return error(new JdomRepresentation(doc, "  "), status);
+  }
+
+  protected Representation error(Representation entity, Status status) {
+    getResponse().setStatus(status);
+    return entity;
+  }
+
+  protected Representation error(final Message m) {
+    return error(m, Status.SERVER_ERROR_INTERNAL);
+  }
+
+  protected Representation error(final Status status) {
+    return error((Representation) null, status);
+  }
+
+  /**
+   * Return a Representation containing the warning message but leave the {@link Response}'s {@link
+   * Status} where it is - which is usually 200 - OK when this method happens to be called.
+   *
+   * @param m - the warning message.
+   * @return A Representation of the warning.
+   */
+  protected JdomRepresentation warning(final Message m) {
+    final Document doc = new Document();
+    final Element root = generateRootElement();
+    root.addContent(m.toElement().setName("Warning"));
+    doc.setRootElement(root);
+    return new JdomRepresentation(doc, "  ");
+  }
+
+  protected Representation noWellFormedNess() {
+    return error(ServerMessages.REQUEST_BODY_NOT_WELLFORMED);
+  }
+
+  protected Representation emptyEntity() {
+    return error(ServerMessages.REQUEST_BODY_EMPTY);
+  }
+
+  protected Representation connectionFailed() {
+    return error(ServerMessages.CANNOT_CONNECT_TO_DATABASE);
+  }
+
+  public Representation handleThrowable(final Throwable t) {
+    try {
+      getRequest().getAttributes().put("THROWN", t);
+      throw t;
+    } catch (final AuthenticationException e) {
+      getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+      return null;
+    } catch (final AuthorizationException e) {
+      getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+      return null;
+    } catch (final Message m) {
+      return error(m, Status.CLIENT_ERROR_BAD_REQUEST);
+    } catch (final FileUploadException e) {
+      return error(ServerMessages.FILE_UPLOAD_FAILED);
+    } catch (final ConnectionException e) {
+      return connectionFailed();
+    } catch (final xmlNotWellFormedException e) {
+      return noWellFormedNess();
+    } catch (final JDOMException e) {
+      return noWellFormedNess();
+    } catch (final Throwable e) {
+      getLogger().log(Level.SEVERE, "UNKNOWN ERROR", e);
+      return error(ServerMessages.UNKNOWN_ERROR(getSRID()));
+    }
+  }
+
+  @Override
+  public ArrayList<Integer> getRequestedIDs() {
+    return this.requestedIDs;
+  }
+
+  @Override
+  public ArrayList<String> getRequestedNames() {
+    return this.requestedNames;
+  }
+
+  @Override
+  public void setRequestedNames(final ArrayList<String> requestedNames) {
+    this.requestedNames = requestedNames;
+  }
+
+  @Override
+  public HashMap<String, String> getFlags() {
+    return this.flags;
+  }
+
+  protected Element generateRootElement(Element... elements) {
+    Element root = generateRootElement();
+    for (Element e : elements) {
+      root.addContent(e);
+    }
+    return root;
+  }
+
+  /**
+   * Returns the client request ID, which can be set by the client.
+   *
+   * @return The cRID.
+   */
+  public String getCRID() {
+    return cRID;
+  }
+
+  public void setCRID(String cRID) {
+    this.cRID = cRID;
+  }
+
+}
diff --git a/src/main/java/caosdb/server/resource/transaction/EntityResource.java b/src/main/java/caosdb/server/resource/transaction/EntityResource.java
index 0c853096..367450fa 100644
--- a/src/main/java/caosdb/server/resource/transaction/EntityResource.java
+++ b/src/main/java/caosdb/server/resource/transaction/EntityResource.java
@@ -22,11 +22,21 @@
  */
 package caosdb.server.resource.transaction;
 
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.sql.SQLException;
+import org.jdom2.JDOMException;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.resource.Get;
+import org.restlet.resource.Post;
+import org.restlet.resource.Put;
 import caosdb.server.CaosDBException;
 import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 import caosdb.server.entity.container.DeleteContainer;
 import caosdb.server.entity.container.InsertContainer;
 import caosdb.server.entity.container.RetrieveContainer;
+import caosdb.server.entity.container.TransactionContainer;
 import caosdb.server.entity.container.UpdateContainer;
 import caosdb.server.resource.AbstractCaosDBServerResource;
 import caosdb.server.resource.transaction.handlers.FileUploadHandler;
@@ -38,15 +48,6 @@ import caosdb.server.transaction.Delete;
 import caosdb.server.transaction.Insert;
 import caosdb.server.transaction.Retrieve;
 import caosdb.server.transaction.Update;
-import java.io.IOException;
-import java.security.NoSuchAlgorithmException;
-import java.sql.SQLException;
-import org.jdom2.Document;
-import org.jdom2.Element;
-import org.jdom2.JDOMException;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
 
 public class EntityResource extends AbstractCaosDBServerResource {
 
@@ -93,8 +94,8 @@ public class EntityResource extends AbstractCaosDBServerResource {
     }
   }
 
-  @Override
-  protected final Representation httpGetInChildClass()
+  @Get
+  protected final TransactionContainer httpGetInChildClass()
       throws ConnectionException, IOException, SQLException, CaosDBException,
           NoSuchAlgorithmException, Exception {
 
@@ -105,7 +106,6 @@ public class EntityResource extends AbstractCaosDBServerResource {
     }
     final RetrieveContainer entityContainer =
         new RetrieveContainer(getUser(), getTimestamp(), getSRID(), getFlags());
-    final Document doc = new Document();
 
     getGetRequestHandler().handle(this, entityContainer);
 
@@ -116,14 +116,11 @@ public class EntityResource extends AbstractCaosDBServerResource {
     entityContainer
         .getTransactionBenchmark()
         .addMeasurement(getClass().getSimpleName() + ".httpGetInChildClass", t2 - t1);
-    final Element rootElem = generateRootElement();
-    entityContainer.addToElement(rootElem);
-    doc.setRootElement(rootElem);
-    return ok(doc);
+    return entityContainer;
   }
 
-  @Override
-  protected final Representation httpDeleteInChildClass() throws Exception {
+  @org.restlet.resource.Delete
+  protected final TransactionContainer httpDeleteInChildClass() throws Exception {
 
     if (!this.delete) {
       getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
@@ -131,23 +128,18 @@ public class EntityResource extends AbstractCaosDBServerResource {
     }
     final DeleteContainer entityContainer =
         new DeleteContainer(getUser(), getTimestamp(), getSRID(), getFlags());
-    final Document doc = new Document();
 
     getDeleteRequestHandler().handle(this, entityContainer);
 
     final Delete delete = new Delete(entityContainer);
     delete.execute();
 
-    final Element rootElem = generateRootElement();
-    entityContainer.addToElement(rootElem);
-    doc.setRootElement(rootElem);
-
-    return ok(doc);
+    return entityContainer;
   }
 
-  @Override
-  protected final Representation httpPostInChildClass(final Representation entity)
-      throws xmlNotWellFormedException, Exception {
+  @Post
+  protected final TransactionContainer httpPostInChildClass(final TransactionContainer entities)
+      throws Exception {
 
     if (!this.post) {
       getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
@@ -156,23 +148,18 @@ public class EntityResource extends AbstractCaosDBServerResource {
 
     final InsertContainer entityContainer =
         new InsertContainer(getUser(), getTimestamp(), getSRID(), getFlags());
-    final Document doc = new Document();
 
     getPostRequestHandler().handle(this, entityContainer);
 
     final Insert insert = new Insert(entityContainer);
     insert.execute();
 
-    final Element rootElem = generateRootElement();
-    entityContainer.addToElement(rootElem);
-    doc.setRootElement(rootElem);
-
-    return ok(doc);
+    return entityContainer;
   }
 
-  @Override
-  protected final Representation httpPutInChildClass(final Representation entity)
-      throws ConnectionException, JDOMException, Exception, xmlNotWellFormedException {
+  @Put
+  protected final TransactionContainer httpPutInChildClass(final TransactionContainer entities)
+      throws ConnectionException, JDOMException, Exception {
 
     if (!this.put) {
       getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
@@ -181,17 +168,12 @@ public class EntityResource extends AbstractCaosDBServerResource {
 
     final UpdateContainer entityContainer =
         new UpdateContainer(getUser(), getTimestamp(), getSRID(), getFlags());
-    final Document doc = new Document();
 
     getPutRequestHandler().handle(this, entityContainer);
 
     final Update update = new Update(entityContainer);
     update.execute();
 
-    final Element rootElem = generateRootElement();
-    entityContainer.addToElement(rootElem);
-    doc.setRootElement(rootElem);
-
-    return ok(doc);
+    return entityContainer;
   }
 }
diff --git a/src/main/java/caosdb/server/resource/transaction/handlers/SimpleWriteHandler.java b/src/main/java/caosdb/server/resource/transaction/handlers/SimpleWriteHandler.java
index 71afcc91..66afef75 100644
--- a/src/main/java/caosdb/server/resource/transaction/handlers/SimpleWriteHandler.java
+++ b/src/main/java/caosdb/server/resource/transaction/handlers/SimpleWriteHandler.java
@@ -22,10 +22,10 @@
  */
 package caosdb.server.resource.transaction.handlers;
 
-import caosdb.server.entity.container.WritableContainer;
-import caosdb.server.resource.transaction.EntityResource;
 import java.util.List;
 import org.jdom2.Element;
+import caosdb.server.entity.container.WritableContainer;
+import caosdb.server.resource.transaction.EntityResource;
 
 public class SimpleWriteHandler<T extends WritableContainer> extends RequestHandler<T> {
 
diff --git a/src/test/java/caosdb/server/permissions/EntityACLTest.java b/src/test/java/caosdb/server/permissions/EntityACLTest.java
index 13ebb627..53b15fe8 100644
--- a/src/test/java/caosdb/server/permissions/EntityACLTest.java
+++ b/src/test/java/caosdb/server/permissions/EntityACLTest.java
@@ -23,11 +23,6 @@
 package caosdb.server.permissions;
 
 import static org.junit.Assert.assertNotNull;
-
-import caosdb.server.CaosDBServer;
-import caosdb.server.resource.AbstractCaosDBServerResource;
-import caosdb.server.resource.AbstractCaosDBServerResource.XMLParser;
-import caosdb.server.utils.Utils;
 import java.io.IOException;
 import java.util.BitSet;
 import java.util.LinkedList;
@@ -36,6 +31,9 @@ import org.jdom2.JDOMException;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import caosdb.server.CaosDBServer;
+import caosdb.server.converter.xml.XMLParser;
+import caosdb.server.utils.Utils;
 
 public class EntityACLTest {
 
@@ -206,7 +204,7 @@ public class EntityACLTest {
     return false;
   }
 
-  public static AbstractCaosDBServerResource.XMLParser parser = new XMLParser();
+  public static XMLParser parser = new XMLParser();
 
   public Element stringToJdom(final String s) throws JDOMException, IOException {
     return parser.parse(Utils.String2InputStream(s)).getRootElement();
diff --git a/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java b/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java
index 81baabd4..1ae724bb 100644
--- a/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java
+++ b/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java
@@ -2,13 +2,6 @@ package caosdb.server.resource;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-
-import caosdb.server.CaosDBException;
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
-import caosdb.server.accessControl.AnonymousAuthenticationToken;
-import caosdb.server.accessControl.AnonymousRealm;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -24,6 +17,12 @@ import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.restlet.data.Reference;
 import org.restlet.representation.Representation;
+import caosdb.server.CaosDBException;
+import caosdb.server.CaosDBServer;
+import caosdb.server.ServerProperties;
+import caosdb.server.accessControl.AnonymousAuthenticationToken;
+import caosdb.server.accessControl.AnonymousRealm;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 
 public class TestAbstractCaosDBServerResource {
 
@@ -38,8 +37,8 @@ public class TestAbstractCaosDBServerResource {
   public void testReponseRootElement() throws IOException {
     final Subject user = new DelegatingSubject(new DefaultSecurityManager(new AnonymousRealm()));
     user.login(AnonymousAuthenticationToken.getInstance());
-    AbstractCaosDBServerResource s =
-        new AbstractCaosDBServerResource() {
+    XMLServerResource s =
+        new  XMLServerResource() {
 
           @Override
           protected Representation httpGetInChildClass()
-- 
GitLab