/* * Copyright 2010 Manuel Carrasco Moñino. (manolo at apache/org) * 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; import java.io.Serializable; import java.util.Date; import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.ProgressListener; /** * * Abstract class for file upload listeners used by apache-commons-fileupload to monitor * the progress of uploaded files. * * It is useful to implement UploadListeners that can be saved in different * ways. * * @author Manolo Carrasco Moñino * */ public abstract class AbstractUploadListener implements ProgressListener, Serializable { protected static String className = AbstractUploadListener.class.getName().replaceAll("^.+\\.", ""); protected static int DEFAULT_SAVE_INTERVAL = 3000; protected static UploadLogger logger = UploadLogger.getLogger(AbstractUploadListener.class); protected static final long serialVersionUID = -6431275569719042836L; public static AbstractUploadListener current(String sessionId) { throw new RuntimeException("Implement the static method 'current' in your customized class"); } protected Long bytesRead = 0L, contentLength = 0L; protected RuntimeException exception = null; protected boolean exceptionTrhown = false; private String postResponse = null; protected int frozenTimeout = 60000; protected Date saved = new Date(); protected String sessionId = ""; protected int slowUploads = 0; public AbstractUploadListener(int sleepMilliseconds, long requestSize) { this(); slowUploads = sleepMilliseconds; contentLength = requestSize; logger.info(className + " " + sessionId + " created new instance. (slow=" + sleepMilliseconds + ", requestSize=" + requestSize + ")"); HttpServletRequest request = UploadServlet.getThreadLocalRequest(); if (request != null) { sessionId = request.getSession().getId(); } save(); } private AbstractUploadListener() { className = this.getClass().getName().replaceAll("^.+\\.", ""); logger = UploadLogger.getLogger(this.getClass()); } /** * Get the bytes transfered so far. * * @return bytes */ public long getBytesRead() { return bytesRead; } /** * Get the total bytes of the request. * * @return bytes */ public long getContentLength() { return contentLength; } /** * Get the exception. * */ public RuntimeException getException() { return exception; } /** * Return the percent done of the current upload. * * @return percent */ public long getPercent() { return contentLength != 0 ? bytesRead * 100 / contentLength : 0; } /** * Return true if the process has been canceled due to an error or * by the user. * * @return boolean */ public boolean isCanceled() { return exception != null; } public boolean isFinished() { return postResponse != null; } /** * Return true if has lasted a long since the last data received. * by the user. * * @return boolean */ public boolean isFrozen() { return getPercent() > 0 && getPercent() < 100 && (new Date()).getTime() - saved.getTime() > frozenTimeout; } /** * Remove itself from session or cache. */ public abstract void remove(); /** * Save itself in session or cache. */ public abstract void save(); /** * Set the exception which cancels the upload. * */ public void setException(RuntimeException e) { exception = e; save(); } public void setFinished(String postResponse) { this.postResponse = postResponse; save(); } public String toString() { return "total=" + getContentLength() + " done=" + getBytesRead() + " cancelled=" + isCanceled() + " finished=" + isFinished() + " saved=" + saved; } /** * This method is called each time the server receives a block of bytes. */ public void update(long done, long total, int item) { if (exceptionTrhown) { return; } // To avoid cache overloading, this object is saved when the upload starts, // when it has finished, or when the interval from the last save is significant. boolean save = bytesRead == 0 && done > 0 || done >= total || (new Date()).getTime() - saved.getTime() > DEFAULT_SAVE_INTERVAL; bytesRead = done; contentLength = total; if (save) { save(); } // If other request has set an exception, it is thrown so the commons-fileupload's // parser stops and the connection is closed. if (isCanceled()) { String eName = exception.getClass().getName().replaceAll("^.+\\.", ""); logger.info(className + " " + sessionId + " The upload has been canceled after " + bytesRead + " bytes received, raising an exception (" + eName + ") to close the socket"); exceptionTrhown = true; throw exception; } // Just a way to slow down the upload process and see the progress bar in fast networks. if (slowUploads > 0 && done < total) { try { Thread.sleep(slowUploads); } catch (Exception e) { exception = new RuntimeException(e); } } } public String getPostResponse() { return postResponse; } }