gwtupload.server.gae.BlobstoreUploadAction.java Source code

Java tutorial

Introduction

Here is the source code for gwtupload.server.gae.BlobstoreUploadAction.java

Source

/*
 * Copyright 2010 Manuel Carrasco Moino. (manuel_carrasco at
 * users.sourceforge.net) http://code.google.com/p/gwtupload
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package gwtupload.server.gae;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

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

import static gwtupload.shared.UConsts.PARAM_BLOBKEY;
import static gwtupload.shared.UConsts.PARAM_CANCEL;
import static gwtupload.shared.UConsts.PARAM_ERROR;
import static gwtupload.shared.UConsts.PARAM_REDIRECT;
import static gwtupload.shared.UConsts.RESP_OK;
import static gwtupload.shared.UConsts.TAG_CANCELED;
import static gwtupload.shared.UConsts.TAG_ERROR;
import static gwtupload.shared.UConsts.TAG_FINISHED;
import static gwtupload.shared.UConsts.TAG_MESSAGE;
import gwtupload.server.AbstractUploadListener;
import gwtupload.server.UploadAction;
import gwtupload.server.exceptions.UploadActionException;
import gwtupload.server.exceptions.UploadCanceledException;
import gwtupload.server.gae.BlobstoreFileItemFactory.BlobstoreFileItem;
import gwtupload.shared.UConsts;

/**
 * <p>
 * Upload servlet for the GwtUpload library's deployed in Google App-engine using blobstore.
 * </p>
 *
 * <p>
 * Constrains:
 * <ul>
 *   <li>It seems that the redirected servlet path must be /upload because wildcards don't work.</li>
 *   <li>After of blobstoring, our doPost receives a request size = -1.</li>
 *   <li>If the upload fails, our doPost is never called.</li>
 * </ul>
 *
 * @author Manolo Carrasco Moino
 *
 */
public class BlobstoreUploadAction extends UploadAction {

    private static final long serialVersionUID = -2569300604226532811L;

    protected static BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

    // See constrain 1
    private String servletPath = "/upload";

    @Override
    public void checkRequest(HttpServletRequest request) {
        logger.debug("BLOB-STORE-SERVLET: (" + request.getSession().getId() + ") procesing a request with size: "
                + request.getContentLength() + " bytes.");
    }

    @Override
    public boolean isAppEngine() {
        return true;
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        uploadDelay = 0;
        useBlobstore = true;
        logger.info("BLOB-STORE-SERVLET: init: maxSize=" + maxSize + ", slowUploads=" + uploadDelay
                + ", isAppEngine=" + isAppEngine() + ", useBlobstore=" + useBlobstore);
    }

    @SuppressWarnings("serial")
    @Override
    protected final AbstractUploadListener createNewListener(HttpServletRequest request) {
        return new MemCacheUploadListener(uploadDelay, request.getContentLength()) {
            int cont = 1;

            // In blobStore we cannot know the fileSize emulating progress
            public long getBytesRead() {
                return getContentLength() / (isFinished() ? 1 : 10 * (1 + (cont++ % 10)));
            }

            public long getContentLength() {
                return 100;
            }
        };
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        if (request.getParameter(PARAM_BLOBKEY) != null) {
            BlobKey blobKey = new BlobKey(request.getParameter("blob-key"));
            blobstoreService.serve(blobKey, response);
            try {
                logger.info("BLOB-STORE-SERVLET: Serving blobstore file. " + request.getParameter(PARAM_BLOBKEY));
                blobstoreService.serve(new BlobKey(request.getParameter(PARAM_BLOBKEY)), response);
            } catch (Throwable e) {
                logger.info("BLOB-STORE-SERVLET: Exception accessing blobStoreService:" + e.getMessage());
                e.printStackTrace();
                renderXmlResponse(request, response,
                        "Error getting blob: " + e.getMessage() + " " + request.getParameter(PARAM_BLOBKEY));
            }
        } else if (request.getParameter(PARAM_REDIRECT) != null) {
            perThreadRequest.set(request);
            Map<String, String> stat = new HashMap<String, String>();
            if (request.getParameter(PARAM_ERROR) != null) {
                stat.put(TAG_ERROR, request.getParameter(PARAM_ERROR));
            } else if (request.getParameter(PARAM_CANCEL) != null) {
                stat.put(TAG_CANCELED, request.getParameter(PARAM_CANCEL));
            } else {
                try {
                    getFileItemsSummary(request, stat);
                    String message = executeAction(request, getMySessionFileItems(request));
                    stat.put(TAG_MESSAGE, message);
                    stat.put(TAG_FINISHED, RESP_OK);
                } catch (UploadActionException e) {
                    logger.error("ExecuteUploadActionException: " + e);
                    stat.put(TAG_ERROR, e.getMessage());
                }
            }
            String ret = statusToString(stat);
            finish(request, ret);

            logger.debug("BLOB-STORE-SERVLET: (" + request.getSession().getId() + ") redirect \n" + ret);
            renderXmlResponse(request, response, ret, true);

            perThreadRequest.set(null);
        } else {
            super.doGet(request, response);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        String error = null;
        perThreadRequest.set(request);
        try {
            error = super.parsePostRequest(request, response);
        } catch (UploadCanceledException e) {
            redirect(response, PARAM_CANCEL + "=true");
            return;
        } catch (Exception e) {
            logger.info("BLOB-STORE-SERVLET: Exception " + e);
            error = e.getMessage();
        } finally {
            perThreadRequest.set(null);
        }

        if (error != null) {
            removeSessionFileItems(request);
            redirect(response, PARAM_ERROR + "=" + error);
            perThreadRequest.set(null);
            return;
        }

        List<FileItem> sessionFiles = getLastReceivedFileItems(request);
        if (sessionFiles == null) {
            sessionFiles = new ArrayList<FileItem>();
            request.setAttribute(getSessionLastFilesKey(request), sessionFiles);
        }
        Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(request);
        if (blobs != null && blobs.size() > 0) {
            for (Entry<String, List<BlobKey>> e : blobs.entrySet()) {
                for (BlobKey blob : e.getValue()) {
                    BlobstoreFileItem bfi = null;
                    if (sessionFiles != null) {
                        for (FileItem i : sessionFiles) {
                            if (i.getFieldName().replaceFirst("-\\d+$", "")
                                    .equals(e.getKey().replace(UConsts.MULTI_SUFFIX, ""))) {
                                bfi = (BlobstoreFileItem) i;
                                break;
                            }
                        }
                    }
                    if (bfi == null) {
                        bfi = new BlobstoreFileItem(e.getKey(), "unknown", false, "");
                        sessionFiles.add(bfi);
                    }
                    bfi.setKey(blob);
                    logger.info("BLOB-STORE-SERVLET: received file: " + e.getKey() + " " + bfi);
                }
            }
            redirect(response, null);
        } else {
            redirect(response, PARAM_ERROR + "=" + getMessage("no_data"));
        }

        perThreadRequest.set(null);
    }

    /**
     * User can override this for customization.
     */
    public String executeAction(HttpServletRequest request, List<FileItem> sessionFiles)
            throws UploadActionException {
        // Let the user whether remove or not file items overriding this method
        removeSessionFileItems(request, false);
        return null;
    }

    protected void redirect(HttpServletResponse response, String params) throws IOException {
        String url = servletPath + "?" + PARAM_REDIRECT + "=true"
                + (params != null ? "&" + params.replaceAll("[\n\r]+", " ") : "");
        logger.info("BLOB-STORE-SERVLET: redirecting to -> : " + url);
        response.sendRedirect(url);
    }

    protected String getBlobstorePath(HttpServletRequest request) {
        String ret = blobstoreService.createUploadUrl(servletPath);
        logger.info("BLOB-STORE-SERVLET: generated new upload-url -> " + servletPath + " : " + ret);
        ret = ret.replaceFirst("^https?://[^/]+", "");
        return ret;
    }

    @Override
    protected final AbstractUploadListener getCurrentListener(HttpServletRequest request) {
        return MemCacheUploadListener.current(request.getSession().getId());
    }

    @Override
    protected final FileItemFactory getFileItemFactory(long requestSize) {
        return new BlobstoreFileItemFactory();
    }
}