001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.upload;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
018    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.servlet.HttpHeaders;
022    import com.liferay.portal.kernel.servlet.ServletInputStreamAdapter;
023    import com.liferay.portal.kernel.util.FileUtil;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.ProgressTracker;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.servlet.filters.uploadservletrequest.UploadServletRequestFilter;
028    import com.liferay.portal.util.PropsUtil;
029    
030    import java.io.File;
031    import java.io.FileInputStream;
032    import java.io.FileOutputStream;
033    import java.io.IOException;
034    import java.io.OutputStream;
035    
036    import javax.servlet.ServletInputStream;
037    import javax.servlet.http.HttpServletRequest;
038    import javax.servlet.http.HttpSession;
039    
040    /**
041     * @author Brian Myunghun Kim
042     * @author Brian Wing Shun Chan
043     * @author Harry Mark
044     */
045    public class LiferayInputStream extends ServletInputStreamAdapter {
046    
047            public static final long THRESHOLD_SIZE = GetterUtil.getLong(
048                    PropsUtil.get(LiferayInputStream.class.getName() + ".threshold.size"));
049    
050            public LiferayInputStream(HttpServletRequest request) throws IOException {
051                    super(request.getInputStream());
052    
053                    _session = request.getSession();
054                    _totalSize = request.getContentLength();
055    
056                    if (_totalSize < 0) {
057                            _totalSize = GetterUtil.getLong(
058                                    request.getHeader(HttpHeaders.CONTENT_LENGTH), _totalSize);
059                    }
060    
061                    boolean createTempFile = GetterUtil.getBoolean(
062                            request.getAttribute(
063                                    UploadServletRequestFilter.COPY_MULTIPART_STREAM_TO_FILE),
064                                    Boolean.TRUE);
065    
066                    if ((_totalSize >= THRESHOLD_SIZE) && createTempFile) {
067                            _tempFile = FileUtil.createTempFile();
068                    }
069                    else {
070                            _tempFile = null;
071    
072                            request.removeAttribute(
073                                    UploadServletRequestFilter.COPY_MULTIPART_STREAM_TO_FILE);
074                    }
075            }
076    
077            public void cleanUp() {
078                    if (_tempFile != null) {
079                            if (_tempFileOutputStream != null) {
080                                    try {
081                                            _tempFileOutputStream.close();
082                                    }
083                                    catch (IOException ioe) {
084                                            if (_log.isWarnEnabled()) {
085                                                    _log.warn(ioe, ioe);
086                                            }
087                                    }
088                            }
089    
090                            _tempFile.delete();
091                    }
092            }
093    
094            @Override
095            public void close() throws IOException {
096                    super.close();
097    
098                    if (_tempFileOutputStream != null) {
099                            _tempFileOutputStream.close();
100                    }
101            }
102    
103            public ServletInputStream getCachedInputStream() throws IOException {
104                    if (_totalSize < THRESHOLD_SIZE) {
105                            return new ServletInputStreamAdapter(
106                                    new UnsyncByteArrayInputStream(
107                                            _cachedBytes.unsafeGetByteArray(), 0, _cachedBytes.size()));
108                    }
109                    else if (_tempFile != null) {
110                            return new ServletInputStreamAdapter(
111                                    new FileInputStream(_tempFile));
112                    }
113                    else {
114                            return this;
115                    }
116            }
117    
118            @Override
119            public int read(byte[] b, int off, int len) throws IOException {
120                    int bytesRead = super.read(b, off, len);
121    
122                    if (bytesRead > 0) {
123                            _totalRead += bytesRead;
124                    }
125                    else {
126                            return bytesRead;
127                    }
128    
129                    int percent = (int)((_totalRead * 100L) / _totalSize);
130    
131                    if (_log.isDebugEnabled()) {
132                            _log.debug(bytesRead + "/" + _totalRead + "=" + percent);
133                    }
134    
135                    if (_totalSize > 0) {
136                            if (_totalSize < THRESHOLD_SIZE) {
137                                    _cachedBytes.write(b, off, bytesRead);
138                            }
139                            else {
140                                    _writeToTempFile(b, off, bytesRead);
141                            }
142                    }
143    
144                    ProgressTracker progressTracker =
145                            (ProgressTracker)_session.getAttribute(LiferayFileUpload.PERCENT);
146    
147                    Integer curPercent = null;
148    
149                    if (progressTracker != null) {
150                            curPercent = progressTracker.getPercent();
151                    }
152    
153                    if ((curPercent == null) || ((percent - curPercent.intValue()) >= 1)) {
154                            if (progressTracker == null) {
155                                    progressTracker = new ProgressTracker(StringPool.BLANK);
156    
157                                    progressTracker.initialize(_session);
158                            }
159    
160                            progressTracker.setPercent(percent);
161                    }
162    
163                    return bytesRead;
164            }
165    
166            private void _writeToTempFile(byte[] b, int off, int bytesRead)
167                    throws IOException {
168    
169                    if ((_tempFile != null) && (bytesRead > 0)) {
170                            if (_tempFileOutputStream == null) {
171                                    _tempFileOutputStream = new FileOutputStream(_tempFile, true);
172                            }
173    
174                            _tempFileOutputStream.write(b, off, bytesRead);
175                    }
176            }
177    
178            private static Log _log = LogFactoryUtil.getLog(LiferayInputStream.class);
179    
180            private UnsyncByteArrayOutputStream _cachedBytes =
181                    new UnsyncByteArrayOutputStream();
182            private final HttpSession _session;
183            private final File _tempFile;
184            private OutputStream _tempFileOutputStream;
185            private long _totalRead;
186            private long _totalSize;
187    
188    }