001    /**
002     * Copyright (c) 2000-present 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    
055                    long totalSize = request.getContentLength();
056    
057                    if (totalSize < 0) {
058                            totalSize = GetterUtil.getLong(
059                                    request.getHeader(HttpHeaders.CONTENT_LENGTH), totalSize);
060                    }
061    
062                    _totalSize = totalSize;
063    
064                    boolean createTempFile = GetterUtil.getBoolean(
065                            request.getAttribute(
066                                    UploadServletRequestFilter.COPY_MULTIPART_STREAM_TO_FILE),
067                            Boolean.TRUE);
068    
069                    if ((_totalSize >= THRESHOLD_SIZE) && createTempFile) {
070                            _tempFile = FileUtil.createTempFile();
071                    }
072                    else {
073                            _tempFile = null;
074    
075                            request.removeAttribute(
076                                    UploadServletRequestFilter.COPY_MULTIPART_STREAM_TO_FILE);
077                    }
078            }
079    
080            public void cleanUp() {
081                    if (_tempFile != null) {
082                            if (_tempFileOutputStream != null) {
083                                    try {
084                                            _tempFileOutputStream.close();
085                                    }
086                                    catch (IOException ioe) {
087                                            if (_log.isWarnEnabled()) {
088                                                    _log.warn(ioe, ioe);
089                                            }
090                                    }
091                            }
092    
093                            _tempFile.delete();
094                    }
095            }
096    
097            @Override
098            public void close() throws IOException {
099                    super.close();
100    
101                    if (_tempFileOutputStream != null) {
102                            _tempFileOutputStream.close();
103                    }
104            }
105    
106            public ServletInputStream getCachedInputStream() throws IOException {
107                    if (_totalSize < THRESHOLD_SIZE) {
108                            return new ServletInputStreamAdapter(
109                                    new UnsyncByteArrayInputStream(
110                                            _cachedBytes.unsafeGetByteArray(), 0, _cachedBytes.size()));
111                    }
112                    else if (_tempFile != null) {
113                            return new ServletInputStreamAdapter(
114                                    new FileInputStream(_tempFile));
115                    }
116                    else {
117                            return this;
118                    }
119            }
120    
121            @Override
122            public int read(byte[] b, int off, int len) throws IOException {
123                    int bytesRead = super.read(b, off, len);
124    
125                    if (bytesRead > 0) {
126                            _totalRead += bytesRead;
127                    }
128                    else {
129                            return bytesRead;
130                    }
131    
132                    int percent = (int)((_totalRead * 100L) / _totalSize);
133    
134                    if (_log.isDebugEnabled()) {
135                            _log.debug(bytesRead + "/" + _totalRead + "=" + percent);
136                    }
137    
138                    if (_totalSize > 0) {
139                            if (_totalSize < THRESHOLD_SIZE) {
140                                    _cachedBytes.write(b, off, bytesRead);
141                            }
142                            else {
143                                    _writeToTempFile(b, off, bytesRead);
144                            }
145                    }
146    
147                    ProgressTracker progressTracker =
148                            (ProgressTracker)_session.getAttribute(ProgressTracker.PERCENT);
149    
150                    Integer curPercent = null;
151    
152                    if (progressTracker != null) {
153                            curPercent = progressTracker.getPercent();
154                    }
155    
156                    if ((curPercent == null) || ((percent - curPercent.intValue()) >= 1)) {
157                            if (progressTracker == null) {
158                                    progressTracker = new ProgressTracker(StringPool.BLANK);
159    
160                                    progressTracker.initialize(_session);
161                            }
162    
163                            progressTracker.setPercent(percent);
164                    }
165    
166                    return bytesRead;
167            }
168    
169            private void _writeToTempFile(byte[] b, int off, int bytesRead)
170                    throws IOException {
171    
172                    if ((_tempFile != null) && (bytesRead > 0)) {
173                            if (_tempFileOutputStream == null) {
174                                    _tempFileOutputStream = new FileOutputStream(_tempFile, true);
175                            }
176    
177                            _tempFileOutputStream.write(b, off, bytesRead);
178                    }
179            }
180    
181            private static final Log _log = LogFactoryUtil.getLog(
182                    LiferayInputStream.class);
183    
184            private final UnsyncByteArrayOutputStream _cachedBytes =
185                    new UnsyncByteArrayOutputStream();
186            private final HttpSession _session;
187            private final File _tempFile;
188            private OutputStream _tempFileOutputStream;
189            private long _totalRead;
190            private final long _totalSize;
191    
192    }