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