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.portlet.documentlibrary.util;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.image.ImageBag;
020    import com.liferay.portal.kernel.image.ImageToolUtil;
021    import com.liferay.portal.kernel.lar.PortletDataContext;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.messaging.DestinationNames;
025    import com.liferay.portal.kernel.messaging.MessageBusException;
026    import com.liferay.portal.kernel.messaging.MessageBusUtil;
027    import com.liferay.portal.kernel.repository.model.FileEntry;
028    import com.liferay.portal.kernel.repository.model.FileVersion;
029    import com.liferay.portal.kernel.util.FileUtil;
030    import com.liferay.portal.kernel.util.SetUtil;
031    import com.liferay.portal.kernel.util.StreamUtil;
032    import com.liferay.portal.kernel.util.StringBundler;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.Validator;
035    import com.liferay.portal.kernel.xml.Element;
036    import com.liferay.portal.util.PropsValues;
037    import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
038    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
039    
040    import java.awt.image.RenderedImage;
041    
042    import java.io.File;
043    import java.io.FileOutputStream;
044    import java.io.InputStream;
045    
046    import java.util.List;
047    import java.util.Set;
048    import java.util.Vector;
049    
050    /**
051     * @author Sergio Gonz??lez
052     * @author Alexander Chow
053     */
054    public class ImageProcessorImpl
055            extends DLPreviewableProcessor implements ImageProcessor {
056    
057            @Override
058            public void afterPropertiesSet() {
059            }
060    
061            @Override
062            public void cleanUp(FileEntry fileEntry) {
063                    deleteFiles(fileEntry, null);
064            }
065    
066            @Override
067            public void cleanUp(FileVersion fileVersion) {
068                    String type = getThumbnailType(fileVersion);
069    
070                    deleteFiles(fileVersion, type);
071            }
072    
073            @Override
074            public void generateImages(FileVersion fileVersion) {
075                    _generateImages(fileVersion);
076            }
077    
078            @Override
079            public Set<String> getImageMimeTypes() {
080                    return _imageMimeTypes;
081            }
082    
083            @Override
084            public InputStream getPreviewAsStream(FileVersion fileVersion)
085                    throws Exception {
086    
087                    if (_previewGenerationRequired(fileVersion)) {
088                            String type = getPreviewType(fileVersion);
089    
090                            return doGetPreviewAsStream(fileVersion, type);
091                    }
092    
093                    return fileVersion.getContentStream(false);
094            }
095    
096            @Override
097            public long getPreviewFileSize(FileVersion fileVersion) throws Exception {
098                    if (_previewGenerationRequired(fileVersion)) {
099                            String type = getPreviewType(fileVersion);
100    
101                            return doGetPreviewFileSize(fileVersion, type);
102                    }
103    
104                    return fileVersion.getSize();
105            }
106    
107            @Override
108            public String getPreviewType(FileVersion fileVersion) {
109                    return _getType(fileVersion);
110            }
111    
112            @Override
113            public InputStream getThumbnailAsStream(FileVersion fileVersion, int index)
114                    throws Exception {
115    
116                    return doGetThumbnailAsStream(fileVersion, index);
117            }
118    
119            @Override
120            public long getThumbnailFileSize(FileVersion fileVersion, int index)
121                    throws Exception {
122    
123                    return doGetThumbnailFileSize(fileVersion, index);
124            }
125    
126            @Override
127            public String getThumbnailType(FileVersion fileVersion) {
128                    return _getType(fileVersion);
129            }
130    
131            @Override
132            public boolean hasImages(FileVersion fileVersion) {
133                    if (!PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
134                            !PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
135    
136                            return false;
137                    }
138    
139                    boolean hasImages = false;
140    
141                    try {
142                            if (_hasPreview(fileVersion) && hasThumbnails(fileVersion)) {
143                                    hasImages = true;
144                            }
145    
146                            if (!hasImages && isSupported(fileVersion)) {
147                                    _queueGeneration(fileVersion);
148                            }
149                    }
150                    catch (Exception e) {
151                            _log.error(e, e);
152                    }
153    
154                    return hasImages;
155            }
156    
157            @Override
158            public boolean isImageSupported(FileVersion fileVersion) {
159                    return isSupported(fileVersion);
160            }
161    
162            @Override
163            public boolean isImageSupported(String mimeType) {
164                    return isSupported(mimeType);
165            }
166    
167            @Override
168            public boolean isSupported(String mimeType) {
169                    if (Validator.isNull(mimeType)) {
170                            return false;
171                    }
172    
173                    return _imageMimeTypes.contains(mimeType);
174            }
175    
176            @Override
177            public void storeThumbnail(
178                            long companyId, long groupId, long fileEntryId, long fileVersionId,
179                            long custom1ImageId, long custom2ImageId, InputStream is,
180                            String type)
181                    throws Exception {
182    
183                    _storeThumbnail(
184                            companyId, groupId, fileEntryId, fileVersionId, custom1ImageId,
185                            custom2ImageId, is, type);
186            }
187    
188            @Override
189            public void trigger(FileVersion fileVersion) {
190                    _queueGeneration(fileVersion);
191            }
192    
193            @Override
194            protected void doExportGeneratedFiles(
195                            PortletDataContext portletDataContext, FileEntry fileEntry,
196                            Element fileEntryElement)
197                    throws Exception {
198    
199                    exportThumbnails(
200                            portletDataContext, fileEntry, fileEntryElement, "image");
201    
202                    exportPreview(portletDataContext, fileEntry, fileEntryElement);
203            }
204    
205            @Override
206            protected void doImportGeneratedFiles(
207                            PortletDataContext portletDataContext, FileEntry fileEntry,
208                            FileEntry importedFileEntry, Element fileEntryElement)
209                    throws Exception {
210    
211                    importThumbnails(
212                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
213                            "image");
214    
215                    FileVersion importedFileVersion = importedFileEntry.getFileVersion();
216    
217                    if (!_previewGenerationRequired(importedFileVersion)) {
218                            return;
219                    }
220    
221                    importPreview(
222                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
223                            "image", getPreviewType(importedFileVersion));
224            }
225    
226            protected void exportPreview(
227                            PortletDataContext portletDataContext, FileEntry fileEntry,
228                            Element fileEntryElement)
229                    throws Exception {
230    
231                    FileVersion fileVersion = fileEntry.getFileVersion();
232    
233                    if (!isSupported(fileVersion) ||
234                            !_previewGenerationRequired(fileVersion) ||
235                            !_hasPreview(fileVersion)) {
236    
237                            return;
238                    }
239    
240                    exportPreview(
241                            portletDataContext, fileEntry, fileEntryElement, "image",
242                            getPreviewType(fileVersion));
243            }
244    
245            private void _generateImages(FileVersion fileVersion) {
246                    InputStream inputStream = null;
247    
248                    try {
249                            if (!PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
250                                    !PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
251    
252                                    return;
253                            }
254    
255                            inputStream = fileVersion.getContentStream(false);
256    
257                            byte[] bytes = FileUtil.getBytes(inputStream);
258    
259                            ImageBag imageBag = ImageToolUtil.read(bytes);
260    
261                            RenderedImage renderedImage = imageBag.getRenderedImage();
262    
263                            if (renderedImage == null) {
264                                    return;
265                            }
266    
267                            if (!_hasPreview(fileVersion)) {
268                                    _storePreviewImage(fileVersion, renderedImage);
269                            }
270    
271                            if (!hasThumbnails(fileVersion)) {
272                                    storeThumbnailImages(fileVersion, renderedImage);
273                            }
274                    }
275                    catch (NoSuchFileEntryException nsfee) {
276                    }
277                    catch (Exception e) {
278                            _log.error(e, e);
279                    }
280                    finally {
281                            StreamUtil.cleanUp(inputStream);
282    
283                            _fileVersionIds.remove(fileVersion.getFileVersionId());
284                    }
285            }
286    
287            private String _getType(FileVersion fileVersion) {
288                    String type = "png";
289    
290                    if (fileVersion == null) {
291                            return type;
292                    }
293    
294                    String extension = fileVersion.getExtension();
295    
296                    if (extension.equals("jpeg")) {
297                            type = "jpg";
298                    }
299                    else if (!_previewGenerationRequired(fileVersion)) {
300                            type = extension;
301                    }
302    
303                    return type;
304            }
305    
306            private boolean _hasPreview(FileVersion fileVersion)
307                    throws PortalException, SystemException {
308    
309                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
310                            _previewGenerationRequired(fileVersion)) {
311    
312                            String type = getPreviewType(fileVersion);
313    
314                            String previewFilePath = getPreviewFilePath(fileVersion, type);
315    
316                            if (!DLStoreUtil.hasFile(
317                                            fileVersion.getCompanyId(), REPOSITORY_ID,
318                                            previewFilePath)) {
319    
320                                    return false;
321                            }
322                    }
323    
324                    return true;
325            }
326    
327            private boolean _previewGenerationRequired(FileVersion fileVersion) {
328                    String type = fileVersion.getExtension();
329    
330                    if (type.equals("tiff") || type.equals("tif")) {
331                            return true;
332                    }
333                    else {
334                            return false;
335                    }
336            }
337    
338            private void _queueGeneration(FileVersion fileVersion) {
339                    if (!_fileVersionIds.contains(fileVersion.getFileVersionId()) &&
340                            isSupported(fileVersion) && !hasThumbnails(fileVersion)) {
341    
342                            _fileVersionIds.add(fileVersion.getFileVersionId());
343    
344                            if (PropsValues.DL_FILE_ENTRY_PROCESSORS_TRIGGER_SYNCHRONOUSLY) {
345                                    try {
346                                            MessageBusUtil.sendSynchronousMessage(
347                                                    DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
348                                                    fileVersion);
349                                    }
350                                    catch (MessageBusException mbe) {
351                                            if (_log.isWarnEnabled()) {
352                                                    _log.warn(mbe, mbe);
353                                            }
354                                    }
355                            }
356                            else {
357                                    MessageBusUtil.sendMessage(
358                                            DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
359                                            fileVersion);
360                            }
361                    }
362            }
363    
364            private void _storePreviewImage(
365                            FileVersion fileVersion, RenderedImage renderedImage)
366                    throws Exception {
367    
368                    String type = getPreviewType(fileVersion);
369    
370                    File file = null;
371    
372                    try {
373                            file = FileUtil.createTempFile(type);
374    
375                            FileOutputStream fos = new FileOutputStream(file);
376    
377                            try {
378                                    ImageToolUtil.write(renderedImage, type, fos);
379                            }
380                            finally {
381                                    fos.close();
382                            }
383    
384                            addFileToStore(
385                                    fileVersion.getCompanyId(), PREVIEW_PATH,
386                                    getPreviewFilePath(fileVersion, type), file);
387                    }
388                    finally {
389                            FileUtil.delete(file);
390                    }
391            }
392    
393            private void _storeThumbnail(
394                            long companyId, long groupId, long fileEntryId, long fileVersionId,
395                            long custom1ImageId, long custom2ImageId, InputStream is,
396                            String type)
397                    throws Exception {
398    
399                    StringBundler sb = new StringBundler(5);
400    
401                    sb.append(getPathSegment(groupId, fileEntryId, fileVersionId, false));
402    
403                    if (custom1ImageId != 0) {
404                            sb.append(StringPool.DASH);
405                            sb.append(1);
406                    }
407                    else if (custom2ImageId != 0) {
408                            sb.append(StringPool.DASH);
409                            sb.append(2);
410                    }
411    
412                    sb.append(StringPool.PERIOD);
413                    sb.append(type);
414    
415                    String filePath = sb.toString();
416    
417                    File file = null;
418    
419                    try {
420                            file = FileUtil.createTempFile(is);
421    
422                            addFileToStore(companyId, THUMBNAIL_PATH, filePath, file);
423                    }
424                    finally {
425                            FileUtil.delete(file);
426                    }
427            }
428    
429            private static Log _log = LogFactoryUtil.getLog(ImageProcessorImpl.class);
430    
431            private List<Long> _fileVersionIds = new Vector<Long>();
432            private Set<String> _imageMimeTypes = SetUtil.fromArray(
433                    PropsValues.DL_FILE_ENTRY_PREVIEW_IMAGE_MIME_TYPES);
434    
435    }