001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.documentlibrary.util;
016    
017    import com.liferay.portal.kernel.configuration.Filter;
018    import com.liferay.portal.kernel.image.ImageToolUtil;
019    import com.liferay.portal.kernel.lar.PortletDataContext;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.messaging.DestinationNames;
023    import com.liferay.portal.kernel.messaging.MessageBusException;
024    import com.liferay.portal.kernel.messaging.MessageBusUtil;
025    import com.liferay.portal.kernel.process.ClassPathUtil;
026    import com.liferay.portal.kernel.process.ProcessCallable;
027    import com.liferay.portal.kernel.process.ProcessException;
028    import com.liferay.portal.kernel.process.ProcessExecutor;
029    import com.liferay.portal.kernel.repository.model.FileEntry;
030    import com.liferay.portal.kernel.repository.model.FileVersion;
031    import com.liferay.portal.kernel.util.ContentTypes;
032    import com.liferay.portal.kernel.util.FileUtil;
033    import com.liferay.portal.kernel.util.GetterUtil;
034    import com.liferay.portal.kernel.util.InstancePool;
035    import com.liferay.portal.kernel.util.MimeTypesUtil;
036    import com.liferay.portal.kernel.util.OSDetector;
037    import com.liferay.portal.kernel.util.PropsKeys;
038    import com.liferay.portal.kernel.util.StreamUtil;
039    import com.liferay.portal.kernel.util.StringBundler;
040    import com.liferay.portal.kernel.util.StringPool;
041    import com.liferay.portal.kernel.util.SystemEnv;
042    import com.liferay.portal.kernel.util.Validator;
043    import com.liferay.portal.kernel.xml.Element;
044    import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
045    import com.liferay.portal.util.PrefsPropsUtil;
046    import com.liferay.portal.util.PropsUtil;
047    import com.liferay.portal.util.PropsValues;
048    import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
049    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
050    
051    import java.awt.image.BufferedImage;
052    import java.awt.image.RenderedImage;
053    
054    import java.io.File;
055    import java.io.FileInputStream;
056    import java.io.FileOutputStream;
057    import java.io.InputStream;
058    
059    import java.util.Arrays;
060    import java.util.LinkedList;
061    import java.util.List;
062    import java.util.Properties;
063    import java.util.Set;
064    import java.util.Vector;
065    
066    import javax.imageio.ImageIO;
067    
068    import javax.portlet.PortletPreferences;
069    
070    import org.apache.commons.lang.time.StopWatch;
071    import org.apache.pdfbox.pdmodel.PDDocument;
072    import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
073    import org.apache.pdfbox.pdmodel.PDPage;
074    
075    import org.im4java.core.IMOperation;
076    
077    /**
078     * @author Alexander Chow
079     * @author Mika Koivisto
080     * @author Juan González
081     * @author Sergio González
082     */
083    public class PDFProcessorImpl
084            extends DLPreviewableProcessor implements PDFProcessor {
085    
086            public static PDFProcessorImpl getInstance() {
087                    return _instance;
088            }
089    
090            public void generateImages(FileVersion fileVersion) throws Exception {
091                    Initializer._initializedInstance._generateImages(fileVersion);
092            }
093    
094            public String getGlobalSearchPath() throws Exception {
095                    PortletPreferences preferences = PrefsPropsUtil.getPreferences();
096    
097                    String globalSearchPath = preferences.getValue(
098                            PropsKeys.IMAGEMAGICK_GLOBAL_SEARCH_PATH, null);
099    
100                    if (Validator.isNotNull(globalSearchPath)) {
101                            return globalSearchPath;
102                    }
103    
104                    String filterName = null;
105    
106                    if (OSDetector.isApple()) {
107                            filterName = "apple";
108                    }
109                    else if (OSDetector.isWindows()) {
110                            filterName = "windows";
111                    }
112                    else {
113                            filterName = "unix";
114                    }
115    
116                    return PropsUtil.get(
117                            PropsKeys.IMAGEMAGICK_GLOBAL_SEARCH_PATH, new Filter(filterName));
118            }
119    
120            public InputStream getPreviewAsStream(FileVersion fileVersion, int index)
121                    throws Exception {
122    
123                    return Initializer._initializedInstance.doGetPreviewAsStream(
124                            fileVersion, index, PREVIEW_TYPE);
125            }
126    
127            public int getPreviewFileCount(FileVersion fileVersion) {
128                    try {
129                            return Initializer._initializedInstance.doGetPreviewFileCount(
130                                    fileVersion);
131                    }
132                    catch (Exception e) {
133                            _log.error(e, e);
134                    }
135    
136                    return 0;
137            }
138    
139            public long getPreviewFileSize(FileVersion fileVersion, int index)
140                    throws Exception {
141    
142                    return Initializer._initializedInstance.doGetPreviewFileSize(
143                            fileVersion, index);
144            }
145    
146            public Properties getResourceLimitsProperties() throws Exception {
147                    Properties resourceLimitsProperties = PrefsPropsUtil.getProperties(
148                            PropsKeys.IMAGEMAGICK_RESOURCE_LIMIT, true);
149    
150                    if (resourceLimitsProperties.isEmpty()) {
151                            resourceLimitsProperties = PropsUtil.getProperties(
152                                    PropsKeys.IMAGEMAGICK_RESOURCE_LIMIT, true);
153                    }
154    
155                    return resourceLimitsProperties;
156            }
157    
158            public InputStream getThumbnailAsStream(FileVersion fileVersion, int index)
159                    throws Exception {
160    
161                    return doGetThumbnailAsStream(fileVersion, index);
162            }
163    
164            public long getThumbnailFileSize(FileVersion fileVersion, int index)
165                    throws Exception {
166    
167                    return doGetThumbnailFileSize(fileVersion, index);
168            }
169    
170            public boolean hasImages(FileVersion fileVersion) {
171                    boolean hasImages = false;
172    
173                    try {
174                            hasImages = _hasImages(fileVersion);
175    
176                            if (!hasImages && isSupported(fileVersion)) {
177                                    Initializer._initializedInstance._queueGeneration(fileVersion);
178                            }
179                    }
180                    catch (Exception e) {
181                            _log.error(e, e);
182                    }
183    
184                    return hasImages;
185            }
186    
187            public boolean isDocumentSupported(FileVersion fileVersion) {
188                    return Initializer._initializedInstance.isSupported(fileVersion);
189            }
190    
191            public boolean isDocumentSupported(String mimeType) {
192                    return Initializer._initializedInstance.isSupported(mimeType);
193            }
194    
195            public boolean isImageMagickEnabled() throws Exception {
196                    if (PrefsPropsUtil.getBoolean(PropsKeys.IMAGEMAGICK_ENABLED)) {
197                            return true;
198                    }
199    
200                    if (!_warned) {
201                            StringBundler sb = new StringBundler(6);
202    
203                            sb.append("Liferay is not configured to use ImageMagick. For ");
204                            sb.append("better quality document and image previews, install ");
205                            sb.append("ImageMagick and enable it in portal-ext.properties or ");
206                            sb.append("in the Server Administration control panel at: ");
207                            sb.append("http://<server>/group/control_panel/manage/-/server/");
208                            sb.append("external-services");
209    
210                            _log.warn(sb.toString());
211    
212                            _warned = true;
213                    }
214    
215                    return false;
216            }
217    
218            public boolean isSupported(String mimeType) {
219                    if (Validator.isNull(mimeType)) {
220                            return false;
221                    }
222    
223                    if (mimeType.equals(ContentTypes.APPLICATION_PDF) ||
224                            mimeType.equals(ContentTypes.APPLICATION_X_PDF)) {
225    
226                            return true;
227                    }
228    
229                    if (DocumentConversionUtil.isEnabled()) {
230                            Set<String> extensions = MimeTypesUtil.getExtensions(mimeType);
231    
232                            for (String extension : extensions) {
233                                    extension = extension.substring(1);
234    
235                                    String[] targetExtensions =
236                                            DocumentConversionUtil.getConversions(extension);
237    
238                                    if (Arrays.binarySearch(targetExtensions, "pdf") >= 0) {
239                                            return true;
240                                    }
241                            }
242                    }
243    
244                    return false;
245            }
246    
247            public void reset() throws Exception {
248                    if (isImageMagickEnabled()) {
249                            _globalSearchPath = getGlobalSearchPath();
250    
251                            _resourceLimitsProperties = getResourceLimitsProperties();
252                    }
253            }
254    
255            public void trigger(FileVersion fileVersion) {
256                    Initializer._initializedInstance._queueGeneration(fileVersion);
257            }
258    
259            @Override
260            protected void doExportGeneratedFiles(
261                            PortletDataContext portletDataContext, FileEntry fileEntry,
262                            Element fileEntryElement)
263                    throws Exception {
264    
265                    exportThumbnails(
266                            portletDataContext, fileEntry, fileEntryElement, "pdf");
267    
268                    exportPreviews(portletDataContext, fileEntry, fileEntryElement);
269            }
270    
271            @Override
272            protected void doImportGeneratedFiles(
273                            PortletDataContext portletDataContext, FileEntry fileEntry,
274                            FileEntry importedFileEntry, Element fileEntryElement)
275                    throws Exception {
276    
277                    importThumbnails(
278                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
279                            "pdf");
280    
281                    importPreviews(
282                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement);
283            }
284    
285            protected void exportPreviews(
286                            PortletDataContext portletDataContext, FileEntry fileEntry,
287                            Element fileEntryElement)
288                    throws Exception {
289    
290                    FileVersion fileVersion = fileEntry.getFileVersion();
291    
292                    if (!isSupported(fileVersion) || !_hasImages(fileVersion)) {
293                            return;
294                    }
295    
296                    if (!portletDataContext.isPerformDirectBinaryImport()) {
297                            int previewFileCount = PDFProcessorUtil.getPreviewFileCount(
298                                    fileVersion);
299    
300                            fileEntryElement.addAttribute(
301                                    "bin-path-pdf-preview-count", String.valueOf(previewFileCount));
302    
303                            for (int i = 0; i < previewFileCount; i++) {
304                                    exportPreview(
305                                            portletDataContext, fileEntry, fileEntryElement, "pdf",
306                                            PREVIEW_TYPE, i);
307                            }
308                    }
309            }
310    
311            @Override
312            protected String getPreviewType(FileVersion fileVersion) {
313                    return PREVIEW_TYPE;
314            }
315    
316            @Override
317            protected String getThumbnailType(FileVersion fileVersion) {
318                    return THUMBNAIL_TYPE;
319            }
320    
321            protected void importPreviews(
322                            PortletDataContext portletDataContext, FileEntry fileEntry,
323                            FileEntry importedFileEntry, Element fileEntryElement)
324                    throws Exception {
325    
326                    int previewFileCount = GetterUtil.getInteger(
327                            fileEntryElement.attributeValue("bin-path-pdf-preview-count"));
328    
329                    for (int i = 0; i < previewFileCount; i++) {
330                            importPreview(
331                                    portletDataContext, fileEntry, importedFileEntry,
332                                    fileEntryElement, "pdf", PREVIEW_TYPE, i);
333                    }
334            }
335    
336            protected void initialize() {
337                    try {
338                            FileUtil.mkdirs(PREVIEW_TMP_PATH);
339                            FileUtil.mkdirs(THUMBNAIL_TMP_PATH);
340    
341                            reset();
342                    }
343                    catch (Exception e) {
344                            _log.warn(e, e);
345                    }
346            }
347    
348            private PDFProcessorImpl() {
349            }
350    
351            private void _generateImages(FileVersion fileVersion) throws Exception {
352                    InputStream inputStream = null;
353    
354                    try {
355                            if (_hasImages(fileVersion)) {
356                                    return;
357                            }
358    
359                            String extension = fileVersion.getExtension();
360    
361                            if (extension.equals("pdf")) {
362                                    if (fileVersion instanceof LiferayFileVersion) {
363                                            try {
364                                                    LiferayFileVersion liferayFileVersion =
365                                                            (LiferayFileVersion)fileVersion;
366    
367                                                    File file = liferayFileVersion.getFile(false);
368    
369                                                    _generateImages(fileVersion, file);
370    
371                                                    return;
372                                            }
373                                            catch (UnsupportedOperationException uoe) {
374                                            }
375                                    }
376    
377                                    inputStream = fileVersion.getContentStream(false);
378    
379                                    _generateImages(fileVersion, inputStream);
380                            }
381                            else if (DocumentConversionUtil.isEnabled()) {
382                                    inputStream = fileVersion.getContentStream(false);
383    
384                                    String tempFileId = DLUtil.getTempFileId(
385                                            fileVersion.getFileEntryId(), fileVersion.getVersion());
386    
387                                    File file = DocumentConversionUtil.convert(
388                                            tempFileId, inputStream, extension, "pdf");
389    
390                                    _generateImages(fileVersion, file);
391                            }
392                    }
393                    catch (NoSuchFileEntryException nsfee) {
394                    }
395                    finally {
396                            StreamUtil.cleanUp(inputStream);
397    
398                            _fileVersionIds.remove(fileVersion.getFileVersionId());
399                    }
400            }
401    
402            private void _generateImages(FileVersion fileVersion, File file)
403                    throws Exception {
404    
405                    if (isImageMagickEnabled()) {
406                            _generateImagesIM(fileVersion, file);
407                    }
408                    else {
409                            _generateImagesPB(fileVersion, file);
410                    }
411            }
412    
413            private void _generateImages(
414                            FileVersion fileVersion, InputStream inputStream)
415                    throws Exception {
416    
417                    if (isImageMagickEnabled()) {
418                            _generateImagesIM(fileVersion, inputStream);
419                    }
420                    else {
421                            _generateImagesPB(fileVersion, inputStream);
422                    }
423            }
424    
425            private void _generateImagesIM(FileVersion fileVersion, File file)
426                    throws Exception {
427    
428                    if (_isGeneratePreview(fileVersion)) {
429                            StopWatch stopWatch = null;
430    
431                            if (_log.isInfoEnabled()) {
432                                    stopWatch = new StopWatch();
433    
434                                    stopWatch.start();
435                            }
436    
437                            _generateImagesIM(fileVersion, file, false);
438    
439                            if (_log.isInfoEnabled()) {
440                                    int previewFileCount = getPreviewFileCount(fileVersion);
441    
442                                    _log.info(
443                                            "ImageMagick generated " + previewFileCount +
444                                                    " preview pages for " + fileVersion.getTitle() +
445                                                            " in " + stopWatch);
446                            }
447                    }
448    
449                    if (_isGenerateThumbnail(fileVersion)) {
450                            StopWatch stopWatch = null;
451    
452                            if (_log.isInfoEnabled()) {
453                                    stopWatch = new StopWatch();
454    
455                                    stopWatch.start();
456                            }
457    
458                            _generateImagesIM(fileVersion, file, true);
459    
460                            if (_log.isInfoEnabled()) {
461                                    _log.info(
462                                            "ImageMagick generated a thumbnail for " +
463                                                    fileVersion.getTitle() + " in " + stopWatch);
464                            }
465                    }
466            }
467    
468            private void _generateImagesIM(
469                            FileVersion fileVersion, File file, boolean thumbnail)
470                    throws Exception {
471    
472                    // Generate images
473    
474                    String tempFileId = DLUtil.getTempFileId(
475                            fileVersion.getFileEntryId(), fileVersion.getVersion());
476    
477                    IMOperation imOperation = new IMOperation();
478    
479                    imOperation.alpha("off");
480    
481                    imOperation.density(
482                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI,
483                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI);
484    
485                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT != 0) {
486                            imOperation.adaptiveResize(
487                                    PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH,
488                                    PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT);
489                    }
490                    else {
491                            imOperation.adaptiveResize(
492                                    PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH);
493                    }
494    
495                    imOperation.depth(PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DEPTH);
496    
497                    if (thumbnail) {
498                            imOperation.addImage(file.getPath() + "[0]");
499                            imOperation.addImage(getThumbnailTempFilePath(tempFileId));
500                    }
501                    else {
502                            imOperation.addImage(file.getPath());
503                            imOperation.addImage(getPreviewTempFilePath(tempFileId, -1));
504                    }
505    
506                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_FORK_PROCESS_ENABLED) {
507                            ProcessCallable<String> processCallable =
508                                    new ImageMagickProcessCallable(
509                                            _globalSearchPath, _resourceLimitsProperties,
510                                            imOperation.getCmdArgs());
511    
512                            ProcessExecutor.execute(
513                                    processCallable, ClassPathUtil.getPortalClassPath());
514                    }
515                    else {
516                            LiferayConvertCmd.run(
517                                    _globalSearchPath, _resourceLimitsProperties,
518                                    imOperation.getCmdArgs());
519                    }
520    
521                    // Store images
522    
523                    if (thumbnail) {
524                            File thumbnailTempFile = getThumbnailTempFile(tempFileId);
525    
526                            try {
527                                    storeThumbnailImages(fileVersion, thumbnailTempFile);
528                            }
529                            finally {
530                                    FileUtil.delete(thumbnailTempFile);
531                            }
532                    }
533                    else {
534    
535                            // ImageMagick converts single page PDFs without appending an
536                            // index. Rename file for consistency.
537    
538                            File singlePagePreviewFile = getPreviewTempFile(tempFileId, -1);
539    
540                            if (singlePagePreviewFile.exists()) {
541                                    singlePagePreviewFile.renameTo(
542                                            getPreviewTempFile(tempFileId, 1));
543                            }
544    
545                            int total = getPreviewTempFileCount(fileVersion);
546    
547                            for (int i = 0; i < total; i++) {
548                                    File previewTempFile = getPreviewTempFile(tempFileId, i + 1);
549    
550                                    try {
551                                            addFileToStore(
552                                                    fileVersion.getCompanyId(), PREVIEW_PATH,
553                                                    getPreviewFilePath(fileVersion, i + 1),
554                                                    previewTempFile);
555                                    }
556                                    finally {
557                                            FileUtil.delete(previewTempFile);
558                                    }
559                            }
560                    }
561            }
562    
563            private void _generateImagesIM(
564                            FileVersion fileVersion, InputStream inputStream)
565                    throws Exception {
566    
567                    File file = null;
568    
569                    try {
570                            file = FileUtil.createTempFile(inputStream);
571    
572                            _generateImagesIM(fileVersion, file);
573                    }
574                    finally {
575                            FileUtil.delete(file);
576                    }
577            }
578    
579            private void _generateImagesPB(FileVersion fileVersion, File file)
580                    throws Exception {
581    
582                    _generateImagesPB(fileVersion, new FileInputStream(file));
583            }
584    
585            private void _generateImagesPB(
586                            FileVersion fileVersion, InputStream inputStream)
587                    throws Exception {
588    
589                    boolean generatePreview = _isGeneratePreview(fileVersion);
590                    boolean generateThumbnail = _isGenerateThumbnail(fileVersion);
591    
592                    PDDocument pdDocument = null;
593    
594                    try {
595                            pdDocument = PDDocument.load(inputStream);
596    
597                            PDDocumentCatalog pdDocumentCatalog =
598                                    pdDocument.getDocumentCatalog();
599    
600                            List<PDPage> pdPages = pdDocumentCatalog.getAllPages();
601    
602                            for (int i = 0; i < pdPages.size(); i++) {
603                                    PDPage pdPage = pdPages.get(i);
604    
605                                    if (generateThumbnail && (i == 0)) {
606                                            _generateImagesPB(fileVersion, pdPage, i);
607    
608                                            if (_log.isInfoEnabled()) {
609                                                    _log.info(
610                                                            "PDFBox generated a thumbnail for " +
611                                                                    fileVersion.getFileVersionId());
612                                            }
613                                    }
614    
615                                    if (!generatePreview) {
616                                            break;
617                                    }
618    
619                                    _generateImagesPB(fileVersion, pdPage, i + 1);
620                            }
621    
622                            if (_log.isInfoEnabled() && generatePreview) {
623                                    _log.info(
624                                            "PDFBox generated " +
625                                                    getPreviewFileCount(fileVersion) +
626                                                            " preview pages for " +
627                                                                    fileVersion.getFileVersionId());
628                            }
629                    }
630                    finally {
631                            if (pdDocument != null) {
632                                    pdDocument.close();
633                            }
634                    }
635            }
636    
637            private void _generateImagesPB(
638                            FileVersion fileVersion, PDPage pdPage, int index)
639                    throws Exception {
640    
641                    // Generate images
642    
643                    RenderedImage renderedImage = pdPage.convertToImage(
644                            BufferedImage.TYPE_INT_RGB,
645                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI);
646    
647                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT != 0) {
648                            renderedImage = ImageToolUtil.scale(
649                                    renderedImage,
650                                    PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH,
651                                    PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT);
652                    }
653                    else {
654                            renderedImage = ImageToolUtil.scale(
655                                    renderedImage,
656                                    PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH);
657                    }
658    
659                    // Store images
660    
661                    if (index == 0) {
662                            storeThumbnailImages(fileVersion, renderedImage);
663                    }
664                    else {
665                            File tempFile = null;
666    
667                            try {
668                                    String tempFileId = DLUtil.getTempFileId(
669                                            fileVersion.getFileEntryId(), fileVersion.getVersion());
670    
671                                    tempFile = getPreviewTempFile(tempFileId, index);
672    
673                                    tempFile.createNewFile();
674    
675                                    ImageIO.write(
676                                            renderedImage, PREVIEW_TYPE,
677                                            new FileOutputStream(tempFile));
678    
679                                    addFileToStore(
680                                            fileVersion.getCompanyId(), PREVIEW_PATH,
681                                            getPreviewFilePath(fileVersion, index), tempFile);
682                            }
683                            finally {
684                                    FileUtil.delete(tempFile);
685                            }
686                    }
687            }
688    
689            private boolean _hasImages(FileVersion fileVersion) throws Exception {
690                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
691                            if (!DLStoreUtil.hasFile(
692                                            fileVersion.getCompanyId(), REPOSITORY_ID,
693                                            getPreviewFilePath(fileVersion, 1))) {
694    
695                                    return false;
696                            }
697                    }
698    
699                    return hasThumbnails(fileVersion);
700            }
701    
702            private boolean _isGeneratePreview(FileVersion fileVersion)
703                    throws Exception {
704    
705                    String previewFilePath = getPreviewFilePath(fileVersion, 1);
706    
707                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
708                            !DLStoreUtil.hasFile(
709                                    fileVersion.getCompanyId(), REPOSITORY_ID, previewFilePath)) {
710    
711                            return true;
712                    }
713                    else {
714                            return false;
715                    }
716            }
717    
718            private boolean _isGenerateThumbnail(FileVersion fileVersion)
719                    throws Exception {
720    
721                    String thumbnailFilePath = getThumbnailFilePath(
722                            fileVersion, THUMBNAIL_INDEX_DEFAULT);
723    
724                    if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
725                            !DLStoreUtil.hasFile(
726                                    fileVersion.getCompanyId(), REPOSITORY_ID, thumbnailFilePath)) {
727    
728                            return true;
729                    }
730                    else {
731                            return false;
732                    }
733            }
734    
735            private void _queueGeneration(FileVersion fileVersion) {
736                    if (_fileVersionIds.contains(fileVersion.getFileVersionId())) {
737                            return;
738                    }
739    
740                    boolean generateImages = false;
741    
742                    String extension = fileVersion.getExtension();
743    
744                    if (extension.equals("pdf")) {
745                            generateImages = true;
746                    }
747                    else if (DocumentConversionUtil.isEnabled()) {
748                            String[] conversions = DocumentConversionUtil.getConversions(
749                                    extension);
750    
751                            for (String conversion : conversions) {
752                                    if (conversion.equals("pdf")) {
753                                            generateImages = true;
754    
755                                            break;
756                                    }
757                            }
758                    }
759    
760                    if (generateImages) {
761                            _fileVersionIds.add(fileVersion.getFileVersionId());
762    
763                            if (PropsValues.DL_FILE_ENTRY_PROCESSORS_TRIGGER_SYNCHRONOUSLY) {
764                                    try {
765                                            MessageBusUtil.sendSynchronousMessage(
766                                                    DestinationNames.DOCUMENT_LIBRARY_PDF_PROCESSOR,
767                                                    fileVersion);
768                                    }
769                                    catch (MessageBusException mbe) {
770                                            if (_log.isWarnEnabled()) {
771                                                    _log.warn(mbe, mbe);
772                                            }
773                                    }
774                            }
775                            else {
776                                    MessageBusUtil.sendMessage(
777                                            DestinationNames.DOCUMENT_LIBRARY_PDF_PROCESSOR,
778                                            fileVersion);
779                            }
780                    }
781            }
782    
783            private static Log _log = LogFactoryUtil.getLog(PDFProcessorImpl.class);
784    
785            private static PDFProcessorImpl _instance = new PDFProcessorImpl();
786    
787            static {
788                    InstancePool.put(PDFProcessorImpl.class.getName(), _instance);
789            }
790    
791            private List<Long> _fileVersionIds = new Vector<Long>();
792            private String _globalSearchPath;
793            private Properties _resourceLimitsProperties;
794            private boolean _warned;
795    
796            private static class ImageMagickProcessCallable
797                    implements ProcessCallable<String> {
798    
799                    public ImageMagickProcessCallable(
800                            String globalSearchPath, Properties resourceLimits,
801                            LinkedList<String> commandArguments) {
802    
803                            _globalSearchPath = globalSearchPath;
804                            _commandArguments = commandArguments;
805                            _resourceLimits = resourceLimits;
806                    }
807    
808                    public String call() throws ProcessException {
809                            Properties systemProperties = System.getProperties();
810    
811                            SystemEnv.setProperties(systemProperties);
812    
813                            try {
814                                    LiferayConvertCmd.run(
815                                            _globalSearchPath, _resourceLimits, _commandArguments);
816                            }
817                            catch (Exception e) {
818                                    throw new ProcessException(e);
819                            }
820    
821                            return StringPool.BLANK;
822                    }
823    
824                    private LinkedList<String> _commandArguments;
825                    private String _globalSearchPath;
826                    private Properties _resourceLimits;
827    
828            }
829    
830            private static class Initializer {
831    
832                    private static PDFProcessorImpl _initializedInstance;
833    
834                    static {
835                            _instance.initialize();
836    
837                            _initializedInstance = _instance;
838                    }
839    
840            }
841    
842    }