uk.ac.ebi.arrayexpress.servlets.GenomeSpaceUploadServlet.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.ebi.arrayexpress.servlets.GenomeSpaceUploadServlet.java

Source

package uk.ac.ebi.arrayexpress.servlets;

/*
 * Copyright 2009-2014 European Molecular Biology Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.lang.text.StrSubstitutor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.ebi.arrayexpress.app.ApplicationServlet;
import uk.ac.ebi.arrayexpress.components.Files;
import uk.ac.ebi.arrayexpress.utils.StringTools;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GenomeSpaceUploadServlet extends ApplicationServlet {
    private static final long serialVersionUID = 4447436099042802322L;

    private transient final Logger logger = LoggerFactory.getLogger(getClass());

    private final static String GS_DM_ROOT_URL = "https://dm.genomespace.org/datamanager/v1.0";
    private final static String GS_HOME_DIRECTORY = "/personaldirectory";
    private final static String GS_ROOT_DIRECTORY = "/file";

    private final static String JSON_MIME_TYPE = "application/json";

    private HttpClient httpClient;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
        String proxyHost = System.getProperty("http.proxyHost");
        String proxyPort = System.getProperty("http.proxyPort");
        logger.info("Checking system properties for proxy configuration: [{}:{}]", proxyHost, proxyPort);
        if (null != proxyHost && null != proxyPort) {
            httpClient.getHostConfiguration().setProxy(proxyHost, Integer.parseInt(proxyPort));
        }
    }

    @Override
    protected boolean canAcceptRequest(HttpServletRequest request, RequestType requestType) {
        return (requestType == RequestType.GET || requestType == RequestType.POST);
    }

    @Override
    protected void doRequest(HttpServletRequest request, HttpServletResponse response, RequestType requestType)
            throws ServletException, IOException {
        logRequest(logger, request, requestType);

        String action = request.getParameter("action");

        if ("uploadFile".equals(action)) {
            doUploadFileAction(request, response);
        } else if ("checkDirectory".equals(action)) {
            doCheckCreateDirectoryAction(request, response, false);
        } else if ("createDirectory".equals(action)) {
            doCheckCreateDirectoryAction(request, response, true);
        } else {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                    "Action [" + (null != action ? action : "<null>") + "] is not supported");
        }
    }

    private void doCheckCreateDirectoryAction(HttpServletRequest request, HttpServletResponse response,
            boolean shouldCreate) throws IOException {
        String accession = request.getParameter("accession");
        String gsToken = request.getParameter("token");

        if (null == accession || null == gsToken) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                    "Expected parameters [accession] and [token] not found in the request");
        } else {
            DirectoryInfo dir = new DirectoryInfo();
            Integer statusCode = getDirectoryInfo("/", dir, gsToken);
            if (HttpServletResponse.SC_OK != statusCode) {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return;
            }

            String homePath = dir.getPath();
            logger.debug("Located GenomeSpace user home directory path: [{}]", homePath);

            if (null == homePath) {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return;
            }

            if (shouldCreate) {
                statusCode = getDirectoryInfo(homePath + "/ArrayExpress", dir, gsToken);
                if (HttpServletResponse.SC_NOT_FOUND == statusCode) {
                    // let's attempt to create subdirectory "ArrayExpress"
                    statusCode = createDirectory(homePath + "/ArrayExpress", dir, gsToken);
                    if (HttpServletResponse.SC_OK != statusCode) {
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        return;
                    }

                } else if (HttpServletResponse.SC_OK != statusCode) {
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    return;
                }

                String aePath = dir.getPath();
                logger.debug("Located GenomeSpace AE directory path: [{}]", aePath);
                if (null == aePath) {
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    return;
                }
            }
            String opStatus = "exists";
            statusCode = getDirectoryInfo(homePath + "/ArrayExpress/" + accession, dir, gsToken);
            if (HttpServletResponse.SC_NOT_FOUND == statusCode) {
                if (shouldCreate) {
                    // let's attempt to create subdirectory "ArrayExpress"
                    statusCode = createDirectory(homePath + "/ArrayExpress/" + accession, dir, gsToken);
                    if (HttpServletResponse.SC_OK != statusCode) {
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        return;
                    }
                    opStatus = "created";
                } else {
                    opStatus = "missing";
                }
            } else if (HttpServletResponse.SC_OK != statusCode) {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return;
            }

            String accessionPath = dir.getPath();
            logger.debug("Located GenomeSpace target directory path for [{}]: [{}]", accession, accessionPath);

            response.setContentType(JSON_MIME_TYPE);
            try (PrintWriter out = response.getWriter()) {
                out.print("{\"target\":\"" + accessionPath + "\",\"status\":\"" + opStatus + "\"}");
            }
        }
    }

    private void doUploadFileAction(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Files files = (Files) getComponent("Files");

        String fileName = request.getParameter("filename");
        String accession = request.getParameter("accession");
        String targetLocation = request.getParameter("target");
        String gsToken = request.getParameter("token");

        if (null == fileName || null == accession || null == gsToken || null == targetLocation) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                    "Expected parameters [filename], [accession], [target], [token] not found in the request");
        } else {
            String fileLocation = files.getLocation(accession, null, fileName);
            File file = null != fileLocation ? new File(files.getRootFolder(), fileLocation) : null;

            if (null == file || !file.exists()) {
                logger.error("Requested file upload of [{}/{}] which is not found", accession, fileName);
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
            } else {
                UploadFileInfo fileInfo = new UploadFileInfo(file);
                Integer statusCode = getFileUploadURL(fileInfo, targetLocation, gsToken);
                if (HttpServletResponse.SC_OK != statusCode) {
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    return;
                }

                statusCode = putFile(fileInfo);
                if (HttpServletResponse.SC_OK != statusCode) {
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    return;
                }
                response.setContentType(JSON_MIME_TYPE);
                try (PrintWriter out = response.getWriter()) {
                    out.print("{\"status\":\"copied\"}");
                }
                logger.info("Successfully sent [{}] to [GenomeSpace:{}]", fileLocation, targetLocation);
            }
        }
    }

    private Integer getDirectoryInfo(String path, DirectoryInfo directoryInfo, String gsToken) throws IOException {
        GetMethod get = new GetMethod(
                GS_DM_ROOT_URL + ("/".equals(path) ? GS_HOME_DIRECTORY : GS_ROOT_DIRECTORY + path));
        get.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        get.setRequestHeader("Cookie", "gs-token=" + gsToken);
        get.setRequestHeader("Accept", "application/json");
        get.setRequestHeader("Content-Type", "application/json");

        JSONParser jsonParser = new JSONParser();
        Integer statusCode = null;
        try {
            statusCode = httpClient.executeMethod(get);
            if (HttpServletResponse.SC_OK == statusCode) {
                try (InputStream is = get.getResponseBodyAsStream()) {
                    JSONObject dirInfo = (JSONObject) jsonParser
                            .parse(new BufferedReader(new InputStreamReader(is)));
                    directoryInfo.setInfo((null != dirInfo && dirInfo.containsKey("directory"))
                            ? (JSONObject) dirInfo.get("directory")
                            : null);
                } catch (ParseException x) {
                    logger.error("Unable to parse JSON response:", x);
                }
            } else {
                logger.error("Unable to get directory info, status code [{}]", statusCode);
            }
        } catch (HttpException x) {
            logger.error("Caught an exception:", x);
        } finally {
            get.releaseConnection();
        }

        return statusCode;
    }

    private Integer createDirectory(String path, DirectoryInfo directoryInfo, String gsToken) throws IOException {
        PutMethod put = new PutMethod(GS_DM_ROOT_URL + GS_ROOT_DIRECTORY + path);
        put.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        put.setRequestHeader("Cookie", "gs-token=" + gsToken);
        put.setRequestHeader("Accept", "application/json");
        put.setRequestHeader("Content-Type", "application/json");
        put.setRequestEntity(new StringRequestEntity("{\"isDirectory\":true}", JSON_MIME_TYPE, "US-ASCII"));
        JSONParser jsonParser = new JSONParser();
        Integer statusCode = null;
        try {
            statusCode = httpClient.executeMethod(put);
            if (HttpServletResponse.SC_OK == statusCode) {
                try (InputStream is = put.getResponseBodyAsStream()) {
                    directoryInfo
                            .setInfo((JSONObject) jsonParser.parse(new BufferedReader(new InputStreamReader(is))));
                } catch (ParseException x) {
                    logger.error("Unable to parse JSON response:", x);
                }
            } else {
                logger.error("Unable create directory, status code [{}]", statusCode);
            }
        } catch (HttpException x) {
            logger.error("Caught an exception:", x);
        } finally {
            put.releaseConnection();
        }

        return statusCode;
    }

    private Integer getFileUploadURL(UploadFileInfo fileInfo, String target, String gsToken) throws IOException {
        GetMethod get = new GetMethod(GS_DM_ROOT_URL + "/uploadurl" + target.replaceAll("^/?(.+[^/])/?$", "/$1/")
                + fileInfo.getFile().getName());
        get.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        get.setQueryString(new NameValuePair[] { new NameValuePair("Content-Length", fileInfo.getContentLength()),
                new NameValuePair("Content-Type", fileInfo.GetContentType()),
                new NameValuePair("Content-MD5", fileInfo.getContentMD5()) });
        get.setRequestHeader("Cookie", "gs-token=" + gsToken);

        Integer statusCode = null;
        try {
            statusCode = httpClient.executeMethod(get);
            if (HttpServletResponse.SC_OK == statusCode) {
                fileInfo.setUploadURL(StringTools.streamToString(get.getResponseBodyAsStream(), "US-ASCII"));
            } else {
                logger.error("Unable to obtain upload URL, status code [{}]", statusCode);
            }
        } catch (HttpException x) {
            logger.error("Caught an exception:", x);
        } finally {
            get.releaseConnection();
        }

        return statusCode;
    }

    private Integer putFile(UploadFileInfo fileInfo) throws IOException {
        PutMethod put = new PutMethod(fileInfo.getUploadURL());
        RequestEntity entity = new FileRequestEntity(fileInfo.getFile(), fileInfo.GetContentType());
        put.setRequestEntity(entity);
        put.setRequestHeader("Content-MD5", fileInfo.getContentMD5());

        Integer statusCode = null;
        try {
            statusCode = httpClient.executeMethod(put);
        } catch (HttpException x) {
            logger.error("Caught an exception:", x);
        } finally {
            put.releaseConnection();
        }
        return statusCode;
    }

    private class DirectoryInfo {
        private JSONObject info = null;

        public void setInfo(JSONObject info) {
            this.info = info;
        }

        public JSONObject getInfo() {
            return this.info;
        }

        public String getPath() {
            if (null != info && info.containsKey("path")) {
                return (String) info.get("path");
            }
            return null;
        }
    }

    private class UploadFileInfo {
        private File file = null;
        private String md5 = null;
        private String uploadURL = null;

        public UploadFileInfo(File file) {
            this.file = file;

        }

        public File getFile() {
            return this.file;
        }

        public String getContentLength() {
            if (null != getFile()) {
                return String.valueOf(getFile().length());
            }
            return null;
        }

        public String getContentMD5() throws IOException {
            if (null != getFile() && null == this.md5) {
                String md5Command = getPreferences().getString("ae.files.get-md5-base64-encoded-command");

                // put fileLocation in place of ${file} in command line
                Map<String, String> params = new HashMap<>();
                params.put("arg.file", getFile().getPath());
                StrSubstitutor sub = new StrSubstitutor(params);
                md5Command = sub.replace(md5Command);

                // execute command
                List<String> commandParams = new ArrayList<>();
                commandParams.add("/bin/sh");
                commandParams.add("-c");
                commandParams.add(md5Command);
                logger.debug("Executing [{}]", md5Command);
                ProcessBuilder pb = new ProcessBuilder(commandParams);
                Process process = pb.start();

                try (InputStream stdOut = process.getInputStream()) {

                    this.md5 = StringTools.streamToString(stdOut, "US-ASCII").replaceAll("\\s", "");
                    if (0 != process.waitFor()) {
                        this.md5 = null;
                    }
                } catch (InterruptedException x) {
                    logger.error("Process was interrupted: ", x);
                }
            }
            return this.md5;
        }

        public String GetContentType() {
            if (null != getFile()) {
                return getServletContext().getMimeType(getFile().getName());
            }
            return null;
        }

        public String getUploadURL() {
            return this.uploadURL;
        }

        public void setUploadURL(String url) {
            this.uploadURL = url;
        }
    }
}