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.documentlibrary.util;
016    
017    import com.liferay.document.library.kernel.exception.NoSuchFileEntryException;
018    import com.liferay.document.library.kernel.model.DLProcessorConstants;
019    import com.liferay.document.library.kernel.store.DLStoreUtil;
020    import com.liferay.document.library.kernel.util.DLPreviewableProcessor;
021    import com.liferay.document.library.kernel.util.DLUtil;
022    import com.liferay.document.library.kernel.util.PDFProcessor;
023    import com.liferay.exportimport.kernel.lar.PortletDataContext;
024    import com.liferay.portal.fabric.InputResource;
025    import com.liferay.portal.fabric.OutputResource;
026    import com.liferay.portal.kernel.image.GhostscriptUtil;
027    import com.liferay.portal.kernel.log.Log;
028    import com.liferay.portal.kernel.log.LogFactoryUtil;
029    import com.liferay.portal.kernel.messaging.DestinationNames;
030    import com.liferay.portal.kernel.process.ClassPathUtil;
031    import com.liferay.portal.kernel.process.ProcessCallable;
032    import com.liferay.portal.kernel.process.ProcessChannel;
033    import com.liferay.portal.kernel.process.ProcessException;
034    import com.liferay.portal.kernel.process.ProcessExecutorUtil;
035    import com.liferay.portal.kernel.repository.model.FileEntry;
036    import com.liferay.portal.kernel.repository.model.FileVersion;
037    import com.liferay.portal.kernel.util.ContentTypes;
038    import com.liferay.portal.kernel.util.FileUtil;
039    import com.liferay.portal.kernel.util.GetterUtil;
040    import com.liferay.portal.kernel.util.MimeTypesUtil;
041    import com.liferay.portal.kernel.util.PropsKeys;
042    import com.liferay.portal.kernel.util.ServerDetector;
043    import com.liferay.portal.kernel.util.StreamUtil;
044    import com.liferay.portal.kernel.util.StringPool;
045    import com.liferay.portal.kernel.util.SystemEnv;
046    import com.liferay.portal.kernel.util.Validator;
047    import com.liferay.portal.kernel.xml.Element;
048    import com.liferay.portal.log.Log4jLogFactoryImpl;
049    import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
050    import com.liferay.portal.util.PropsUtil;
051    import com.liferay.portal.util.PropsValues;
052    import com.liferay.util.log4j.Log4JUtil;
053    
054    import java.io.File;
055    import java.io.InputStream;
056    
057    import java.util.ArrayList;
058    import java.util.Arrays;
059    import java.util.List;
060    import java.util.Map;
061    import java.util.Objects;
062    import java.util.Properties;
063    import java.util.Set;
064    import java.util.Vector;
065    import java.util.concurrent.Future;
066    import java.util.concurrent.TimeUnit;
067    import java.util.concurrent.TimeoutException;
068    
069    import org.apache.commons.lang.time.StopWatch;
070    import org.apache.pdfbox.pdmodel.PDDocument;
071    
072    /**
073     * @author Alexander Chow
074     * @author Mika Koivisto
075     * @author Juan Gonz??lez
076     * @author Sergio Gonz??lez
077     * @author Ivica Cardic
078     */
079    public class PDFProcessorImpl
080            extends DLPreviewableProcessor implements PDFProcessor {
081    
082            @Override
083            public void afterPropertiesSet() throws Exception {
084                    FileUtil.mkdirs(PREVIEW_TMP_PATH);
085                    FileUtil.mkdirs(THUMBNAIL_TMP_PATH);
086            }
087    
088            @Override
089            public void generateImages(
090                            FileVersion sourceFileVersion, FileVersion destinationFileVersion)
091                    throws Exception {
092    
093                    _generateImages(sourceFileVersion, destinationFileVersion);
094            }
095    
096            @Override
097            public InputStream getPreviewAsStream(FileVersion fileVersion, int index)
098                    throws Exception {
099    
100                    return doGetPreviewAsStream(fileVersion, index, PREVIEW_TYPE);
101            }
102    
103            @Override
104            public int getPreviewFileCount(FileVersion fileVersion) {
105                    try {
106                            return doGetPreviewFileCount(fileVersion);
107                    }
108                    catch (Exception e) {
109                            _log.error(e, e);
110                    }
111    
112                    return 0;
113            }
114    
115            @Override
116            public long getPreviewFileSize(FileVersion fileVersion, int index)
117                    throws Exception {
118    
119                    return doGetPreviewFileSize(fileVersion, index);
120            }
121    
122            @Override
123            public InputStream getThumbnailAsStream(FileVersion fileVersion, int index)
124                    throws Exception {
125    
126                    return doGetThumbnailAsStream(fileVersion, index);
127            }
128    
129            @Override
130            public long getThumbnailFileSize(FileVersion fileVersion, int index)
131                    throws Exception {
132    
133                    return doGetThumbnailFileSize(fileVersion, index);
134            }
135    
136            @Override
137            public String getType() {
138                    return DLProcessorConstants.PDF_PROCESSOR;
139            }
140    
141            @Override
142            public boolean hasImages(FileVersion fileVersion) {
143                    boolean hasImages = false;
144    
145                    try {
146                            hasImages = _hasImages(fileVersion);
147    
148                            if (!hasImages && isSupported(fileVersion)) {
149                                    _queueGeneration(null, fileVersion);
150                            }
151                    }
152                    catch (Exception e) {
153                            _log.error(e, e);
154                    }
155    
156                    return hasImages;
157            }
158    
159            @Override
160            public boolean isDocumentSupported(FileVersion fileVersion) {
161                    return isSupported(fileVersion);
162            }
163    
164            @Override
165            public boolean isDocumentSupported(String mimeType) {
166                    return isSupported(mimeType);
167            }
168    
169            @Override
170            public boolean isSupported(String mimeType) {
171                    if (Validator.isNull(mimeType)) {
172                            return false;
173                    }
174    
175                    if (mimeType.equals(ContentTypes.APPLICATION_PDF) ||
176                            mimeType.equals(ContentTypes.APPLICATION_X_PDF)) {
177    
178                            return true;
179                    }
180    
181                    if (DocumentConversionUtil.isEnabled()) {
182                            Set<String> extensions = MimeTypesUtil.getExtensions(mimeType);
183    
184                            for (String extension : extensions) {
185                                    extension = extension.substring(1);
186    
187                                    String[] targetExtensions =
188                                            DocumentConversionUtil.getConversions(extension);
189    
190                                    if (Arrays.binarySearch(targetExtensions, "pdf") >= 0) {
191                                            return true;
192                                    }
193                            }
194                    }
195    
196                    return false;
197            }
198    
199            @Override
200            public void trigger(
201                    FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
202    
203                    super.trigger(sourceFileVersion, destinationFileVersion);
204    
205                    _queueGeneration(sourceFileVersion, destinationFileVersion);
206            }
207    
208            @Override
209            protected void copyPreviews(
210                    FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
211    
212                    if (!PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
213                            return;
214                    }
215    
216                    try {
217                            if (hasPreview(sourceFileVersion) &&
218                                    !hasPreview(destinationFileVersion)) {
219    
220                                    int count = getPreviewFileCount(sourceFileVersion);
221    
222                                    for (int i = 0; i < count; i++) {
223                                            String previewFilePath = getPreviewFilePath(
224                                                    destinationFileVersion, i + 1);
225    
226                                            InputStream is = doGetPreviewAsStream(
227                                                    sourceFileVersion, i + 1, PREVIEW_TYPE);
228    
229                                            addFileToStore(
230                                                    destinationFileVersion.getCompanyId(), PREVIEW_PATH,
231                                                    previewFilePath, is);
232                                    }
233                            }
234                    }
235                    catch (Exception e) {
236                            _log.error(e, e);
237                    }
238            }
239    
240            @Override
241            protected void doExportGeneratedFiles(
242                            PortletDataContext portletDataContext, FileEntry fileEntry,
243                            Element fileEntryElement)
244                    throws Exception {
245    
246                    exportThumbnails(
247                            portletDataContext, fileEntry, fileEntryElement, "pdf");
248    
249                    exportPreviews(portletDataContext, fileEntry, fileEntryElement);
250            }
251    
252            @Override
253            protected void doImportGeneratedFiles(
254                            PortletDataContext portletDataContext, FileEntry fileEntry,
255                            FileEntry importedFileEntry, Element fileEntryElement)
256                    throws Exception {
257    
258                    importThumbnails(
259                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
260                            "pdf");
261    
262                    importPreviews(
263                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement);
264            }
265    
266            protected void exportPreviews(
267                            PortletDataContext portletDataContext, FileEntry fileEntry,
268                            Element fileEntryElement)
269                    throws Exception {
270    
271                    FileVersion fileVersion = fileEntry.getFileVersion();
272    
273                    if (!isSupported(fileVersion) || !_hasImages(fileVersion)) {
274                            return;
275                    }
276    
277                    if (!portletDataContext.isPerformDirectBinaryImport()) {
278                            int previewFileCount = getPreviewFileCount(fileVersion);
279    
280                            fileEntryElement.addAttribute(
281                                    "bin-path-pdf-preview-count", String.valueOf(previewFileCount));
282    
283                            for (int i = 0; i < previewFileCount; i++) {
284                                    exportPreview(
285                                            portletDataContext, fileEntry, fileEntryElement, "pdf",
286                                            PREVIEW_TYPE, i);
287                            }
288                    }
289            }
290    
291            @Override
292            protected List<Long> getFileVersionIds() {
293                    return _fileVersionIds;
294            }
295    
296            @Override
297            protected String getPreviewType(FileVersion fileVersion) {
298                    return PREVIEW_TYPE;
299            }
300    
301            @Override
302            protected String getThumbnailType(FileVersion fileVersion) {
303                    return THUMBNAIL_TYPE;
304            }
305    
306            protected boolean hasPreview(FileVersion fileVersion) throws Exception {
307                    return hasPreview(fileVersion, null);
308            }
309    
310            @Override
311            protected boolean hasPreview(FileVersion fileVersion, String type)
312                    throws Exception {
313    
314                    String previewFilePath = getPreviewFilePath(fileVersion, 1);
315    
316                    return DLStoreUtil.hasFile(
317                            fileVersion.getCompanyId(), REPOSITORY_ID, previewFilePath);
318            }
319    
320            protected void importPreviews(
321                            PortletDataContext portletDataContext, FileEntry fileEntry,
322                            FileEntry importedFileEntry, Element fileEntryElement)
323                    throws Exception {
324    
325                    int previewFileCount = GetterUtil.getInteger(
326                            fileEntryElement.attributeValue("bin-path-pdf-preview-count"));
327    
328                    for (int i = 0; i < previewFileCount; i++) {
329                            importPreview(
330                                    portletDataContext, fileEntry, importedFileEntry,
331                                    fileEntryElement, "pdf", PREVIEW_TYPE, i);
332                    }
333            }
334    
335            private void _generateImages(FileVersion fileVersion, File file)
336                    throws Exception {
337    
338                    if (GhostscriptUtil.isEnabled()) {
339                            if (!_ghostscriptInitialized) {
340                                    GhostscriptUtil.reset();
341    
342                                    _ghostscriptInitialized = true;
343                            }
344    
345                            _generateImagesGS(fileVersion, file);
346                    }
347                    else {
348                            _generateImagesPB(fileVersion, file);
349                    }
350            }
351    
352            private void _generateImages(
353                            FileVersion sourceFileVersion, FileVersion destinationFileVersion)
354                    throws Exception {
355    
356                    InputStream inputStream = null;
357    
358                    try {
359                            if (sourceFileVersion != null) {
360                                    copy(sourceFileVersion, destinationFileVersion);
361    
362                                    return;
363                            }
364    
365                            if (_hasImages(destinationFileVersion)) {
366                                    return;
367                            }
368    
369                            String extension = destinationFileVersion.getExtension();
370    
371                            if (extension.equals("pdf")) {
372                                    if (destinationFileVersion instanceof LiferayFileVersion) {
373                                            try {
374                                                    LiferayFileVersion liferayFileVersion =
375                                                            (LiferayFileVersion)destinationFileVersion;
376    
377                                                    File file = liferayFileVersion.getFile(false);
378    
379                                                    _generateImages(destinationFileVersion, file);
380    
381                                                    return;
382                                            }
383                                            catch (UnsupportedOperationException uoe) {
384                                            }
385                                    }
386    
387                                    inputStream = destinationFileVersion.getContentStream(false);
388    
389                                    _generateImages(destinationFileVersion, inputStream);
390                            }
391                            else if (DocumentConversionUtil.isEnabled()) {
392                                    inputStream = destinationFileVersion.getContentStream(false);
393    
394                                    String tempFileId = DLUtil.getTempFileId(
395                                            destinationFileVersion.getFileEntryId(),
396                                            destinationFileVersion.getVersion());
397    
398                                    if (Objects.equals(
399                                                    "PWC", destinationFileVersion.getVersion()) ||
400                                            destinationFileVersion.isPending()) {
401    
402                                            File file = new File(
403                                                    DocumentConversionUtil.getFilePath(tempFileId, "pdf"));
404    
405                                            FileUtil.delete(file);
406                                    }
407    
408                                    File file = DocumentConversionUtil.convert(
409                                            tempFileId, inputStream, extension, "pdf");
410    
411                                    _generateImages(destinationFileVersion, file);
412                            }
413                    }
414                    catch (NoSuchFileEntryException nsfee) {
415                            if (_log.isDebugEnabled()) {
416                                    _log.debug(nsfee, nsfee);
417                            }
418                    }
419                    finally {
420                            StreamUtil.cleanUp(inputStream);
421    
422                            _fileVersionIds.remove(destinationFileVersion.getFileVersionId());
423                    }
424            }
425    
426            private void _generateImages(
427                            FileVersion fileVersion, InputStream inputStream)
428                    throws Exception {
429    
430                    if (GhostscriptUtil.isEnabled()) {
431                            _generateImagesGS(fileVersion, inputStream);
432                    }
433                    else {
434                            _generateImagesPB(fileVersion, inputStream);
435                    }
436            }
437    
438            private void _generateImagesGS(FileVersion fileVersion, File file)
439                    throws Exception {
440    
441                    if (_isGeneratePreview(fileVersion)) {
442                            StopWatch stopWatch = new StopWatch();
443    
444                            stopWatch.start();
445    
446                            _generateImagesGS(fileVersion, file, false);
447    
448                            if (_log.isInfoEnabled()) {
449                                    int previewFileCount = getPreviewFileCount(fileVersion);
450    
451                                    _log.info(
452                                            "Ghostscript generated " + previewFileCount +
453                                                    " preview pages for " + fileVersion.getTitle() +
454                                                            " in " + stopWatch.getTime() + " ms");
455                            }
456                    }
457    
458                    if (_isGenerateThumbnail(fileVersion)) {
459                            StopWatch stopWatch = new StopWatch();
460    
461                            stopWatch.start();
462    
463                            _generateImagesGS(fileVersion, file, true);
464    
465                            if (_log.isInfoEnabled()) {
466                                    _log.info(
467                                            "Ghostscript generated a thumbnail for " +
468                                                    fileVersion.getTitle() + " in " + stopWatch.getTime() +
469                                                            " ms");
470                            }
471                    }
472            }
473    
474            private void _generateImagesGS(
475                            FileVersion fileVersion, File file, boolean thumbnail)
476                    throws Exception {
477    
478                    // Generate images
479    
480                    String tempFileId = DLUtil.getTempFileId(
481                            fileVersion.getFileEntryId(), fileVersion.getVersion());
482    
483                    List<String> arguments = new ArrayList<>();
484    
485                    arguments.add("-sDEVICE=png16m");
486    
487                    if (thumbnail) {
488                            arguments.add(
489                                    "-sOutputFile=" + getThumbnailTempFilePath(tempFileId));
490                            arguments.add("-dFirstPage=1");
491                            arguments.add("-dLastPage=1");
492                    }
493                    else {
494                            arguments.add(
495                                    "-sOutputFile=" + getPreviewTempFilePath(tempFileId, -1));
496                    }
497    
498                    arguments.add("-dPDFFitPage");
499                    arguments.add("-dTextAlphaBits=4");
500                    arguments.add("-dGraphicsAlphaBits=4");
501                    arguments.add("-r" + PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI);
502    
503                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH != 0) {
504                            arguments.add(
505                                    "-dDEVICEWIDTH=" +
506                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH);
507                    }
508    
509                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT != 0) {
510                            arguments.add(
511                                    "-dDEVICEHEIGHT=" +
512                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT);
513                    }
514    
515                    arguments.add(file.getPath());
516    
517                    Future<?> future = GhostscriptUtil.execute(arguments);
518    
519                    String processIdentity = String.valueOf(fileVersion.getFileVersionId());
520    
521                    long ghostscriptTimeout =
522                            PropsValues.DL_FILE_ENTRY_PREVIEW_GENERATION_TIMEOUT_GHOSTSCRIPT;
523    
524                    if (_log.isDebugEnabled()) {
525                            if (thumbnail) {
526                                    _log.debug(
527                                            "Waiting for " + ghostscriptTimeout +
528                                                    " seconds to generate thumbnail for " + file.getPath());
529                            }
530                            else {
531                                    _log.debug(
532                                            "Waiting for " + ghostscriptTimeout +
533                                                    " seconds to generate preview for " + file.getPath());
534                            }
535                    }
536    
537                    try {
538                            future.get(ghostscriptTimeout, TimeUnit.SECONDS);
539    
540                            futures.put(processIdentity, future);
541                    }
542                    catch (TimeoutException te) {
543                            String errorMessage =
544                                    "Timeout when generating preview for " + file.getPath();
545    
546                            if (thumbnail) {
547                                    errorMessage =
548                                            "Timeout when generating thumbanil for " + file.getPath();
549                            }
550    
551                            if (future.cancel(true)) {
552                                    errorMessage += " resulted in a canceled timeout for " + future;
553                            }
554    
555                            _log.error(errorMessage);
556    
557                            throw te;
558                    }
559                    catch (Exception e) {
560                            _log.error(e, e);
561    
562                            throw e;
563                    }
564    
565                    // Store images
566    
567                    if (thumbnail) {
568                            File thumbnailTempFile = getThumbnailTempFile(tempFileId);
569    
570                            try {
571                                    storeThumbnailImages(fileVersion, thumbnailTempFile);
572                            }
573                            finally {
574                                    FileUtil.delete(thumbnailTempFile);
575                            }
576                    }
577                    else {
578                            int total = getPreviewTempFileCount(fileVersion);
579    
580                            for (int i = 0; i < total; i++) {
581                                    File previewTempFile = getPreviewTempFile(tempFileId, i + 2);
582    
583                                    try {
584                                            addFileToStore(
585                                                    fileVersion.getCompanyId(), PREVIEW_PATH,
586                                                    getPreviewFilePath(fileVersion, i + 1),
587                                                    previewTempFile);
588                                    }
589                                    finally {
590                                            FileUtil.delete(previewTempFile);
591                                    }
592                            }
593                    }
594            }
595    
596            private void _generateImagesGS(
597                            FileVersion fileVersion, InputStream inputStream)
598                    throws Exception {
599    
600                    File file = null;
601    
602                    try {
603                            file = FileUtil.createTempFile(inputStream);
604    
605                            _generateImagesGS(fileVersion, file);
606                    }
607                    finally {
608                            FileUtil.delete(file);
609                    }
610            }
611    
612            private void _generateImagesPB(FileVersion fileVersion, File file)
613                    throws Exception {
614    
615                    String tempFileId = DLUtil.getTempFileId(
616                            fileVersion.getFileEntryId(), fileVersion.getVersion());
617    
618                    File thumbnailFile = getThumbnailTempFile(tempFileId);
619    
620                    int previewFilesCount = 0;
621    
622                    try (PDDocument pdDocument = PDDocument.load(file)) {
623                            previewFilesCount = pdDocument.getNumberOfPages();
624                    }
625    
626                    File[] previewFiles = new File[previewFilesCount];
627    
628                    for (int i = 0; i < previewFilesCount; i++) {
629                            previewFiles[i] = getPreviewTempFile(tempFileId, i);
630                    }
631    
632                    boolean generatePreview = _isGeneratePreview(fileVersion);
633                    boolean generateThumbnail = _isGenerateThumbnail(fileVersion);
634    
635                    StopWatch stopWatch = new StopWatch();
636    
637                    stopWatch.start();
638    
639                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_FORK_PROCESS_ENABLED) {
640                            ProcessCallable<String> processCallable =
641                                    new LiferayPDFBoxProcessCallable(
642                                            ServerDetector.getServerId(),
643                                            PropsUtil.get(PropsKeys.LIFERAY_HOME),
644                                            Log4JUtil.getCustomLogSettings(), file, thumbnailFile,
645                                            previewFiles, getThumbnailType(fileVersion),
646                                            getPreviewType(fileVersion),
647                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI,
648                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT,
649                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH,
650                                            generatePreview, generateThumbnail);
651    
652                            ProcessChannel<String> processChannel = ProcessExecutorUtil.execute(
653                                    ClassPathUtil.getPortalProcessConfig(), processCallable);
654    
655                            Future<String> future = processChannel.getProcessNoticeableFuture();
656    
657                            String processIdentity = String.valueOf(
658                                    fileVersion.getFileVersionId());
659    
660                            long pdfBoxTimeout =
661                                    PropsValues.DL_FILE_ENTRY_PREVIEW_GENERATION_TIMEOUT_PDFBOX;
662    
663                            if (_log.isDebugEnabled()) {
664                                    if (generateThumbnail && generatePreview) {
665                                            _log.debug(
666                                                    "Waiting for " + pdfBoxTimeout +
667                                                            " seconds to generate thumbnail and preview for " +
668                                                                    file.getPath());
669                                    }
670                                    else {
671                                            if (generateThumbnail) {
672                                                    _log.debug(
673                                                            "Waiting for " + pdfBoxTimeout +
674                                                                    " seconds to generate thumbnail for " +
675                                                                            file.getPath());
676                                            }
677    
678                                            if (generatePreview) {
679                                                    _log.debug(
680                                                            "Waiting for " + pdfBoxTimeout +
681                                                                    " seconds to generate preview for " +
682                                                                            file.getPath());
683                                            }
684                                    }
685                            }
686    
687                            try {
688                                    future.get(pdfBoxTimeout, TimeUnit.SECONDS);
689    
690                                    futures.put(processIdentity, future);
691                            }
692                            catch (TimeoutException te) {
693                                    String errorMessage = null;
694    
695                                    if (generateThumbnail && generatePreview) {
696                                            errorMessage =
697                                                    "Timeout when generating thumbnail and preview for " +
698                                                            file.getPath();
699                                    }
700                                    else {
701                                            if (generateThumbnail) {
702                                                    errorMessage =
703                                                            "Timeout when generating thumbnail for " +
704                                                                    file.getPath();
705                                            }
706    
707                                            if (generatePreview) {
708                                                    errorMessage =
709                                                            "Timeout when generating preview for " +
710                                                                    file.getPath();
711                                            }
712                                    }
713    
714                                    if (future.cancel(true)) {
715                                            errorMessage +=
716                                                    " resulted in a canceled timeout for " + future;
717                                    }
718    
719                                    _log.error(errorMessage);
720    
721                                    throw te;
722                            }
723                            catch (Exception e) {
724                                    _log.error(e, e);
725    
726                                    throw e;
727                            }
728                    }
729                    else {
730                            LiferayPDFBoxConverter liferayConverter =
731                                    new LiferayPDFBoxConverter(
732                                            file, thumbnailFile, previewFiles,
733                                            getPreviewType(fileVersion), getThumbnailType(fileVersion),
734                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI,
735                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT,
736                                            PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH,
737                                            generatePreview, generateThumbnail);
738    
739                            liferayConverter.generateImagesPB();
740                    }
741    
742                    if (generateThumbnail) {
743                            try {
744                                    storeThumbnailImages(fileVersion, thumbnailFile);
745                            }
746                            finally {
747                                    FileUtil.delete(thumbnailFile);
748                            }
749                    }
750    
751                    if (generatePreview) {
752                            int index = 0;
753    
754                            for (File previewFile : previewFiles) {
755                                    try {
756                                            addFileToStore(
757                                                    fileVersion.getCompanyId(), PREVIEW_PATH,
758                                                    getPreviewFilePath(fileVersion, index + 1),
759                                                    previewFile);
760                                    }
761                                    finally {
762                                            FileUtil.delete(previewFile);
763                                    }
764    
765                                    index++;
766                            }
767                    }
768    
769                    if (_log.isInfoEnabled()) {
770                            long fileVersionId = fileVersion.getFileVersionId();
771                            int previewFileCount = getPreviewFileCount(fileVersion);
772                            long time = stopWatch.getTime();
773    
774                            if (generateThumbnail && generatePreview) {
775                                    _log.info(
776                                            "PDFBox generated a thumbnail and " + previewFileCount +
777                                                    " preview pages for " + fileVersionId + " in " + time +
778                                                            " ms");
779                            }
780                            else {
781                                    if (generateThumbnail) {
782                                            _log.info(
783                                                    "PDFBox generated a thumbnail for " + fileVersionId +
784                                                            " in " + time + " ms");
785                                    }
786    
787                                    if (generatePreview) {
788                                            _log.info(
789                                                    "PDFBox generated " + previewFileCount +
790                                                            " preview pages for " + fileVersionId + " in " +
791                                                                    time + " ms");
792                                    }
793                            }
794                    }
795            }
796    
797            private void _generateImagesPB(
798                            FileVersion fileVersion, InputStream inputStream)
799                    throws Exception {
800    
801                    File file = null;
802    
803                    try {
804                            file = FileUtil.createTempFile(inputStream);
805    
806                            _generateImagesPB(fileVersion, file);
807                    }
808                    finally {
809                            FileUtil.delete(file);
810                    }
811            }
812    
813            private boolean _hasImages(FileVersion fileVersion) throws Exception {
814                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
815                            if (!hasPreview(fileVersion)) {
816                                    return false;
817                            }
818                    }
819    
820                    return hasThumbnails(fileVersion);
821            }
822    
823            private boolean _isGeneratePreview(FileVersion fileVersion)
824                    throws Exception {
825    
826                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
827                            !hasPreview(fileVersion)) {
828    
829                            return true;
830                    }
831                    else {
832                            return false;
833                    }
834            }
835    
836            private boolean _isGenerateThumbnail(FileVersion fileVersion)
837                    throws Exception {
838    
839                    if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
840                            !hasThumbnail(fileVersion, THUMBNAIL_INDEX_DEFAULT)) {
841    
842                            return true;
843                    }
844                    else {
845                            return false;
846                    }
847            }
848    
849            private void _queueGeneration(
850                    FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
851    
852                    if (_fileVersionIds.contains(
853                                    destinationFileVersion.getFileVersionId())) {
854    
855                            return;
856                    }
857    
858                    boolean generateImages = false;
859    
860                    String extension = destinationFileVersion.getExtension();
861    
862                    if (extension.equals("pdf")) {
863                            generateImages = true;
864                    }
865                    else if (DocumentConversionUtil.isEnabled()) {
866                            String[] conversions = DocumentConversionUtil.getConversions(
867                                    extension);
868    
869                            for (String conversion : conversions) {
870                                    if (conversion.equals("pdf")) {
871                                            generateImages = true;
872    
873                                            break;
874                                    }
875                            }
876                    }
877    
878                    if (generateImages) {
879                            _fileVersionIds.add(destinationFileVersion.getFileVersionId());
880    
881                            sendGenerationMessage(
882                                    DestinationNames.DOCUMENT_LIBRARY_PDF_PROCESSOR,
883                                    sourceFileVersion, destinationFileVersion);
884                    }
885            }
886    
887            private static final Log _log = LogFactoryUtil.getLog(
888                    PDFProcessorImpl.class);
889    
890            private final List<Long> _fileVersionIds = new Vector<>();
891            private boolean _ghostscriptInitialized;
892    
893            private static class LiferayPDFBoxProcessCallable
894                    implements ProcessCallable<String> {
895    
896                    public LiferayPDFBoxProcessCallable(
897                            String serverId, String liferayHome,
898                            Map<String, String> customLogSettings, File inputFile,
899                            File thumbnailFile, File[] previewFiles, String extension,
900                            String thumbnailExtension, int dpi, int height, int width,
901                            boolean generatePreview, boolean generateThumbnail) {
902    
903                            _serverId = serverId;
904                            _liferayHome = liferayHome;
905                            _customLogSettings = customLogSettings;
906                            _inputFile = inputFile;
907                            _thumbnailFile = thumbnailFile;
908                            _previewFiles = previewFiles;
909                            _extension = extension;
910                            _thumbnailExtension = thumbnailExtension;
911                            _dpi = dpi;
912                            _height = height;
913                            _width = width;
914                            _generatePreview = generatePreview;
915                            _generateThumbnail = generateThumbnail;
916                    }
917    
918                    @Override
919                    public String call() throws ProcessException {
920                            Properties systemProperties = System.getProperties();
921    
922                            SystemEnv.setProperties(systemProperties);
923    
924                            Class<?> clazz = getClass();
925    
926                            ClassLoader classLoader = clazz.getClassLoader();
927    
928                            Log4JUtil.initLog4J(
929                                    _serverId, _liferayHome, classLoader, new Log4jLogFactoryImpl(),
930                                    _customLogSettings);
931    
932                            try {
933                                    LiferayPDFBoxConverter liferayConverter =
934                                            new LiferayPDFBoxConverter(
935                                                    _inputFile, _thumbnailFile, _previewFiles, _extension,
936                                                    _thumbnailExtension, _dpi, _height, _width,
937                                                    _generatePreview, _generateThumbnail);
938    
939                                    liferayConverter.generateImagesPB();
940                            }
941                            catch (Exception e) {
942                                    throw new ProcessException(e);
943                            }
944    
945                            return StringPool.BLANK;
946                    }
947    
948                    private static final long serialVersionUID = 1L;
949    
950                    private final Map<String, String> _customLogSettings;
951                    private final int _dpi;
952                    private final String _extension;
953                    private final boolean _generatePreview;
954                    private final boolean _generateThumbnail;
955                    private final int _height;
956    
957                    @InputResource
958                    private final File _inputFile;
959    
960                    private final String _liferayHome;
961    
962                    @OutputResource
963                    private final File[] _previewFiles;
964    
965                    private final String _serverId;
966                    private final String _thumbnailExtension;
967    
968                    @OutputResource
969                    private final File _thumbnailFile;
970    
971                    private final int _width;
972    
973            }
974    
975    }