package com.google.appengine.demos;

import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsInputChannel;
import com.google.appengine.tools.cloudstorage.GcsOutputChannel;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
import com.google.appengine.tools.cloudstorage.RetryParams;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;

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


/**
 * A simple servlet that proxies reads and writes to its Google Cloud Storage bucket.
 */
@SuppressWarnings("serial")
public class GcsExampleServlet extends HttpServlet {

  /**
   * This is where backoff parameters are configured. Here it is aggressively retrying with
   * backoff, up to 10 times but taking no more that 15 seconds total to do so.
   */
  private final GcsService gcsService = GcsServiceFactory.createGcsService(new RetryParams.Builder()
      .initialRetryDelayMillis(10)
      .retryMaxAttempts(10)
      .totalRetryPeriodMillis(15000)
      .build());

  /**Used below to determine the size of chucks to read in. Should be > 1kb and < 10MB */
  private static final int BUFFER_SIZE = 2 * 1024 * 1024;

  /**
   * Retrieves a file from GCS and returns it in the http response.
   * If a get comes in for request path /gcs/Foo/Bar this will be interpreted as
   * a request to read the GCS file named Bar in the bucket Foo.
   */
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    GcsInputChannel readChannel =
      gcsService.openPrefetchingReadChannel(getFileName(req), 0, BUFFER_SIZE);
    copy(Channels.newInputStream(readChannel), resp.getOutputStream());
  }

  /**
   * Writes the payload of the incoming post as the contents of a file to GCS.
   * If the post is to request path is /gcs/Foo/Bar this will be interpreted as
   * a request to create a GCS file named Bar in bucket Foo.
   */
  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    GcsOutputChannel outputChannel =
        gcsService.createOrReplace(getFileName(req), GcsFileOptions.getDefaultInstance());
    copy(req.getInputStream(), Channels.newOutputStream(outputChannel));
  }

  private GcsFilename getFileName(HttpServletRequest req) {
    String[] splits = req.getRequestURI().split("/", 4);
    if (!splits[0].equals("") || !splits[1].equals("gcs")) {
      throw new IllegalArgumentException("The URL is not formed as expected. " +
          "Expecting /gcs/<bucket>/<object>");
    }
    return new GcsFilename(splits[2], splits[3]);
  }

  /**
   * Transfer the data from the inputStream to the outputStream. Then close both streams.
   */
  private void copy(InputStream input, OutputStream output) throws IOException {
    try {
      byte[] buffer = new byte[BUFFER_SIZE];
      int bytesRead = input.read(buffer);
      while (bytesRead != -1) {
        output.write(buffer, 0, bytesRead);
        bytesRead = input.read(buffer);
      }
    } finally {
      input.close();
      output.close();
    }
  }


}

@@ -26,24 +26,202 @@
 ine.demos;%0A%0A
+import com.google.appengine.api.blobstore.BlobKey;%0Aimport com.google.appengine.api.blobstore.BlobstoreService;%0Aimport com.google.appengine.api.blobstore.BlobstoreServiceFactory;%0A
 import com.g
@@ -271,16 +271,16 @@
 ptions;%0A
-
 import c
@@ -1077,16 +1077,82 @@
 vlet %7B%0A%0A
+  public static final boolean SERVE_USING_BLOBSTORE_API = false;%0A%0A
   /**%0A  
@@ -2020,24 +2020,392 @@
 Exception %7B%0A
+    GcsFilename fileName = getFileName(req);%0A    if (SERVE_USING_BLOBSTORE_API) %7B%0A      BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();%0A      BlobKey blobKey = blobstoreService.createGsBlobKey(%0A          %22/gs/%22 + fileName.getBucketName() + %22/%22 + fileName.getObjectName());%0A      blobstoreService.serve(blobKey, resp);%0A    %7D else %7B%0A  
     GcsInput
@@ -2425,22 +2425,16 @@
 hannel =
-%0A     
  gcsServ
@@ -2464,32 +2464,24 @@
 Channel(
-getF
+f
 ileName
-(req)
 , 0, BUF
@@ -2491,16 +2491,18 @@
 _SIZE);%0A
+  
     copy
@@ -2561,24 +2561,30 @@
 tStream());%0A
+    %7D%0A
   %7D%0A%0A  /**%0A 

Add an example to serve data from GCS using BlobStore.