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