001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.upload;
029
030import org.opencms.gwt.shared.CmsUploadProgessInfo;
031import org.opencms.gwt.shared.CmsUploadProgessInfo.UPLOAD_STATE;
032import org.opencms.main.CmsLog;
033import org.opencms.util.CmsUUID;
034
035import java.io.Serializable;
036
037import org.apache.commons.fileupload.ProgressListener;
038import org.apache.commons.logging.Log;
039
040/**
041 * Provides the upload listener for the upload widget.<p>
042 *
043 * @since 8.0.0
044 */
045public class CmsUploadListener implements ProgressListener, Serializable {
046
047    /** The log object for this class. */
048    private static final Log LOG = CmsLog.getLog(CmsUploadListener.class);
049
050    /** The serial version id. */
051    private static final long serialVersionUID = -6431275569719042836L;
052
053    /** The content length of the request (larger than the sum of file sizes). */
054    protected long m_contentLength;
055
056    /** Stores the exception if one has been occurred. */
057    protected RuntimeException m_exception;
058
059    /** Signals that there occurred an exception before. */
060    protected boolean m_exceptionTrhown;
061
062    /** The bytes read so far. */
063    private long m_bytesRead;
064
065    /** The upload delay. */
066    private int m_delay;
067
068    /** A flag that signals if the upload is finished. */
069    private boolean m_finished;
070
071    /** The UUID for this listener. */
072    private CmsUUID m_id;
073
074    /** Stores the current item. */
075    private int m_item;
076
077    /** The timeout watch dog for this listener. */
078    private CmsUploadTimeoutWatcher m_watcher;
079
080    /**
081     * The public constructor for the listener.<p>
082     *
083     * @param requestSize content length of the request (larger than the sum of file sizes)
084     */
085    public CmsUploadListener(int requestSize) {
086
087        m_id = new CmsUUID();
088        m_contentLength = Long.valueOf(requestSize).longValue();
089        startWatcher();
090    }
091
092    /**
093     * Sets the exception that should cancel the upload on the next update.<p>
094     *
095     * @param e the exception
096     */
097    public void cancelUpload(CmsUploadException e) {
098
099        m_exception = e;
100    }
101
102    /**
103     * Returns the bytes transfered so far.<p>
104     *
105     * @return the bytes transfered so far
106     */
107    public long getBytesRead() {
108
109        return m_bytesRead;
110    }
111
112    /**
113     * Returns the content length of the request (larger than the sum of file sizes).<p>
114     *
115     * @return the content length of the request (larger than the sum of file sizes)
116     */
117    public long getContentLength() {
118
119        return m_contentLength;
120    }
121
122    /**
123     * Returns the exception.<p>
124     *
125     * @return the exception
126     */
127    public RuntimeException getException() {
128
129        return m_exception;
130    }
131
132    /**
133     * Returns the listeners UUID.<p>
134     *
135     * @return the listeners UUID
136     */
137    public CmsUUID getId() {
138
139        return m_id;
140    }
141
142    /**
143     * Returns the current progress info of the upload.<p>
144     *
145     * @return the progress info
146     */
147    public CmsUploadProgessInfo getInfo() {
148
149        if (m_finished) {
150            return new CmsUploadProgessInfo(
151                getItem(),
152                (int)getPercent(),
153                UPLOAD_STATE.finished,
154                getContentLength(),
155                getBytesRead());
156        }
157        return new CmsUploadProgessInfo(
158            getItem(),
159            (int)getPercent(),
160            UPLOAD_STATE.running,
161            getContentLength(),
162            getBytesRead());
163    }
164
165    /**
166     * Returns the number of the field, which is currently being read.<p>
167     * <ul>
168     * <li>0 = no item so far
169     * <li>1 = first item is being read, ...
170     * </ul>
171
172     * @return the number of the field, which is currently being read.
173     */
174    public int getItem() {
175
176        return m_item;
177    }
178
179    /**
180     * Returns the percent done of the current upload.<p>
181     *
182     * @return the percent done of the current upload
183     */
184    public long getPercent() {
185
186        return m_contentLength != 0 ? (m_bytesRead * 100) / m_contentLength : 0;
187    }
188
189    /**
190     * Returns <code>true</code> if the process has been canceled due to an error or by the user.<p>
191     *
192     * @return boolean<code>true</code> if the process has been canceled due to an error or by the user
193     */
194    public boolean isCanceled() {
195
196        return m_exception != null;
197    }
198
199    /**
200     * Returns the finished.<p>
201     *
202     * @return the finished
203     */
204    public boolean isFinished() {
205
206        return m_finished;
207    }
208
209    /**
210     * Sets the delay.<p>
211     *
212     * @param delay the delay to set
213     */
214    public void setDelay(int delay) {
215
216        m_delay = delay;
217    }
218
219    /**
220     * Sets the finished.<p>
221     *
222     * @param finished the finished to set
223     */
224    public void setFinished(boolean finished) {
225
226        m_finished = finished;
227    }
228
229    /**
230     * @see java.lang.Object#toString()
231     */
232    @Override
233    public String toString() {
234
235        return "UUID="
236            + getId()
237            + " total="
238            + getContentLength()
239            + " done="
240            + getBytesRead()
241            + " cancelled="
242            + isCanceled();
243    }
244
245    /**
246     * Updates the listeners status information and does the following steps:
247     * <ul>
248     * <li> returns if there was already thrown an exception before
249     * <li> sets the local variables to the current upload state
250     * <li> throws an RuntimeException if it was set in the meanwhile (by another request e.g. user has canceled)
251     * <li> slows down the upload process if it's configured
252     * <li> stops the watcher if the upload has reached more than 100 percent
253     * </ul>
254     *
255     * @see org.apache.commons.fileupload.ProgressListener#update(long, long, int)
256     */
257    public void update(long done, long total, int item) {
258
259        if (m_exceptionTrhown) {
260            return;
261        }
262
263        m_bytesRead = done;
264        m_contentLength = total;
265        m_item = item;
266
267        // If an other request has set an exception, it is thrown so the commons-fileupload's
268        // parser stops and the connection is closed.
269        if (isCanceled()) {
270            m_exceptionTrhown = true;
271            throw m_exception;
272        }
273
274        // Just a way to slow down the upload process and see the progress bar in fast networks.
275        if ((m_delay > 0) && (done < total)) {
276            try {
277                Thread.sleep(m_delay);
278            } catch (Exception e) {
279                m_exception = new RuntimeException(e);
280            }
281        }
282        if (getPercent() >= 100) {
283            stopWatcher();
284        }
285    }
286
287    /**
288     * Starts the watcher.<p>
289     */
290    private void startWatcher() {
291
292        if (m_watcher == null) {
293            try {
294                m_watcher = new CmsUploadTimeoutWatcher(this);
295                m_watcher.start();
296            } catch (Exception e) {
297                LOG.info(
298                    Messages.get().getBundle().key(Messages.LOG_UPLOAD_CREATE_WATCH_DOG_2, getId(), e.getMessage()));
299            }
300        }
301    }
302
303    /**
304     * Stops the watcher.<p>
305     */
306    private void stopWatcher() {
307
308        if (m_watcher != null) {
309            m_watcher.cancel();
310        }
311    }
312}