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.portlet.imageuploader.action;
016    
017    import com.liferay.portal.ImageTypeException;
018    import com.liferay.portal.NoSuchRepositoryException;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.flash.FlashMagicBytesUtil;
021    import com.liferay.portal.kernel.image.ImageBag;
022    import com.liferay.portal.kernel.image.ImageToolUtil;
023    import com.liferay.portal.kernel.json.JSONFactoryUtil;
024    import com.liferay.portal.kernel.json.JSONObject;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.portlet.PortletResponseUtil;
028    import com.liferay.portal.kernel.repository.model.FileEntry;
029    import com.liferay.portal.kernel.servlet.SessionErrors;
030    import com.liferay.portal.kernel.servlet.SessionMessages;
031    import com.liferay.portal.kernel.upload.UploadException;
032    import com.liferay.portal.kernel.upload.UploadPortletRequest;
033    import com.liferay.portal.kernel.upload.UploadRequestSizeException;
034    import com.liferay.portal.kernel.util.Constants;
035    import com.liferay.portal.kernel.util.ContentTypes;
036    import com.liferay.portal.kernel.util.FileUtil;
037    import com.liferay.portal.kernel.util.MimeTypesUtil;
038    import com.liferay.portal.kernel.util.ParamUtil;
039    import com.liferay.portal.kernel.util.PropsKeys;
040    import com.liferay.portal.kernel.util.StreamUtil;
041    import com.liferay.portal.kernel.util.StringPool;
042    import com.liferay.portal.kernel.util.StringUtil;
043    import com.liferay.portal.kernel.util.TempFileEntryUtil;
044    import com.liferay.portal.kernel.util.TextFormatter;
045    import com.liferay.portal.kernel.util.Validator;
046    import com.liferay.portal.kernel.util.WebKeys;
047    import com.liferay.portal.security.auth.PrincipalException;
048    import com.liferay.portal.struts.PortletAction;
049    import com.liferay.portal.theme.ThemeDisplay;
050    import com.liferay.portal.util.PortalUtil;
051    import com.liferay.portal.util.PrefsPropsUtil;
052    import com.liferay.portal.util.PropsValues;
053    import com.liferay.portlet.documentlibrary.FileExtensionException;
054    import com.liferay.portlet.documentlibrary.FileSizeException;
055    import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
056    import com.liferay.portlet.documentlibrary.NoSuchFileException;
057    import com.liferay.portlet.documentlibrary.antivirus.AntivirusScannerException;
058    
059    import java.awt.image.RenderedImage;
060    
061    import java.io.File;
062    import java.io.InputStream;
063    
064    import javax.portlet.ActionRequest;
065    import javax.portlet.ActionResponse;
066    import javax.portlet.MimeResponse;
067    import javax.portlet.PortletConfig;
068    import javax.portlet.PortletRequest;
069    import javax.portlet.RenderRequest;
070    import javax.portlet.RenderResponse;
071    import javax.portlet.ResourceRequest;
072    import javax.portlet.ResourceResponse;
073    
074    import org.apache.struts.action.ActionForm;
075    import org.apache.struts.action.ActionForward;
076    import org.apache.struts.action.ActionMapping;
077    
078    /**
079     * @author Brian Wing Shun Chan
080     * @author Tibor Lipusz
081     */
082    public class UploadImageAction extends PortletAction {
083    
084            @Override
085            public void processAction(
086                            ActionMapping actionMapping, ActionForm actionForm,
087                            PortletConfig portletConfig, ActionRequest actionRequest,
088                            ActionResponse actionResponse)
089                    throws Exception {
090    
091                    String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
092    
093                    long maxFileSize = ParamUtil.getLong(actionRequest, "maxFileSize");
094    
095                    try {
096                            UploadException uploadException =
097                                    (UploadException)actionRequest.getAttribute(
098                                            WebKeys.UPLOAD_EXCEPTION);
099    
100                            if (uploadException != null) {
101                                    Throwable cause = uploadException.getCause();
102    
103                                    if (uploadException.isExceededFileSizeLimit()) {
104                                            throw new FileSizeException(cause);
105                                    }
106    
107                                    if (uploadException.isExceededUploadRequestSizeLimit()) {
108                                            throw new UploadRequestSizeException(cause);
109                                    }
110    
111                                    throw new PortalException(cause);
112                            }
113                            else if (cmd.equals(Constants.ADD_TEMP)) {
114                                    FileEntry tempImageFileEntry = addTempImageFileEntry(
115                                            actionRequest);
116    
117                                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
118    
119                                    jsonObject.put(
120                                            "tempImageFileName", tempImageFileEntry.getTitle());
121    
122                                    writeJSON(actionRequest, actionResponse, jsonObject);
123                            }
124                            else {
125                                    FileEntry fileEntry = null;
126    
127                                    boolean imageUploaded = ParamUtil.getBoolean(
128                                            actionRequest, "imageUploaded");
129    
130                                    if (imageUploaded) {
131                                            fileEntry = saveTempImageFileEntry(actionRequest);
132    
133                                            if (fileEntry.getSize() > maxFileSize) {
134                                                    throw new FileSizeException();
135                                            }
136                                    }
137    
138                                    SessionMessages.add(actionRequest, "imageUploaded", fileEntry);
139    
140                                    sendRedirect(actionRequest, actionResponse);
141                            }
142                    }
143                    catch (Exception e) {
144                            handleUploadException(
145                                    actionRequest, actionResponse, cmd, maxFileSize, e);
146                    }
147            }
148    
149            @Override
150            public ActionForward render(
151                            ActionMapping actionMapping, ActionForm actionForm,
152                            PortletConfig portletConfig, RenderRequest renderRequest,
153                            RenderResponse renderResponse)
154                    throws Exception {
155    
156                    return actionMapping.findForward(
157                            getForward(renderRequest, "portlet.image_uploader.view"));
158            }
159    
160            @Override
161            public void serveResource(
162                            ActionMapping actionMapping, ActionForm actionForm,
163                            PortletConfig portletConfig, ResourceRequest resourceRequest,
164                            ResourceResponse resourceResponse)
165                    throws Exception {
166    
167                    try {
168                            String cmd = ParamUtil.getString(resourceRequest, Constants.CMD);
169    
170                            if (cmd.equals(Constants.GET_TEMP)) {
171                                    FileEntry tempFileEntry = getTempImageFileEntry(
172                                            resourceRequest);
173    
174                                    FlashMagicBytesUtil.Result flashMagicBytesUtilResult =
175                                            FlashMagicBytesUtil.check(tempFileEntry.getContentStream());
176    
177                                    if (flashMagicBytesUtilResult.isFlash()) {
178                                            return;
179                                    }
180    
181                                    serveTempImageFile(
182                                            resourceResponse,
183                                            flashMagicBytesUtilResult.getInputStream());
184                            }
185                    }
186                    catch (NoSuchFileEntryException nsfee) {
187                    }
188                    catch (Exception e) {
189                            _log.error(e);
190                    }
191            }
192    
193            protected FileEntry addTempImageFileEntry(PortletRequest portletRequest)
194                    throws Exception {
195    
196                    UploadPortletRequest uploadPortletRequest =
197                            PortalUtil.getUploadPortletRequest(portletRequest);
198    
199                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
200                            WebKeys.THEME_DISPLAY);
201    
202                    String contentType = uploadPortletRequest.getContentType("fileName");
203    
204                    String fileName = uploadPortletRequest.getFileName("fileName");
205    
206                    File file = uploadPortletRequest.getFile("fileName");
207    
208                    String mimeType = MimeTypesUtil.getContentType(file, fileName);
209    
210                    if (!StringUtil.equalsIgnoreCase(
211                                    ContentTypes.APPLICATION_OCTET_STREAM, mimeType)) {
212    
213                            contentType = mimeType;
214                    }
215    
216                    if (!MimeTypesUtil.isWebImage(contentType)) {
217                            throw new ImageTypeException();
218                    }
219    
220                    try {
221                            TempFileEntryUtil.deleteTempFileEntry(
222                                    themeDisplay.getScopeGroupId(), themeDisplay.getUserId(),
223                                    getTempImageFolderName(), fileName);
224                    }
225                    catch (Exception e) {
226                    }
227    
228                    return TempFileEntryUtil.addTempFileEntry(
229                            themeDisplay.getScopeGroupId(), themeDisplay.getUserId(),
230                            getTempImageFolderName(), fileName, file, contentType);
231            }
232    
233            protected FileEntry getTempImageFileEntry(PortletRequest portletRequest)
234                    throws PortalException {
235    
236                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
237                            WebKeys.THEME_DISPLAY);
238    
239                    return TempFileEntryUtil.getTempFileEntry(
240                            themeDisplay.getScopeGroupId(), themeDisplay.getUserId(),
241                            getTempImageFolderName(), getTempImageFileName(portletRequest));
242            }
243    
244            protected String getTempImageFileName(PortletRequest portletRequest) {
245                    return ParamUtil.getString(portletRequest, "tempImageFileName");
246            }
247    
248            protected String getTempImageFolderName() {
249                    Class<?> clazz = getClass();
250    
251                    return clazz.getName();
252            }
253    
254            protected void handleUploadException(
255                            ActionRequest actionRequest, ActionResponse actionResponse,
256                            String cmd, long maxFileSize, Exception e)
257                    throws Exception {
258    
259                    if (e instanceof PrincipalException) {
260                            SessionErrors.add(actionRequest, e.getClass());
261    
262                            setForward(actionRequest, "portal.error");
263                    }
264                    else if (e instanceof AntivirusScannerException ||
265                                     e instanceof FileExtensionException ||
266                                     e instanceof FileSizeException ||
267                                     e instanceof ImageTypeException ||
268                                     e instanceof NoSuchFileException ||
269                                     e instanceof UploadException ||
270                                     e instanceof UploadRequestSizeException) {
271    
272                            if (cmd.equals(Constants.ADD_TEMP)) {
273                                    hideDefaultErrorMessage(actionRequest);
274    
275                                    ThemeDisplay themeDisplay =
276                                            (ThemeDisplay)actionRequest.getAttribute(
277                                                    WebKeys.THEME_DISPLAY);
278    
279                                    String errorMessage = StringPool.BLANK;
280    
281                                    if (e instanceof AntivirusScannerException) {
282                                            AntivirusScannerException ase =
283                                                    (AntivirusScannerException)e;
284    
285                                            errorMessage = themeDisplay.translate(ase.getMessageKey());
286                                    }
287                                    else if (e instanceof FileExtensionException) {
288                                            errorMessage = themeDisplay.translate(
289                                                    "please-enter-a-file-with-a-valid-extension-x",
290                                                    StringUtil.merge(
291                                                            PropsValues.DL_FILE_EXTENSIONS, StringPool.COMMA));
292                                    }
293                                    else if (e instanceof FileSizeException) {
294                                            if (maxFileSize == 0) {
295                                                    maxFileSize = PrefsPropsUtil.getLong(
296                                                            PropsKeys.UPLOAD_SERVLET_REQUEST_IMPL_MAX_SIZE);
297                                            }
298    
299                                            errorMessage = themeDisplay.translate(
300                                                    "please-enter-a-file-with-a-valid-file-size-no" +
301                                                            "-larger-than-x",
302                                                    TextFormatter.formatStorageSize(
303                                                            maxFileSize, themeDisplay.getLocale()));
304                                    }
305                                    else if (e instanceof ImageTypeException) {
306                                            errorMessage = themeDisplay.translate(
307                                                    "please-enter-a-file-with-a-valid-file-type");
308                                    }
309                                    else if (e instanceof NoSuchFileException ||
310                                                     e instanceof UploadException) {
311    
312                                            errorMessage = themeDisplay.translate(
313                                                    "an-unexpected-error-occurred-while-uploading" +
314                                                            "-your-file");
315                                    }
316    
317                                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
318    
319                                    jsonObject.put("errorMessage", errorMessage);
320    
321                                    writeJSON(actionRequest, actionResponse, jsonObject);
322                            }
323                            else {
324                                    SessionErrors.add(actionRequest, e.getClass(), e);
325                            }
326                    }
327                    else {
328                            throw e;
329                    }
330            }
331    
332            protected FileEntry saveTempImageFileEntry(ActionRequest actionRequest)
333                    throws Exception {
334    
335                    FileEntry tempFileEntry = null;
336    
337                    InputStream tempImageStream = null;
338    
339                    try {
340                            tempFileEntry = getTempImageFileEntry(actionRequest);
341    
342                            tempImageStream = tempFileEntry.getContentStream();
343    
344                            ImageBag imageBag = ImageToolUtil.read(tempImageStream);
345    
346                            RenderedImage renderedImage = imageBag.getRenderedImage();
347    
348                            String cropRegionJSON = ParamUtil.getString(
349                                    actionRequest, "cropRegion");
350    
351                            if (Validator.isNotNull(cropRegionJSON)) {
352                                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
353                                            cropRegionJSON);
354    
355                                    int height = jsonObject.getInt("height");
356                                    int width = jsonObject.getInt("width");
357                                    int x = jsonObject.getInt("x");
358                                    int y = jsonObject.getInt("y");
359    
360                                    if ((x == 0) && (y == 0) &&
361                                            (renderedImage.getHeight() == height) &&
362                                            (renderedImage.getWidth() == width)) {
363    
364                                            return tempFileEntry;
365                                    }
366    
367                                    if ((height + y) > renderedImage.getHeight()) {
368                                            height = renderedImage.getHeight() - y;
369                                    }
370    
371                                    if ((width + x) > renderedImage.getWidth()) {
372                                            width = renderedImage.getWidth() - x;
373                                    }
374    
375                                    renderedImage = ImageToolUtil.crop(
376                                            renderedImage, height, width, x, y);
377                            }
378    
379                            byte[] bytes = ImageToolUtil.getBytes(
380                                    renderedImage, imageBag.getType());
381    
382                            ThemeDisplay themeDisplay =
383                                    (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
384    
385                            File file = FileUtil.createTempFile(bytes);
386    
387                            try {
388                                    TempFileEntryUtil.deleteTempFileEntry(
389                                            themeDisplay.getScopeGroupId(), themeDisplay.getUserId(),
390                                            getTempImageFolderName(),
391                                            getTempImageFileName(actionRequest));
392                            }
393                            catch (Exception e) {
394                            }
395    
396                            return TempFileEntryUtil.addTempFileEntry(
397                                    themeDisplay.getScopeGroupId(), themeDisplay.getUserId(),
398                                    getTempImageFolderName(), getTempImageFileName(actionRequest),
399                                    file, tempFileEntry.getMimeType());
400                    }
401                    catch (NoSuchFileEntryException nsfee) {
402                            throw new UploadException(nsfee);
403                    }
404                    catch (NoSuchRepositoryException nsre) {
405                            throw new UploadException(nsre);
406                    }
407                    finally {
408                            StreamUtil.cleanUp(tempImageStream);
409                    }
410            }
411    
412            protected void serveTempImageFile(
413                            MimeResponse mimeResponse, InputStream tempImageStream)
414                    throws Exception {
415    
416                    ImageBag imageBag = ImageToolUtil.read(tempImageStream);
417    
418                    byte[] bytes = ImageToolUtil.getBytes(
419                            imageBag.getRenderedImage(), imageBag.getType());
420    
421                    String contentType = MimeTypesUtil.getExtensionContentType(
422                            imageBag.getType());
423    
424                    mimeResponse.setContentType(contentType);
425    
426                    PortletResponseUtil.write(mimeResponse, bytes);
427            }
428    
429            private static final Log _log = LogFactoryUtil.getLog(
430                    UploadImageAction.class);
431    
432    }