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