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