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.exception.SystemException;
020    import com.liferay.portal.kernel.image.ImageBag;
021    import com.liferay.portal.kernel.image.ImageToolUtil;
022    import com.liferay.portal.kernel.lar.PortletDataContext;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.messaging.DestinationNames;
026    import com.liferay.portal.kernel.process.ClassPathUtil;
027    import com.liferay.portal.kernel.process.ProcessCallable;
028    import com.liferay.portal.kernel.process.ProcessChannel;
029    import com.liferay.portal.kernel.process.ProcessException;
030    import com.liferay.portal.kernel.process.ProcessExecutorUtil;
031    import com.liferay.portal.kernel.repository.model.FileEntry;
032    import com.liferay.portal.kernel.repository.model.FileVersion;
033    import com.liferay.portal.kernel.util.FileUtil;
034    import com.liferay.portal.kernel.util.PropsKeys;
035    import com.liferay.portal.kernel.util.ServerDetector;
036    import com.liferay.portal.kernel.util.SetUtil;
037    import com.liferay.portal.kernel.util.StreamUtil;
038    import com.liferay.portal.kernel.util.StringBundler;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.SystemEnv;
041    import com.liferay.portal.kernel.util.Validator;
042    import com.liferay.portal.kernel.xml.Element;
043    import com.liferay.portal.kernel.xuggler.XugglerUtil;
044    import com.liferay.portal.log.Log4jLogFactoryImpl;
045    import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
046    import com.liferay.portal.util.PropsUtil;
047    import com.liferay.portal.util.PropsValues;
048    import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
049    import com.liferay.util.log4j.Log4JUtil;
050    
051    import java.awt.image.RenderedImage;
052    
053    import java.io.File;
054    import java.io.InputStream;
055    
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.CancellationException;
062    import java.util.concurrent.Future;
063    
064    import org.apache.commons.lang.time.StopWatch;
065    
066    /**
067     * @author Juan Gonz??lez
068     * @author Sergio Gonz??lez
069     * @author Mika Koivisto
070     * @author Ivica Cardic
071     */
072    public class VideoProcessorImpl
073            extends DLPreviewableProcessor implements VideoProcessor {
074    
075            @Override
076            public void afterPropertiesSet() {
077                    boolean valid = true;
078    
079                    if ((_PREVIEW_TYPES.length == 0) || (_PREVIEW_TYPES.length > 2)) {
080                            valid = false;
081                    }
082                    else {
083                            for (String previewType : _PREVIEW_TYPES) {
084                                    if (!previewType.equals("mp4") && !previewType.equals("ogv")) {
085                                            valid = false;
086    
087                                            break;
088                                    }
089                            }
090                    }
091    
092                    if (!valid && _log.isWarnEnabled()) {
093                            StringBundler sb = new StringBundler(5);
094    
095                            sb.append("Liferay is incorrectly configured to generate video ");
096                            sb.append("previews using video containers other than MP4 or ");
097                            sb.append("OGV. Please change the property ");
098                            sb.append(PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO_CONTAINERS);
099                            sb.append(" in portal-ext.properties.");
100    
101                            _log.warn(sb.toString());
102                    }
103    
104                    FileUtil.mkdirs(PREVIEW_TMP_PATH);
105                    FileUtil.mkdirs(THUMBNAIL_TMP_PATH);
106            }
107    
108            @Override
109            public void generateVideo(
110                            FileVersion sourceFileVersion, FileVersion destinationFileVersion)
111                    throws Exception {
112    
113                    _generateVideo(sourceFileVersion, destinationFileVersion);
114            }
115    
116            @Override
117            public InputStream getPreviewAsStream(FileVersion fileVersion, String type)
118                    throws Exception {
119    
120                    return doGetPreviewAsStream(fileVersion, type);
121            }
122    
123            @Override
124            public long getPreviewFileSize(FileVersion fileVersion, String type)
125                    throws Exception {
126    
127                    return doGetPreviewFileSize(fileVersion, type);
128            }
129    
130            @Override
131            public InputStream getThumbnailAsStream(FileVersion fileVersion, int index)
132                    throws Exception {
133    
134                    return doGetThumbnailAsStream(fileVersion, index);
135            }
136    
137            @Override
138            public long getThumbnailFileSize(FileVersion fileVersion, int index)
139                    throws Exception {
140    
141                    return doGetThumbnailFileSize(fileVersion, index);
142            }
143    
144            @Override
145            public Set<String> getVideoMimeTypes() {
146                    return _videoMimeTypes;
147            }
148    
149            @Override
150            public boolean hasVideo(FileVersion fileVersion) {
151                    boolean hasVideo = false;
152    
153                    try {
154                            hasVideo = _hasVideo(fileVersion);
155    
156                            if (!hasVideo && isSupported(fileVersion)) {
157                                    _queueGeneration(null, fileVersion);
158                            }
159                    }
160                    catch (Exception e) {
161                            _log.error(e, e);
162                    }
163    
164                    return hasVideo;
165            }
166    
167            @Override
168            public boolean isSupported(String mimeType) {
169                    if (Validator.isNull(mimeType)) {
170                            return false;
171                    }
172    
173                    try {
174                            if (XugglerUtil.isEnabled()) {
175                                    return _videoMimeTypes.contains(mimeType);
176                            }
177                    }
178                    catch (Exception e) {
179                    }
180    
181                    return false;
182            }
183    
184            @Override
185            public boolean isVideoSupported(FileVersion fileVersion) {
186                    return isSupported(fileVersion);
187            }
188    
189            @Override
190            public boolean isVideoSupported(String mimeType) {
191                    return isSupported(mimeType);
192            }
193    
194            @Override
195            public void trigger(
196                    FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
197    
198                    super.trigger(sourceFileVersion, destinationFileVersion);
199    
200                    _queueGeneration(sourceFileVersion, destinationFileVersion);
201            }
202    
203            @Override
204            protected void doExportGeneratedFiles(
205                            PortletDataContext portletDataContext, FileEntry fileEntry,
206                            Element fileEntryElement)
207                    throws Exception {
208    
209                    exportThumbnails(
210                            portletDataContext, fileEntry, fileEntryElement, "video");
211    
212                    exportPreviews(portletDataContext, fileEntry, fileEntryElement);
213            }
214    
215            @Override
216            protected void doImportGeneratedFiles(
217                            PortletDataContext portletDataContext, FileEntry fileEntry,
218                            FileEntry importedFileEntry, Element fileEntryElement)
219                    throws Exception {
220    
221                    importThumbnails(
222                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
223                            "video");
224    
225                    importPreviews(
226                            portletDataContext, fileEntry, importedFileEntry, fileEntryElement);
227            }
228    
229            protected void exportPreviews(
230                            PortletDataContext portletDataContext, FileEntry fileEntry,
231                            Element fileEntryElement)
232                    throws Exception {
233    
234                    FileVersion fileVersion = fileEntry.getFileVersion();
235    
236                    if (!isSupported(fileVersion) || !hasPreviews(fileVersion)) {
237                            return;
238                    }
239    
240                    if (!portletDataContext.isPerformDirectBinaryImport()) {
241                            if ((_PREVIEW_TYPES.length == 0) || (_PREVIEW_TYPES.length > 2)) {
242                                    return;
243                            }
244    
245                            for (String previewType : _PREVIEW_TYPES) {
246                                    if (previewType.equals("mp4") || previewType.equals("ogv")) {
247                                            exportPreview(
248                                                    portletDataContext, fileEntry, fileEntryElement,
249                                                    "video", previewType);
250                                    }
251                            }
252                    }
253            }
254    
255            @Override
256            protected List<Long> getFileVersionIds() {
257                    return _fileVersionIds;
258            }
259    
260            @Override
261            protected String getPreviewType(FileVersion fileVersion) {
262                    return _PREVIEW_TYPES[0];
263            }
264    
265            @Override
266            protected String[] getPreviewTypes() {
267                    return _PREVIEW_TYPES;
268            }
269    
270            @Override
271            protected String getThumbnailType(FileVersion fileVersion) {
272                    return THUMBNAIL_TYPE;
273            }
274    
275            protected void importPreviews(
276                            PortletDataContext portletDataContext, FileEntry fileEntry,
277                            FileEntry importedFileEntry, Element fileEntryElement)
278                    throws Exception {
279    
280                    if ((_PREVIEW_TYPES.length == 0) || (_PREVIEW_TYPES.length > 2)) {
281                            return;
282                    }
283    
284                    for (String previewType : _PREVIEW_TYPES) {
285                            if (previewType.equals("mp4") || previewType.equals("ogv")) {
286                                    importPreview(
287                                            portletDataContext, fileEntry, importedFileEntry,
288                                            fileEntryElement, "video", previewType);
289                            }
290                    }
291            }
292    
293            @Override
294            protected void storeThumbnailImages(FileVersion fileVersion, File file)
295                    throws Exception {
296    
297                    if (!hasThumbnail(fileVersion, THUMBNAIL_INDEX_DEFAULT)) {
298                            addFileToStore(
299                                    fileVersion.getCompanyId(), THUMBNAIL_PATH,
300                                    getThumbnailFilePath(fileVersion, THUMBNAIL_INDEX_DEFAULT),
301                                    file);
302                    }
303    
304                    if (isThumbnailEnabled(THUMBNAIL_INDEX_CUSTOM_1) ||
305                            isThumbnailEnabled(THUMBNAIL_INDEX_CUSTOM_2)) {
306    
307                            ImageBag imageBag = ImageToolUtil.read(file);
308    
309                            RenderedImage renderedImage = imageBag.getRenderedImage();
310    
311                            storeThumbnailImage(
312                                    fileVersion, renderedImage, THUMBNAIL_INDEX_CUSTOM_1);
313                            storeThumbnailImage(
314                                    fileVersion, renderedImage, THUMBNAIL_INDEX_CUSTOM_2);
315                    }
316            }
317    
318            private void _generateThumbnailXuggler(
319                            FileVersion fileVersion, File file, int height, int width)
320                    throws Exception {
321    
322                    StopWatch stopWatch = new StopWatch();
323    
324                    stopWatch.start();
325    
326                    String tempFileId = DLUtil.getTempFileId(
327                            fileVersion.getFileEntryId(), fileVersion.getVersion());
328    
329                    File thumbnailTempFile = getThumbnailTempFile(tempFileId);
330    
331                    try {
332                            try {
333                                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_FORK_PROCESS_ENABLED) {
334                                            ProcessCallable<String> processCallable =
335                                                    new LiferayVideoThumbnailProcessCallable(
336                                                            ServerDetector.getServerId(),
337                                                            PropsUtil.get(PropsKeys.LIFERAY_HOME),
338                                                            Log4JUtil.getCustomLogSettings(), file,
339                                                            thumbnailTempFile, THUMBNAIL_TYPE, height, width,
340                                                            PropsValues.
341                                                                    DL_FILE_ENTRY_THUMBNAIL_VIDEO_FRAME_PERCENTAGE);
342    
343                                            ProcessChannel<String> processChannel =
344                                                    ProcessExecutorUtil.execute(
345                                                            ClassPathUtil.getPortalProcessConfig(),
346                                                            processCallable);
347    
348                                            Future<String> future =
349                                                    processChannel.getProcessNoticeableFuture();
350    
351                                            String processIdentity = String.valueOf(
352                                                    fileVersion.getFileVersionId());
353    
354                                            futures.put(processIdentity, future);
355    
356                                            future.get();
357                                    }
358                                    else {
359                                            LiferayConverter liferayConverter =
360                                                    new LiferayVideoThumbnailConverter(
361                                                            file.getCanonicalPath(), thumbnailTempFile,
362                                                            THUMBNAIL_TYPE, height, width,
363                                                            PropsValues.
364                                                                    DL_FILE_ENTRY_THUMBNAIL_VIDEO_FRAME_PERCENTAGE);
365    
366                                            liferayConverter.convert();
367                                    }
368                            }
369                            catch (CancellationException ce) {
370                                    if (_log.isInfoEnabled()) {
371                                            _log.info(
372                                                    "Cancellation received for " +
373                                                            fileVersion.getFileVersionId() + " " +
374                                                                    fileVersion.getTitle());
375                                    }
376                            }
377                            catch (Exception e) {
378                                    _log.error(e, e);
379                            }
380    
381                            storeThumbnailImages(fileVersion, thumbnailTempFile);
382    
383                            if (_log.isInfoEnabled()) {
384                                    _log.info(
385                                            "Xuggler generated a thumbnail for " +
386                                                    fileVersion.getTitle() + " in " + stopWatch.getTime() +
387                                                            " ms");
388                            }
389                    }
390                    catch (Exception e) {
391                            throw new SystemException(e);
392                    }
393                    finally {
394                            FileUtil.delete(thumbnailTempFile);
395                    }
396            }
397    
398            private void _generateVideo(
399                            FileVersion sourceFileVersion, FileVersion destinationFileVersion)
400                    throws Exception {
401    
402                    if (!XugglerUtil.isEnabled() || _hasVideo(destinationFileVersion)) {
403                            return;
404                    }
405    
406                    InputStream inputStream = null;
407    
408                    File[] previewTempFiles = new File[_PREVIEW_TYPES.length];
409    
410                    File videoTempFile = null;
411    
412                    try {
413                            if (sourceFileVersion != null) {
414                                    copy(sourceFileVersion, destinationFileVersion);
415    
416                                    return;
417                            }
418    
419                            File file = null;
420    
421                            if (!hasPreviews(destinationFileVersion) ||
422                                    !hasThumbnails(destinationFileVersion)) {
423    
424                                    if (destinationFileVersion instanceof LiferayFileVersion) {
425                                            try {
426                                                    LiferayFileVersion liferayFileVersion =
427                                                            (LiferayFileVersion)destinationFileVersion;
428    
429                                                    file = liferayFileVersion.getFile(false);
430                                            }
431                                            catch (UnsupportedOperationException uoe) {
432                                            }
433                                    }
434    
435                                    if (file == null) {
436                                            inputStream = destinationFileVersion.getContentStream(
437                                                    false);
438    
439                                            videoTempFile = FileUtil.createTempFile(
440                                                    destinationFileVersion.getExtension());
441    
442                                            FileUtil.write(videoTempFile, inputStream);
443    
444                                            file = videoTempFile;
445                                    }
446                            }
447    
448                            if (!hasPreviews(destinationFileVersion)) {
449                                    String tempFileId = DLUtil.getTempFileId(
450                                            destinationFileVersion.getFileEntryId(),
451                                            destinationFileVersion.getVersion());
452    
453                                    for (int i = 0; i < _PREVIEW_TYPES.length; i++) {
454                                            previewTempFiles[i] = getPreviewTempFile(
455                                                    tempFileId, _PREVIEW_TYPES[i]);
456                                    }
457    
458                                    try {
459                                            _generateVideoXuggler(
460                                                    destinationFileVersion, file, previewTempFiles,
461                                                    PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_HEIGHT,
462                                                    PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_WIDTH);
463                                    }
464                                    catch (Exception e) {
465                                            _log.error(e, e);
466                                    }
467                            }
468    
469                            if (!hasThumbnails(destinationFileVersion)) {
470                                    try {
471                                            _generateThumbnailXuggler(
472                                                    destinationFileVersion, file,
473                                                    PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_HEIGHT,
474                                                    PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_WIDTH);
475                                    }
476                                    catch (Exception e) {
477                                            _log.error(e, e);
478                                    }
479                            }
480                    }
481                    catch (NoSuchFileEntryException nsfee) {
482                    }
483                    finally {
484                            StreamUtil.cleanUp(inputStream);
485    
486                            _fileVersionIds.remove(destinationFileVersion.getFileVersionId());
487    
488                            for (int i = 0; i < previewTempFiles.length; i++) {
489                                    FileUtil.delete(previewTempFiles[i]);
490                            }
491    
492                            FileUtil.delete(videoTempFile);
493                    }
494            }
495    
496            private void _generateVideoXuggler(
497                            FileVersion fileVersion, File sourceFile, File destinationFile,
498                            String containerType)
499                    throws Exception {
500    
501                    if (hasPreview(fileVersion, containerType)) {
502                            return;
503                    }
504    
505                    StopWatch stopWatch = new StopWatch();
506    
507                    stopWatch.start();
508    
509                    if (PropsValues.DL_FILE_ENTRY_PREVIEW_FORK_PROCESS_ENABLED) {
510                            ProcessCallable<String> processCallable =
511                                    new LiferayVideoProcessCallable(
512                                            ServerDetector.getServerId(),
513                                            PropsUtil.get(PropsKeys.LIFERAY_HOME),
514                                            Log4JUtil.getCustomLogSettings(), sourceFile,
515                                            destinationFile, containerType,
516                                            PropsUtil.getProperties(
517                                                    PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO, false),
518                                            PropsUtil.getProperties(PropsKeys.XUGGLER_FFPRESET, true));
519    
520                            ProcessChannel<String> processChannel = ProcessExecutorUtil.execute(
521                                    ClassPathUtil.getPortalProcessConfig(), processCallable);
522    
523                            Future<String> future = processChannel.getProcessNoticeableFuture();
524    
525                            String processIdentity = String.valueOf(
526                                    fileVersion.getFileVersionId());
527    
528                            futures.put(processIdentity, future);
529    
530                            future.get();
531                    }
532                    else {
533                            LiferayConverter liferayConverter = new LiferayVideoConverter(
534                                    sourceFile.getCanonicalPath(),
535                                    destinationFile.getCanonicalPath(), containerType,
536                                    PropsUtil.getProperties(
537                                            PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO, false),
538                                    PropsUtil.getProperties(PropsKeys.XUGGLER_FFPRESET, true));
539    
540                            liferayConverter.convert();
541                    }
542    
543                    addFileToStore(
544                            fileVersion.getCompanyId(), PREVIEW_PATH,
545                            getPreviewFilePath(fileVersion, containerType), destinationFile);
546    
547                    if (_log.isInfoEnabled()) {
548                            _log.info(
549                                    "Xuggler generated a " + containerType + " preview video for " +
550                                            fileVersion.getTitle() + " in " + stopWatch.getTime() +
551                                                    " ms");
552                    }
553            }
554    
555            private void _generateVideoXuggler(
556                    FileVersion fileVersion, File sourceFile, File[] destinationFiles,
557                    int height, int width) {
558    
559                    try {
560                            for (int i = 0; i < destinationFiles.length; i++) {
561                                    _generateVideoXuggler(
562                                            fileVersion, sourceFile, destinationFiles[i],
563                                            _PREVIEW_TYPES[i]);
564                            }
565                    }
566                    catch (CancellationException ce) {
567                            if (_log.isInfoEnabled()) {
568                                    _log.info(
569                                            "Cancellation received for " +
570                                                    fileVersion.getFileVersionId() + " " +
571                                                            fileVersion.getTitle());
572                            }
573                    }
574                    catch (Exception e) {
575                            _log.error(e, e);
576                    }
577            }
578    
579            private boolean _hasVideo(FileVersion fileVersion) throws Exception {
580                    if (!isSupported(fileVersion)) {
581                            return false;
582                    }
583    
584                    return hasPreviews(fileVersion) && hasThumbnails(fileVersion);
585            }
586    
587            private void _queueGeneration(
588                    FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
589    
590                    if (_fileVersionIds.contains(
591                                    destinationFileVersion.getFileVersionId()) ||
592                            !isSupported(destinationFileVersion)) {
593    
594                            return;
595                    }
596    
597                    _fileVersionIds.add(destinationFileVersion.getFileVersionId());
598    
599                    sendGenerationMessage(
600                            DestinationNames.DOCUMENT_LIBRARY_VIDEO_PROCESSOR,
601                            sourceFileVersion, destinationFileVersion);
602            }
603    
604            private static final String[] _PREVIEW_TYPES =
605                    PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_CONTAINERS;
606    
607            private static Log _log = LogFactoryUtil.getLog(VideoProcessorImpl.class);
608    
609            private List<Long> _fileVersionIds = new Vector<Long>();
610            private Set<String> _videoMimeTypes = SetUtil.fromArray(
611                    PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_MIME_TYPES);
612    
613            private static class LiferayVideoProcessCallable
614                    implements ProcessCallable<String> {
615    
616                    public LiferayVideoProcessCallable(
617                            String serverId, String liferayHome,
618                            Map<String, String> customLogSettings, File inputFile,
619                            File outputFile, String videoContainer, Properties videoProperties,
620                            Properties ffpresetProperties) {
621    
622                            _serverId = serverId;
623                            _liferayHome = liferayHome;
624                            _customLogSettings = customLogSettings;
625                            _inputFile = inputFile;
626                            _outputFile = outputFile;
627                            _videoContainer = videoContainer;
628                            _videoProperties = videoProperties;
629                            _ffpresetProperties = ffpresetProperties;
630                    }
631    
632                    @Override
633                    public String call() throws ProcessException {
634                            Properties systemProperties = System.getProperties();
635    
636                            SystemEnv.setProperties(systemProperties);
637    
638                            Class<?> clazz = getClass();
639    
640                            ClassLoader classLoader = clazz.getClassLoader();
641    
642                            Log4JUtil.initLog4J(
643                                    _serverId, _liferayHome, classLoader, new Log4jLogFactoryImpl(),
644                                    _customLogSettings);
645    
646                            try {
647                                    LiferayConverter liferayConverter = new LiferayVideoConverter(
648                                            _inputFile.getCanonicalPath(),
649                                            _outputFile.getCanonicalPath(), _videoContainer,
650                                            _videoProperties, _ffpresetProperties);
651    
652                                    liferayConverter.convert();
653                            }
654                            catch (Exception e) {
655                                    throw new ProcessException(e);
656                            }
657    
658                            return StringPool.BLANK;
659                    }
660    
661                    private static final long serialVersionUID = 1L;
662    
663                    private Map<String, String> _customLogSettings;
664                    private Properties _ffpresetProperties;
665    
666                    @InputResource
667                    private File _inputFile;
668    
669                    private String _liferayHome;
670    
671                    @OutputResource
672                    private File _outputFile;
673    
674                    private String _serverId;
675                    private String _videoContainer;
676                    private Properties _videoProperties;
677    
678            }
679    
680            private static class LiferayVideoThumbnailProcessCallable
681                    implements ProcessCallable<String> {
682    
683                    public LiferayVideoThumbnailProcessCallable(
684                            String serverId, String liferayHome,
685                            Map<String, String> customLogSettings, File inputFile,
686                            File outputFile, String extension, int height, int width,
687                            int percentage) {
688    
689                            _serverId = serverId;
690                            _liferayHome = liferayHome;
691                            _customLogSettings = customLogSettings;
692                            _inputFile = inputFile;
693                            _outputFile = outputFile;
694                            _extension = extension;
695                            _height = height;
696                            _width = width;
697                            _percentage = percentage;
698                    }
699    
700                    @Override
701                    public String call() throws ProcessException {
702                            Class<?> clazz = getClass();
703    
704                            ClassLoader classLoader = clazz.getClassLoader();
705    
706                            Properties systemProperties = System.getProperties();
707                            SystemEnv.setProperties(systemProperties);
708    
709                            Log4JUtil.initLog4J(
710                                    _serverId, _liferayHome, classLoader, new Log4jLogFactoryImpl(),
711                                    _customLogSettings);
712    
713                            try {
714                                    LiferayConverter liferayConverter =
715                                            new LiferayVideoThumbnailConverter(
716                                                    _inputFile.getCanonicalPath(), _outputFile, _extension,
717                                                    _height, _width, _percentage);
718    
719                                    liferayConverter.convert();
720                            }
721                            catch (Exception e) {
722                                    throw new ProcessException(e);
723                            }
724    
725                            return StringPool.BLANK;
726                    }
727    
728                    private static final long serialVersionUID = 1L;
729    
730                    private Map<String, String> _customLogSettings;
731                    private String _extension;
732                    private int _height;
733    
734                    @InputResource
735                    private File _inputFile;
736    
737                    private String _liferayHome;
738    
739                    @OutputResource
740                    private File _outputFile;
741    
742                    private int _percentage;
743                    private String _serverId;
744                    private int _width;
745    
746            }
747    
748    }