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