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