Package net.noderunner.amazon.s3.emulator

Source Code of net.noderunner.amazon.s3.emulator.Server

package net.noderunner.amazon.s3.emulator;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.noderunner.amazon.s3.Entry;
import net.noderunner.amazon.s3.Headers;
import net.noderunner.amazon.s3.Owner;
import net.noderunner.amazon.s3.S3Object;
import net.noderunner.http.servlet.ServletServer;


/**
* Amazon S3 emulator that stores data in an internal sorted map.
* Not highly scalable or reliable, but may be fine for testing your application.
*
* Some browse methods are not complete.
* Get Data/Put/Head are mostly complete.
* What's supported is in the test suite.
*
* @author Elias Ross
*/
public class Server extends HttpServlet {

  private static final long serialVersionUID = 1L;

  private transient Log log = LogFactory.getLog(getClass());
  private transient ServletServer ss;
  private boolean bucket = false;
  private SortedMap<Entry, S3Object> map = Collections.synchronizedSortedMap(new TreeMap<Entry, S3Object>());

  public Server() throws IOException {
    ss = new ServletServer(this);
    log.info("Server created " + this);
  }

  /**
   * Closes socket, stops accepting requests.
   */
  public void close() throws IOException {
    log("close");
    ss.close();
  }

  @Override
  protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    Entry e = entry(req);
    S3Object remove = map.remove(e);
    if (remove == null) {
      resp.sendError(404, "Not found " + e);
    } else {
      resp.sendError(HttpURLConnection.HTTP_NO_CONTENT, "Deleted");
    }

  }

  private Entry entry(HttpServletRequest req) {
    return new Entry(key(uri(req)));
  }

  /**
   * Listening port.
   */
  public int getPort() {
    return ss.getPort();
  }

  /**
   * Starts accepting requests.
   */
  public void start() {
    ss.start();
  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    URI uri = uri(req);
    boolean debug = log.isDebugEnabled();
    if (debug)
        log("doGet " + uri);
    if ("/".equals(uri.getPath())) {
      list(req, resp);
    } else {
      String key = uri.getPath().substring(1);
      Entry e = new Entry(key);
      S3Object obj = map.get(e);
        if (debug)
          log("map.get(" + key + ") = " + obj);
      if (obj == null) {
        resp.sendError(404, "Not here: " + e);
        return;
      }
      Headers h = new Headers();
      h = h.mergeMetadata(obj.getMetadata());
      for (Map.Entry<String, List<String>> me : h.getHeaders().entrySet()) {
        for (String v : me.getValue()) {
          resp.setHeader(me.getKey(), v);
        }
      }
      resp.getOutputStream().write(obj.getData());
    }

  }

  private void list(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    String prefix = req.getParameter("prefix");
    String marker = req.getParameter("marker");
    String delimiter = req.getParameter("delimiter");
    String maxKeysStr = req.getParameter("max-keys");
    if (log.isDebugEnabled())
        log("list prefix=" + prefix + " delimiter=" + delimiter);
    int maxKeys = Integer.MAX_VALUE;
    if (maxKeysStr != null)
      maxKeys = Integer.parseInt(maxKeysStr);
    Writer w = new Writer();
    SortedMap<Entry, S3Object> submap = new TreeMap<Entry, S3Object>(map);
    if (prefix != null)
      submap = submap.tailMap(new Entry(prefix));
    int keyCount = 0;
    boolean truncated = false;
    String nextMarker = null;
    for (Entry e : submap.keySet()) {
      if (++keyCount > maxKeys) {
        truncated = true;
        break;
      }
      String key = e.getKey();
      String remain = key;
      nextMarker = key;
      if (prefix != null) {
        if (!key.startsWith(prefix))
            break;
        remain = key.substring(prefix.length());
      }
      if (delimiter != null && remain.indexOf(delimiter) != -1)
        continue;
        if (log.isDebugEnabled())
          log("include key=" + key);
      w.start("Contents");
      w.start("Key").write(key).end();
      w.start("LastModified").write(e.getLastModified()).end();
      w.start("Size").write(e.getSize()).end();
      w.start("Owner");
      w.start("ID").write(e.getOwner().getId()).end()
          .start("DisplayName").write(e.getOwner().getDisplayName())
          .end();
      w.end();
      w.end();
    }

    Writer hw = new Writer();
    hw.start("ListBucketResult");
    hw.start("Name").write("localhost").end();
    hw.start("Prefix").write(s(prefix)).end();
    hw.start("Marker").write(s(marker)).end();
    if (delimiter != null) {
      hw.start("Delimiter").write(delimiter).end();
        if (truncated) {
          hw.start("NextMarker").write(nextMarker).end();
        }
    }
    hw.start("IsTruncated").write(String.valueOf(truncated)).end();
    if (maxKeysStr != null)
      hw.start("MaxKeys").write(maxKeysStr).end();
    hw.write(w);
    hw.end();

    PrintWriter pw = resp.getWriter();
    pw.write(hw.toString());
    pw.flush();
    bucket = true;
  }

  private String s(String s) {
    if (s == null)
      return "";
    return s;
  }

  @Override
  protected void doHead(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    URI uri = uri(req);
    if (log.isDebugEnabled())
        log("doHead " + uri);
    if (map.containsKey(entry(req))) {
        log("found");
      resp.sendError(HttpURLConnection.HTTP_OK, "Found URI");
    } else {
        log("not found");
      resp.sendError(404, "Not found");
    }
  }
 
  private URI uri(HttpServletRequest req) {
    try {
      return new URI(req.getRequestURI());
    } catch (URISyntaxException e1) {
      throw new RuntimeException(e1);
    }
  }
 
  private String key(URI uri) {
    return uri.getPath().substring(1);
  }

  @Override
  protected void doPut(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    URI uri = uri(req);
    log("doPut " + uri);
    if ("/".equals(uri.getPath())) {
      log("create bucket");
      bucket = true;
    } else {
      Entry e = new Entry(key(uri));
      e.setLastModified(new Date());
      e.setSize(req.getContentLength());
      e.setOwner(new Owner("id", "name"));
      ByteArrayOutputStream os = new ByteArrayOutputStream();
      ServletInputStream is = req.getInputStream();
      byte b[] = new byte[128];
      while (true) {
        int len = is.read(b);
        if (len == -1)
          break;
        os.write(b, 0, len);
      }
      S3Object s3 = new S3Object(os.toByteArray());
      map.put(e, s3);
      Headers h = new Headers();
      @SuppressWarnings("unchecked")
      Enumeration<String> names = req.getHeaderNames();
      for (String n : Collections.list(names))
        h.put(n, req.getHeader(n));
      s3.setMetadata(h.extractMetadata());
      log("put '" + e + "' as: " + s3);
    }
  }

  @Override
  public void log(String s) {
    log.debug(s);
  }

  /**
   * Returns a debug <code>String</code>.
   */
  @Override
  public String toString()
  {
      return super.toString() +
          " bucket=" + this.bucket +
          " ss=" + this.ss +
          " map=" + this.map +
          "";
  }

}
TOP

Related Classes of net.noderunner.amazon.s3.emulator.Server

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.