com.google.appinventor.server.GalleryServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.google.appinventor.server.GalleryServlet.java

Source

// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.server;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.util.logging.Logger;

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

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsOutputChannel;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
import com.google.appinventor.server.util.CacheHeaders;
import com.google.appinventor.server.util.CacheHeadersImpl;
import com.google.appinventor.shared.rpc.ServerLayout;
import com.google.appinventor.shared.rpc.UploadResponse;
import com.google.appinventor.shared.rpc.project.GalleryService;
import com.google.appinventor.shared.rpc.project.GallerySettings;

/**
 * Servlet for handling gallery's app publishing.
 *
 */
public class GalleryServlet extends OdeServlet {

    private static int BUFFER_SIZE = 1024 * 1024 * 10;
    private static int MAX_IMAGE_FILE_SIZE = 1024 * 1024 * 5;

    /*
     * URIs for upload requests are structured as follows:
     *    /<baseurl>/gallery_servlet/apps/galleryid/<filePath>
     *    /<baseurl>/gallery_servlet/user/userid/<filePath>
     */

    // Constants for accessing split URI
    /*
     * Upload kind can be: "project", "file", or "userfile".
     * Constants for these are defined in ServerLayout.
     */

    // Constants used when upload kind is "file".
    // Since the file path may contain slashes, it must be the last component in the URI.
    private static final int REQUEST_TYPE_INDEX = 3;
    private static final int GALLERY_OR_USER_ID_INDEX = 4;
    private static final int FILE_PATH_INDEX = 5;

    // Logging support
    private static final Logger LOG = Logger.getLogger(UploadServlet.class.getName());

    // Object used to safely set cache headers in responses
    private static final CacheHeaders CACHE_HEADERS = new CacheHeadersImpl();

    // Content type for response header (to avoid security vulnerabilities)
    private static final String CONTENT_TYPE = "text/html; charset=utf-8";

    private final GalleryService galleryService = new GalleryServiceImpl();

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) {
        setDefaultHeader(resp);
        UploadResponse uploadResponse;

        String uri = req.getRequestURI();
        // First, call split with no limit parameter.
        String[] uriComponents = uri.split("/");

        if (true) {
            String requestType = uriComponents[REQUEST_TYPE_INDEX];
            LOG.info("######### GOT IN URI");
            LOG.info(requestType);

            long project_Id = -1;
            String user_Id = "-1";
            if (requestType.equalsIgnoreCase("apps")) {
                project_Id = Long.parseLong(uriComponents[GALLERY_OR_USER_ID_INDEX]);
            } else if (requestType.equalsIgnoreCase("user")) {
                //the code below doesn't check if user_Id is the id of current user
                //user_Id = uriComponents[GALLERY_OR_USER_ID_INDEX];
                user_Id = userInfoProvider.getUserId();
            }
            InputStream uploadedStream;
            try {
                if (req.getContentLength() < MAX_IMAGE_FILE_SIZE) {
                    uploadedStream = getRequestStream(req, ServerLayout.UPLOAD_FILE_FORM_ELEMENT);

                    // Converts the input stream to byte array
                    byte[] buffer = new byte[8000];
                    int bytesRead = 0;
                    ByteArrayOutputStream bao = new ByteArrayOutputStream();
                    while ((bytesRead = uploadedStream.read(buffer)) != -1) {
                        bao.write(buffer, 0, bytesRead);
                    }
                    // Set up the cloud file (options)
                    String key = "";
                    GallerySettings settings = galleryService.loadGallerySettings();
                    if (requestType.equalsIgnoreCase("apps")) {
                        key = settings.getProjectImageKey(project_Id);
                    } else if (requestType.equalsIgnoreCase("user")) {
                        key = settings.getUserImageKey(user_Id);
                    }

                    // setup cloud
                    GcsService gcsService = GcsServiceFactory.createGcsService();
                    GcsFilename filename = new GcsFilename(settings.getBucket(), key);
                    GcsFileOptions options = new GcsFileOptions.Builder().mimeType("image/jpeg").acl("public-read")
                            .cacheControl("no-cache").build();
                    GcsOutputChannel writeChannel = gcsService.createOrReplace(filename, options);
                    writeChannel.write(ByteBuffer.wrap(bao.toByteArray()));

                    // Now finalize
                    writeChannel.close();

                    uploadResponse = new UploadResponse(UploadResponse.Status.SUCCESS);
                } else {
                    /*file exceeds size of MAX_IMAGE_FILE_SIZE*/
                    uploadResponse = new UploadResponse(UploadResponse.Status.FILE_TOO_LARGE);
                }

                // Now, get the PrintWriter for the servlet response and print the UploadResponse.
                // On the client side, in the onSubmitComplete method in ode/client/utils/Uploader.java, the
                // UploadResponse value will be retrieved as a String via the
                // FormSubmitCompleteEvent.getResults() method.
                PrintWriter out = resp.getWriter();
                out.print(uploadResponse.formatAsHtml());

            } catch (Exception e) {
                throw CrashReport.createAndLogError(LOG, req, null, e);
            }
            // Set http response information
            resp.setStatus(HttpServletResponse.SC_OK);
        }

        // Now, get the PrintWriter for the servlet response and print the UploadResponse.
        // On the client side, in the onSubmitComplete method in ode/client/utils/Uploader.java, the
        // UploadResponse value will be retrieved as a String via the
        // FormSubmitCompleteEvent.getResults() method.
        //    PrintWriter out = resp.getWriter();
        //    out.print(uploadResponse.formatAsHtml());

        // Set http response information
        resp.setStatus(HttpServletResponse.SC_OK);
    }

    private InputStream getRequestStream(HttpServletRequest req, String expectedFieldName) throws Exception {
        ServletFileUpload upload = new ServletFileUpload();
        FileItemIterator iterator = upload.getItemIterator(req);
        while (iterator.hasNext()) {
            FileItemStream item = iterator.next();
            //      LOG.info(item.getContentType());
            if (item.getFieldName().equals(expectedFieldName)) {
                return item.openStream();
            }
        }
        throw new IllegalArgumentException("Field " + expectedFieldName + " not found in upload");
    }

    /**
     * Set a default http header to avoid security vulnerabilities.
     */
    private static void setDefaultHeader(HttpServletResponse resp) {
        CACHE_HEADERS.setNotCacheable(resp);
        resp.setContentType(CONTENT_TYPE);
    }

    /**
     * Helper method for converting input stream
     * @param input
     * @param output
     * @throws IOException
     */
    private void copy(InputStream input, OutputStream output) throws IOException {
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead = input.read(buffer);
        while (bytesRead != -1) {
            output.write(buffer, 0, bytesRead);
            bytesRead = input.read(buffer);
        }
    }
}