ca.nrc.cadc.rest.SyncInput.java Source code

Java tutorial

Introduction

Here is the source code for ca.nrc.cadc.rest.SyncInput.java

Source

/*
************************************************************************
*******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
**************  CENTRE CANADIEN DE DONNES ASTRONOMIQUES  **************
*
*  (c) 2018.                            (c) 2018.
*  Government of Canada                 Gouvernement du Canada
*  National Research Council            Conseil national de recherches
*  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
*  All rights reserved                  Tous droits rservs
*
*  NRC disclaims any warranties,        Le CNRC dnie toute garantie
*  expressed, implied, or               nonce, implicite ou lgale,
*  statutory, of any kind with          de quelque nature que ce
*  respect to the software,             soit, concernant le logiciel,
*  including without limitation         y compris sans restriction
*  any warranty of merchantability      toute garantie de valeur
*  or fitness for a particular          marchande ou de pertinence
*  purpose. NRC shall not be            pour un usage particulier.
*  liable in any event for any          Le CNRC ne pourra en aucun cas
*  damages, whether direct or           tre tenu responsable de tout
*  indirect, special or general,        dommage, direct ou indirect,
*  consequential or incidental,         particulier ou gnral,
*  arising from the use of the          accessoire ou fortuit, rsultant
*  software.  Neither the name          de l'utilisation du logiciel. Ni
*  of the National Research             le nom du Conseil National de
*  Council of Canada nor the            Recherches du Canada ni les noms
*  names of its contributors may        de ses  participants ne peuvent
*  be used to endorse or promote        tre utiliss pour approuver ou
*  products derived from this           promouvoir les produits drivs
*  software without specific prior      de ce logiciel sans autorisation
*  written permission.                  pralable et particulire
*                                       par crit.
*
*  This file is part of the             Ce fichier fait partie du projet
*  OpenCADC project.                    OpenCADC.
*
*  OpenCADC is free software:           OpenCADC est un logiciel libre ;
*  you can redistribute it and/or       vous pouvez le redistribuer ou le
*  modify it under the terms of         modifier suivant les termes de
*  the GNU Affero General Public        la GNU Affero General Public
*  License as published by the          License? telle que publie
*  Free Software Foundation,            par la Free Software Foundation
*  either version 3 of the              : soit la version 3 de cette
*  License, or (at your option)         licence, soit ( votre gr)
*  any later version.                   toute version ultrieure.
*
*  OpenCADC is distributed in the       OpenCADC est distribu
*  hope that it will be useful,         dans lespoir quil vous
*  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
*  without even the implied             GARANTIE : sans mme la garantie
*  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILIT
*  or FITNESS FOR A PARTICULAR          ni dADQUATION  UN OBJECTIF
*  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
*  General Public License for           Gnrale Publique GNU Affero
*  more details.                        pour plus de dtails.
*
*  You should have received             Vous devriez avoir reu une
*  a copy of the GNU Affero             copie de la Licence Gnrale
*  General Public License along         Publique GNU Affero avec
*  with OpenCADC.  If not, see          OpenCADC ; si ce nest
*  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
*                                       <http://www.gnu.org/licenses/>.
*
*  $Revision: 5 $
*
************************************************************************
*/

package ca.nrc.cadc.rest;

import ca.nrc.cadc.util.CaseInsensitiveStringComparator;
import ca.nrc.cadc.net.NetUtil;
import ca.nrc.cadc.net.ResourceNotFoundException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.apache.log4j.Logger;
import java.net.URI;
import java.util.Set;

/**
 * Wrapper around the application-server provided request.
 * 
 * @author pdowler
 */
public class SyncInput {
    private static final Logger log = Logger.getLogger(SyncInput.class);

    private final HttpServletRequest request;
    private final InlineContentHandler inlineContentHandler;

    private final Map<String, Object> content = new TreeMap<>(new CaseInsensitiveStringComparator());
    private final Map<String, List<String>> params = new TreeMap<>(new CaseInsensitiveStringComparator());

    public SyncInput(HttpServletRequest request, InlineContentHandler handler) throws IOException {
        this.request = request;
        this.inlineContentHandler = handler;
    }

    /**
     * Get the real client IP address. The REST binding is split up as follows:
     *  <pre>
     *  requestURI = protocol :// hostname / requestPath
     *  requestPath = contextPath / componentPath / path
     *  </pre>
     * 
     * @return client IP address
     */
    public String getClientIP() {
        return NetUtil.getClientIP(request);
    }

    /**
     * Get the HTTP protocol used for the request.
     * 
     * @return transport protocol (http or https)
     */
    public String getProtocol() {
        return request.getScheme();
    }

    /**
     * Get the complete request URI. This contains everything from protocol, hostname,
     * optional port, and request path.
     * 
     * 
     * @return complete request URI
     */
    public String getRequestURI() {
        return request.getRequestURL().toString();
    }

    /**
     * Get the complete path in the request. This is simply the path component of
     * the requestURI.
     * 
     * @return complete path
     */
    public String getRequestPath() {
        String uri = getRequestURI();
        URI u = URI.create(uri);
        return u.getPath();
    }

    /**
     * Get the path up to the rest binding. This returns the base path of the
     * REST application.
     * 
     * @return context path
     */
    public String getContextPath() {
        String ret = request.getContextPath();
        return ret;
    }

    /**
     * Get the path up to the rest binding. This returns the path of the
     * REST application component.
     * 
     * @return context path
     */
    public String getComponentPath() {
        String ret = request.getServletPath();
        return ret;
    }

    /**
     * Get the application-specific path. This is the rest of the path after the 
     * context path with leading slash removed.
     * 
     * @return application-specific sub-path, possibly null
     */
    public String getPath() {
        String ret = request.getPathInfo();
        if (ret == null)
            return ret;
        if (ret.charAt(0) == '/')
            ret = ret.substring(1);
        return ret;
    }

    /**
     * Get a request header value.
     *
     * @param name HTTP header name
     * @return header value, possibly null
     */
    public String getHeader(String name) {
        return request.getHeader(name);
    }

    /**
     * Get set of all parameters included in the request.
     * 
     * @return set of parameter names
     */
    public Set<String> getParameterNames() {
        return params.keySet();
    }

    /**
     * Get a request parameter value. If there are multiple instances of the parameter,
     * the first is returned (see getParameters).
     *
     * @param name name of parameter
     * @return a value for the specified parameter name; may be null
     */
    public String getParameter(String name) {
        List<String> vals = params.get(name);
        if (vals != null && !vals.isEmpty())
            return vals.get(0);
        return null;
    }

    /**
     * Get all request parameter values.
     *
     * @param name name of parameter
     * @return all values for the specified parameter name; may be null
     */
    public List<String> getParameters(String name) {
        return params.get(name);
    }

    /**
     * Get set of all names for inline content in the request. Accessing inline content 
     * requires an InlineContentHandler.
     * 
     * @return set of inline content names
     */
    public Set<String> getContentNames() {
        return content.keySet();
    }

    /**
     * Get an inline content object.
     *
     * @param name name of inline object
     * @return an object for the specified content name; may be null
     */
    public Object getContent(String name) {
        return content.get(name);
    }

    public void init() throws IOException, ResourceNotFoundException {
        if (request.getMethod().equals("GET") || request.getMethod().equals("HEAD")
                || request.getMethod().equals("DELETE")) {
            Enumeration<String> names = request.getParameterNames();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                processParameter(name, request.getParameterValues(name));
            }
        } else {
            String contentType = request.getContentType();
            if (contentType != null) {
                int i = contentType.indexOf(';');
                if (i > 0)
                    contentType = contentType.substring(0, i);
            }
            log.debug("Content-Type: " + contentType);
            if (contentType != null && contentType.equalsIgnoreCase(RestAction.URLENCODED)) {
                Enumeration<String> names = request.getParameterNames();
                while (names.hasMoreElements()) {
                    String name = names.nextElement();
                    processParameter(name, request.getParameterValues(name));
                }
            } else if (contentType != null && contentType.startsWith(RestAction.MULTIPART)) {
                try {
                    ServletFileUpload upload = new ServletFileUpload();
                    FileItemIterator itemIterator = upload.getItemIterator(request);
                    processMultiPart(itemIterator);
                } catch (FileUploadException ex) {
                    throw new IOException("Failed to process " + RestAction.MULTIPART, ex);
                }
            } else {
                processStream(null, contentType, request.getInputStream());
            }
        }
    }

    private void processParameter(String name, String[] values) {
        this.params.put(name, Arrays.asList(values));
    }

    private void processMultiPart(FileItemIterator itemIterator)
            throws FileUploadException, IOException, ResourceNotFoundException {
        while (itemIterator.hasNext()) {
            FileItemStream item = itemIterator.next();
            String name = item.getFieldName();
            InputStream stream = item.openStream();
            if (item.isFormField())
                processParameter(name, new String[] { Streams.asString(stream) });
            else
                processStream(name, item.getContentType(), stream);
        }
    }

    private void processStream(String name, String contentType, InputStream inputStream)
            throws IOException, ResourceNotFoundException {
        if (inlineContentHandler == null) {
            log.warn("request includes inline content and InlineContentHandler is null");
            // TODO: Need to figure if we need to process the stream to completion
            return;
        }

        InlineContentHandler.Content c = inlineContentHandler.accept(name, contentType,
                new CloseWrapper(inputStream));
        content.put(c.name, c.value);
    }

    // this is here to aid in debugging InputStream failures like the one where some library code
    // called close() in a finalise() method, eg during garbage collection
    private class CloseWrapper extends FilterInputStream {

        String tname;

        public CloseWrapper(InputStream in) {
            super(in);
            this.tname = "CloseWrapper[" + Thread.currentThread().getName() + "] ";
        }

        @Override
        public void close() throws IOException {
            Exception ex = new Exception();
            String streamID = super.in.toString();
            //log.debug(tname + " - " + streamID + ": close() was called: ", ex);
            super.in.close();
        }

    }
}