Skip to content
Snippets Groups Projects
Select Git revision
  • fd7f40f77d95e760b944cf0e7b23d8bd99da8025
  • main default protected
  • f-structured-query-tree
  • f-remove-chown-check
  • f-better-sss-bin-dir
  • dev protected
  • f-remove-dropoffbox
  • f-sss4grpc
  • f-refactor-compose
  • f-real-id
  • f-doip
  • f-filesystem-import
  • henrik-tmp
  • f-filesystem-link
  • f-filesystem-directory
  • f-filesystem-core
  • f-filesystem-cleanup
  • f-string-ids
  • f-filesystem-main
  • f-linkahead-rename-before
  • f-linkahead-rename
  • v0.13.0 protected
  • v0.12.3 protected
  • v0.12.2 protected
  • v0.12.1 protected
  • v0.12.0 protected
  • v0.11.0 protected
  • v0.10.0 protected
  • v0.9.0 protected
  • v0.8.1 protected
  • v0.8.0 protected
  • v0.7.3 protected
  • v0.7.2 protected
  • v0.7.1 protected
  • v0.6.0 protected
  • v0.5.0 protected
  • v0.4.0 protected
  • v0.3.0 protected
  • working_sss protected
  • v0.1 protected
40 results

AbstractCaosDBServerResource.java

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    AbstractCaosDBServerResource.java 12.39 KiB
    /*
     * ** 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.resource;
    
    import static caosdb.server.utils.Utils.isNonNullInteger;
    import static java.net.URLDecoder.decode;
    
    import caosdb.server.CaosDBException;
    import caosdb.server.accessControl.Principal;
    import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
    import caosdb.server.entity.Message;
    import caosdb.server.utils.ServerMessages;
    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.HashMap;
    import java.util.LinkedList;
    import java.util.NoSuchElementException;
    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.jdom2.input.SAXBuilder;
    import org.restlet.data.Form;
    import org.restlet.data.Header;
    import org.restlet.data.MediaType;
    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;
    
    /**
     * Class is still under construction.
     *
     * @author Timm Fitschen
     */
    public abstract class AbstractCaosDBServerResource extends ServerResource {
    
      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;
      protected String cRID = null;
      private String[] requestedItems = null;
      private ArrayList<Integer> requestedIDs = new ArrayList<Integer>();
      private ArrayList<String> requestedNames = new ArrayList<String>();
      private String xslScript = "webcaosdb.xsl";
    
      public static class xmlNotWellFormedException extends Exception {
        private static final long serialVersionUID = -6836378704013776849L;
      }
    
      public String getSRID() {
        return this.sRID;
      }
    
      public Long getTimestamp() {
        return this.timestamp;
      }
    
      public Subject getUser() {
        return SecurityUtils.getSubject();
      }
    
      @Override
      protected void doInit() {
        if (getRequestEntity().isTransient() && !getRequestEntity().isEmpty()) {
          final ReReadableRepresentation r = new ReReadableRepresentation(getRequestEntity());
          getRequest().setEntity(r);
        }
    
        this.timestamp = getRequest().getDate().getTime();
    
        this.sRID = getRequest().getAttributes().get("SRID").toString();
    
        final Series<Header> headers = getRequest().getHeaders();
    
        this.cRID = 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() {}
    
      protected Element generateRootElement() {
        final Element retRoot = new Element("Response");
    
        if (getUser() != null && getUser().isAuthenticated()) {
          retRoot.setAttribute("username", ((Principal) getUser().getPrincipal()).getUsername());
          retRoot.setAttribute("realm", ((Principal) getUser().getPrincipal()).getRealm());
        }
        retRoot.setAttribute("srid", getSRID());
        if (this.cRID != null) {
          retRoot.setAttribute("crid", this.cRID);
        }
        retRoot.setAttribute("timestamp", getTimestamp().toString());
        retRoot.setAttribute("baseuri", getRootRef().toString());
        return retRoot;
      }
    
      @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.xslScript;
      }
    
      protected void setXSLScript(final String s) {
        this.xslScript = s;
      }
    
      protected JdomRepresentation ok(Element root) {
        return ok(new Document(root));
      }
    
      protected JdomRepresentation ok(final Document doc) {
        return new JdomRepresentation(doc, MediaType.TEXT_XML, "  ", getReference(), getXSLScript());
      }
    
      protected JdomRepresentation 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);
        getResponse().setStatus(status);
        return new JdomRepresentation(doc, MediaType.TEXT_XML, "  ", getReference(), getXSLScript());
      }
    
      protected JdomRepresentation error(final Message m) {
        return error(m, Status.SERVER_ERROR_INTERNAL);
      }
    
      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, MediaType.TEXT_XML, "  ", getReference(), getXSLScript());
      }
    
      protected JdomRepresentation noWellFormedNess() {
        return error(ServerMessages.REQUEST_BODY_NOT_WELLFORMED);
      }
    
      protected JdomRepresentation emptyEntity() {
        return error(ServerMessages.REQUEST_BODY_EMPTY);
      }
    
      protected JdomRepresentation connectionFailed() {
        return error(ServerMessages.CANNOT_CONNECT_TO_DATABASE);
      }
    
      public JdomRepresentation 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()));
        }
      }
    
      public ArrayList<Integer> getRequestedIDs() {
        return this.requestedIDs;
      }
    
      public void setReqestedIDs(final ArrayList<Integer> requestedIDs) {
        this.requestedIDs = requestedIDs;
      }
    
      public ArrayList<String> getRequestedNames() {
        return this.requestedNames;
      }
    
      public void setRequestedNames(final ArrayList<String> requestedNames) {
        this.requestedNames = requestedNames;
      }
    
      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;
      }
    
      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();
        }
      }
    }