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