Package org.purl.sword.server

Source Code of org.purl.sword.server.DepositServlet

/**
* Copyright (c) 2008, Aberystwyth University
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*  - Redistributions of source code must retain the above
*    copyright notice, this list of conditions and the
*    following disclaimer.
*  - Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*   
*  - Neither the name of the Centre for Advanced Software and
*    Intelligent Systems (CASIS) nor the names of its
*    contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

package org.purl.sword.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.purl.sword.atom.Summary;
import org.purl.sword.atom.Title;
import org.purl.sword.base.ChecksumUtils;
import org.purl.sword.base.Deposit;
import org.purl.sword.base.DepositResponse;
import org.purl.sword.base.ErrorCodes;
import org.purl.sword.base.HttpHeaders;
import org.purl.sword.base.SWORDAuthenticationException;
import org.purl.sword.base.SWORDErrorDocument;
import org.purl.sword.base.SWORDException;
import org.purl.sword.base.SWORDErrorException;

/**
* DepositServlet
*
* @author Stuart Lewis
*/
public class DepositServlet extends HttpServlet {

  /** Sword repository */
  protected SWORDServer myRepository;

  /** Authentication type */
  private String authN;
 
  /** Maximum file upload size in kB **/
  private int maxUploadSize;

  /** Temp directory */
  private String tempDirectory;

  /** Counter */
  private static AtomicInteger counter = new AtomicInteger(0);

  /** Logger */
  private static Logger log = Logger.getLogger(DepositServlet.class);

  /**
   * Initialise the servlet
   *
   * @throws ServletException
   */
  public void init() throws ServletException {
    // Instantiate the correct SWORD Server class
    String className = getServletContext().getInitParameter("sword-server-class");
    if (className == null) {
      log.fatal("Unable to read value of 'sword-server-class' from Servlet context");
    } else {
      try {
        myRepository = (SWORDServer) Class.forName(className)
            .newInstance();
        log.info("Using " + className + " as the SWORDServer");
      } catch (Exception e) {
        log
            .fatal("Unable to instantiate class from 'sword-server-class': "
                + className);
        throw new ServletException(
            "Unable to instantiate class from 'sword-server-class': "
                + className);
      }
    }

    authN = getServletContext().getInitParameter("authentication-method");
    if ((authN == null) || (authN.equals(""))) {
      authN = "None";
    }
    log.info("Authentication type set to: " + authN);

    String maxUploadSizeStr = getServletContext().getInitParameter("maxUploadSize");
    if ((maxUploadSizeStr == null) ||
        (maxUploadSizeStr.equals("")) ||
        (maxUploadSizeStr.equals("-1"))) {
      maxUploadSize = -1;
      log.warn("No maxUploadSize set, so setting max file upload size to unlimited.");
    } else {
      try {
        maxUploadSize = Integer.parseInt(maxUploadSizeStr);
        log.info("Setting max file upload size to " + maxUploadSize);
      } catch (NumberFormatException nfe) {
        maxUploadSize = -1;
        log.warn("maxUploadSize not a number, so setting max file upload size to unlimited.");
      }
    }

    tempDirectory = getServletContext().getInitParameter(
        "upload-temp-directory");
    if ((tempDirectory == null) || (tempDirectory.equals(""))) {
      tempDirectory = System.getProperty("java.io.tmpdir");
    }
        if (!tempDirectory.endsWith(System.getProperty("file.separator")))
        {
            tempDirectory += System.getProperty("file.separator");
        }
    File tempDir = new File(tempDirectory);
    log.info("Upload temporary directory set to: " + tempDir);
    if (!tempDir.exists()) {
      if (!tempDir.mkdirs()) {
        throw new ServletException(
            "Upload directory did not exist and I can't create it. "
                + tempDir);
      }
    }
    if (!tempDir.isDirectory()) {
      log.fatal("Upload temporary directory is not a directory: "
          + tempDir);
      throw new ServletException(
          "Upload temporary directory is not a directory: " + tempDir);
    }
    if (!tempDir.canWrite()) {
      log.fatal("Upload temporary directory cannot be written to: "
          + tempDir);
      throw new ServletException(
          "Upload temporary directory cannot be written to: "
              + tempDir);
    }
  }

  /**
   * Process the Get request. This will return an unimplemented response.
   */
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // Send a '501 Not Implemented'
    response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
  }

  /**
   * Process a post request.
   */
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // Create the Deposit request
    Deposit d = new Deposit();
    Date date = new Date();
    log.debug("Starting deposit processing at " + date.toString() + " by "
        + request.getRemoteAddr());

    // Are there any authentication details?
    String usernamePassword = getUsernamePassword(request);
    if ((usernamePassword != null) && (!usernamePassword.equals(""))) {
      int p = usernamePassword.indexOf(":");
      if (p != -1) {
        d.setUsername(usernamePassword.substring(0, p));
        d.setPassword(usernamePassword.substring(p + 1));
      }
    } else if (authenticateWithBasic()) {
      String s = "Basic realm=\"SWORD\"";
      response.setHeader("WWW-Authenticate", s);
      response.setStatus(401);
      return;
    }
   
    // Set up some variables
    String filename = null;
    File f = null;
    FileInputStream fis = null;

    // Do the processing
    try {
      // Write the file to the temp directory
      filename = tempDirectory + "SWORD-"
          + request.getRemoteAddr() + "-" + counter.addAndGet(1);
            log.debug("Package temporarily stored as: " + filename);
      InputStream inputstream = request.getInputStream();
      OutputStream outputstream = new FileOutputStream(new File(filename));
      try
      {
          byte[] buf = new byte[1024];
          int len;
          while ((len = inputstream.read(buf)) > 0)
          {
              outputstream.write(buf, 0, len);
          }
      }
      finally
      {
          inputstream.close();
          outputstream.close();
      }

      // Check the size is OK
      File file = new File(filename);
        long fLength = file.length() / 1024;
        if ((maxUploadSize != -1) && (fLength > maxUploadSize)) {
          this.makeErrorDocument(ErrorCodes.MAX_UPLOAD_SIZE_EXCEEDED,
                             HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE,
                             "The uploaded file exceeded the maximum file size this server will accept (the file is " +
                             fLength + "kB but the server will only accept files as large as " +
                             maxUploadSize + "kB)",
                             request,
                             response);
          return;
        }
       
      // Check the MD5 hash
      String receivedMD5 = ChecksumUtils.generateMD5(filename);
      log.debug("Received filechecksum: " + receivedMD5);
      d.setMd5(receivedMD5);
      String md5 = request.getHeader("Content-MD5");
      log.debug("Received file checksum header: " + md5);
      if ((md5 != null) && (!md5.equals(receivedMD5))) {
        // Return an error document
        this.makeErrorDocument(ErrorCodes.ERROR_CHECKSUM_MISMATCH,
                           HttpServletResponse.SC_PRECONDITION_FAILED,
                           "The received MD5 checksum for the deposited file did not match the checksum sent by the deposit client",
                           request,
                           response);
        log.debug("Bad MD5 for file. Aborting with appropriate error message");
        return;
      } else {
        // Set the file
        f = new File(filename);
        fis = new FileInputStream(f);
        d.setFile(fis);

        // Set the X-On-Behalf-Of header
                String onBehalfOf = request.getHeader(HttpHeaders.X_ON_BEHALF_OF.toString());
        if ((onBehalfOf != null) && (onBehalfOf.equals("reject"))) {
                    // user name is "reject", so throw a not know error to allow the client to be tested
                    throw new SWORDErrorException(ErrorCodes.TARGET_OWNER_UKNOWN,"unknown user \"reject\"");
                } else {
                    d.setOnBehalfOf(onBehalfOf);
                }

        // Set the X-Packaging header
        d.setPackaging(request.getHeader(HttpHeaders.X_PACKAGING));

        // Set the X-No-Op header
        String noop = request.getHeader(HttpHeaders.X_NO_OP);
                log.error("X_NO_OP value is " + noop);
        if ((noop != null) && (noop.equals("true"))) {
          d.setNoOp(true);
        } else if ((noop != null) && (noop.equals("false"))) {
          d.setNoOp(false);
                }else if (noop == null) {
                    d.setNoOp(false);
        } else {
                    throw new SWORDErrorException(ErrorCodes.ERROR_BAD_REQUEST,"Bad no-op");
                }

        // Set the X-Verbose header
        String verbose = request.getHeader(HttpHeaders.X_VERBOSE);
        if ((verbose != null) && (verbose.equals("true"))) {
          d.setVerbose(true);
        } else if ((verbose != null) && (verbose.equals("false"))) {
          d.setVerbose(false);
                }else if (verbose == null) {
                    d.setVerbose(false);
        } else {
                    throw new SWORDErrorException(ErrorCodes.ERROR_BAD_REQUEST,"Bad verbose");
                }

        // Set the slug
        String slug = request.getHeader(HttpHeaders.SLUG);
        if (slug != null) {
          d.setSlug(slug);
        }

        // Set the content disposition
        d.setContentDisposition(request.getHeader(HttpHeaders.CONTENT_DISPOSITION));

        // Set the IP address
        d.setIPAddress(request.getRemoteAddr());

        // Set the deposit location
        d.setLocation(getUrl(request));

        // Set the content type
        d.setContentType(request.getContentType());

        // Set the content length
        String cl = request.getHeader(HttpHeaders.CONTENT_LENGTH);
        if ((cl != null) && (!cl.equals(""))) {
          d.setContentLength(Integer.parseInt(cl));
        }

        // Get the DepositResponse
        DepositResponse dr = myRepository.doDeposit(d);
       
        // Echo back the user agent
        if (request.getHeader(HttpHeaders.USER_AGENT.toString()) != null) {
          dr.getEntry().setUserAgent(request.getHeader(HttpHeaders.USER_AGENT.toString()));
        }
       
        // Echo back the packaging format
        if (request.getHeader(HttpHeaders.X_PACKAGING.toString()) != null) {
          dr.getEntry().setPackaging(request.getHeader(HttpHeaders.X_PACKAGING.toString()));
        }
       
        // Print out the Deposit Response
        response.setStatus(dr.getHttpResponse());
        if ((dr.getLocation() != null) && (!dr.getLocation().equals("")))
        {
          response.setHeader("Location", dr.getLocation());
        }
        response.setContentType("application/atom+xml; charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.write(dr.marshall());
        out.flush();
      }
    } catch (SWORDAuthenticationException sae) {
      // Ask for credentials again
      if (authN.equals("Basic")) {
        String s = "Basic realm=\"SWORD\"";
        response.setHeader("WWW-Authenticate", s);
        response.setStatus(401);
      }
    } catch (SWORDErrorException see) {
      // Get the details and send the right SWORD error document
      log.error(see.toString());
      this.makeErrorDocument(see.getErrorURI(),
                            see.getStatus(),
                            see.getDescription(),
                               request,
                               response);
      return;
    } catch (SWORDException se) {
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      log.error(se.toString());
    } catch (NoSuchAlgorithmException nsae) {
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      log.error(nsae.toString());
    }
   
    finally {
      // Close the input stream if it still open
      if (fis != null) {
        fis.close();
      }

      // Try deleting the temp file
      if (filename != null) {
        f = new File(filename);
        f.delete();
      }
    }
  }
 
  /**
   * Utility method to construct a SWORDErrorDocumentTest
   *
   * @param errorURI The error URI to pass
   * @param status The HTTP status to return
   * @param summary The textual description to give the user
   * @param request The HttpServletRequest object
   * @param response The HttpServletResponse to send the error document to
   * @throws IOException
   */
  protected void makeErrorDocument(String errorURI, int status, String summary,
                             HttpServletRequest request, HttpServletResponse response) throws IOException
  {
    SWORDErrorDocument sed = new SWORDErrorDocument(errorURI);
    Title title = new Title();
    title.setContent("ERROR");
    sed.setTitle(title);
    Calendar calendar = Calendar.getInstance();
    String utcformat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
    SimpleDateFormat zulu = new SimpleDateFormat(utcformat);
    String serializeddate = zulu.format(calendar.getTime());
    sed.setUpdated(serializeddate);
    Summary sum = new Summary();
    sum.setContent(summary);
    sed.setSummary(sum);
    if (request.getHeader(HttpHeaders.USER_AGENT.toString()) != null) {
      sed.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT.toString()));
    }
    response.setStatus(status);
      response.setContentType("application/atom+xml; charset=UTF-8");
    PrintWriter out = response.getWriter();
      out.write(sed.marshall().toXML());
    out.flush();
  }

  /**
   * Utility method to return the username and password (separated by a colon
   * ':')
   *
   * @param request
   * @return The username and password combination
   */
  protected String getUsernamePassword(HttpServletRequest request) {
    try {
      String authHeader = request.getHeader("Authorization");
      if (authHeader != null) {
        StringTokenizer st = new StringTokenizer(authHeader);
        if (st.hasMoreTokens()) {
          String basic = st.nextToken();
          if (basic.equalsIgnoreCase("Basic")) {
            String credentials = st.nextToken();
            String userPass = new String(Base64
                .decodeBase64(credentials.getBytes()));
            return userPass;
          }
        }
      }
    } catch (Exception e) {
      log.debug(e.toString());
    }
    return null;
  }

  /**
   * Utility method to decide if we are using HTTP Basic authentication
   *
   * @return if HTTP Basic authentication is in use or not
   */
  protected boolean authenticateWithBasic() {
    if (authN.equalsIgnoreCase("Basic")) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * Utility method to construct the URL called for this Servlet
   *
   * @param req The request object
   * @return The URL
   */
  protected static String getUrl(HttpServletRequest req) {
    String reqUrl = req.getRequestURL().toString();
    String queryString = req.getQueryString();
    if (queryString != null) {
      reqUrl += "?" + queryString;
    }
    return reqUrl;
  }
}
TOP

Related Classes of org.purl.sword.server.DepositServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.