Java tutorial
/** * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portlet.documentlibrary.util; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.kernel.image.ImageBag; import com.liferay.portal.kernel.image.ImageToolUtil; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.messaging.DestinationNames; import com.liferay.portal.kernel.messaging.MessageBusException; import com.liferay.portal.kernel.messaging.MessageBusUtil; import com.liferay.portal.kernel.process.ClassPathUtil; import com.liferay.portal.kernel.process.ProcessCallable; import com.liferay.portal.kernel.process.ProcessException; import com.liferay.portal.kernel.process.ProcessExecutor; import com.liferay.portal.kernel.repository.model.FileVersion; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.InstancePool; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.ServerDetector; import com.liferay.portal.kernel.util.SetUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.log.Log4jLogFactoryImpl; import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion; import com.liferay.portal.util.PrefsPropsUtil; import com.liferay.portal.util.PropsUtil; import com.liferay.portal.util.PropsValues; import com.liferay.portlet.documentlibrary.NoSuchFileEntryException; import com.liferay.portlet.documentlibrary.store.DLStoreUtil; import com.liferay.util.log4j.Log4JUtil; import java.awt.image.RenderedImage; import java.io.File; import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.Vector; import org.apache.commons.lang.time.StopWatch; /** * @author Juan Gonzlez * @author Sergio Gonzlez * @author Mika Koivisto */ public class VideoProcessorImpl extends DefaultPreviewableProcessor implements VideoProcessor { public static VideoProcessorImpl getInstance() { return _instance; } public void generateVideo(FileVersion fileVersion) throws Exception { _instance._generateVideo(fileVersion); } public InputStream getPreviewAsStream(FileVersion fileVersion) throws Exception { return _instance.doGetPreviewAsStream(fileVersion); } public InputStream getPreviewAsStream(FileVersion fileVersion, String type) throws Exception { return _instance.doGetPreviewAsStream(fileVersion, type); } public long getPreviewFileSize(FileVersion fileVersion) throws Exception { return _instance.doGetPreviewFileSize(fileVersion); } public long getPreviewFileSize(FileVersion fileVersion, String type) throws Exception { return _instance.doGetPreviewFileSize(fileVersion, type); } public InputStream getThumbnailAsStream(FileVersion fileVersion, int thumbnailIndex) throws Exception { return _instance.doGetThumbnailAsStream(fileVersion, thumbnailIndex); } public long getThumbnailFileSize(FileVersion fileVersion, int thumbnailIndex) throws Exception { return _instance.doGetThumbnailFileSize(fileVersion, thumbnailIndex); } public Set<String> getVideoMimeTypes() { return _instance._videoMimeTypes; } public boolean hasVideo(FileVersion fileVersion) { boolean hasVideo = false; try { hasVideo = _instance._hasVideo(fileVersion); if (!hasVideo && _instance.isSupported(fileVersion)) { _instance._queueGeneration(fileVersion); } } catch (Exception e) { _log.error(e, e); } return hasVideo; } public boolean isVideoSupported(FileVersion fileVersion) { return _instance.isSupported(fileVersion); } public boolean isVideoSupported(String mimeType) { return _instance.isSupported(mimeType); } public boolean isSupported(String mimeType) { if (Validator.isNull(mimeType)) { return false; } try { if (PrefsPropsUtil.getBoolean(PropsKeys.XUGGLER_ENABLED, PropsValues.XUGGLER_ENABLED)) { return _videoMimeTypes.contains(mimeType); } } catch (Exception e) { } return false; } public void trigger(FileVersion fileVersion) { _instance._queueGeneration(fileVersion); } @Override protected String getPreviewType(FileVersion fileVersion) { return _PREVIEW_TYPES[0]; } @Override protected String[] getPreviewTypes() { return _PREVIEW_TYPES; } @Override protected String getThumbnailType(FileVersion fileVersion) { return THUMBNAIL_TYPE; } @Override protected void storeThumbnailImages(FileVersion fileVersion, File file) throws Exception { addFileToStore(fileVersion.getCompanyId(), THUMBNAIL_PATH, getThumbnailFilePath(fileVersion, THUMBNAIL_INDEX_DEFAULT), file); if (isCustomThumbnailsEnabled(1) || isCustomThumbnailsEnabled(2)) { ImageBag imageBag = ImageToolUtil.read(file); RenderedImage renderedImage = imageBag.getRenderedImage(); storeThumbnailmage(fileVersion, renderedImage, THUMBNAIL_INDEX_CUSTOM_1); storeThumbnailmage(fileVersion, renderedImage, THUMBNAIL_INDEX_CUSTOM_2); } } private VideoProcessorImpl() { boolean valid = true; if ((_PREVIEW_TYPES.length == 0) || (_PREVIEW_TYPES.length > 2)) { valid = false; } else { for (String previewType : _PREVIEW_TYPES) { if (!previewType.equals("mp4") && !previewType.equals("ogv")) { valid = false; break; } } } if (!valid && _log.isWarnEnabled()) { StringBundler sb = new StringBundler(5); sb.append("Liferay is incorrectly configured to generate video "); sb.append("previews using video containers other than MP4 or "); sb.append("OGV. Please change the property "); sb.append(PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO_CONTAINERS); sb.append(" in portal-ext.properties."); _log.warn(sb.toString()); } FileUtil.mkdirs(PREVIEW_TMP_PATH); FileUtil.mkdirs(THUMBNAIL_TMP_PATH); } private void _generateThumbnailXuggler(FileVersion fileVersion, File file, int height, int width) throws Exception { StopWatch stopWatch = null; if (_log.isInfoEnabled()) { stopWatch = new StopWatch(); stopWatch.start(); } String tempFileId = DLUtil.getTempFileId(fileVersion.getFileEntryId(), fileVersion.getVersion()); File thumbnailTempFile = getThumbnailTempFile(tempFileId); try { try { if (PropsValues.DL_FILE_ENTRY_PREVIEW_FORK_PROCESS_ENABLED) { ProcessCallable<String> processCallable = new LiferayVideoThumbnailProcessCallable( ServerDetector.getServerId(), PropsUtil.get(PropsKeys.LIFERAY_HOME), Log4JUtil.getCustomLogSettings(), file.getCanonicalPath(), thumbnailTempFile, THUMBNAIL_TYPE, height, width, PropsValues.DL_FILE_ENTRY_THUMBNAIL_VIDEO_FRAME_PERCENTAGE); ProcessExecutor.execute(processCallable, ClassPathUtil.getPortalClassPath()); } else { LiferayConverter liferayConverter = new LiferayVideoThumbnailConverter(file.getCanonicalPath(), thumbnailTempFile, THUMBNAIL_TYPE, height, width, PropsValues.DL_FILE_ENTRY_THUMBNAIL_VIDEO_FRAME_PERCENTAGE); liferayConverter.convert(); } } catch (Exception e) { _log.error(e, e); } storeThumbnailImages(fileVersion, thumbnailTempFile); if (_log.isInfoEnabled()) { _log.info("Xuggler generated a thumbnail for " + fileVersion.getTitle() + " in " + stopWatch); } } catch (Exception e) { throw new SystemException(e); } finally { FileUtil.delete(thumbnailTempFile); } } private void _generateVideo(FileVersion fileVersion) throws Exception { String tempFileId = DLUtil.getTempFileId(fileVersion.getFileEntryId(), fileVersion.getVersion()); File videoTempFile = _getVideoTempFile(tempFileId, fileVersion.getExtension()); File[] previewTempFiles = new File[_PREVIEW_TYPES.length]; for (int i = 0; i < _PREVIEW_TYPES.length; i++) { previewTempFiles[i] = getPreviewTempFile(tempFileId, _PREVIEW_TYPES[i]); } try { if (!PrefsPropsUtil.getBoolean(PropsKeys.XUGGLER_ENABLED, PropsValues.XUGGLER_ENABLED) || _hasVideo(fileVersion)) { return; } File file = null; if (_isGeneratePreview(fileVersion) || _isGenerateThumbnail(fileVersion)) { if (fileVersion instanceof LiferayFileVersion) { try { LiferayFileVersion liferayFileVersion = (LiferayFileVersion) fileVersion; file = liferayFileVersion.getFile(false); } catch (UnsupportedOperationException uoe) { } } if (file == null) { InputStream inputStream = fileVersion.getContentStream(false); FileUtil.write(videoTempFile, inputStream); file = videoTempFile; } } if (_isGeneratePreview(fileVersion)) { try { _generateVideoXuggler(fileVersion, file, previewTempFiles, PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_HEIGHT, PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_WIDTH); } catch (Exception e) { _log.error(e, e); } } if (_isGenerateThumbnail(fileVersion)) { try { _generateThumbnailXuggler(fileVersion, file, PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_HEIGHT, PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_WIDTH); } catch (Exception e) { _log.error(e, e); } } } catch (NoSuchFileEntryException nsfee) { } finally { _fileVersionIds.remove(fileVersion.getFileVersionId()); for (int i = 0; i < previewTempFiles.length; i++) { FileUtil.delete(previewTempFiles[i]); } FileUtil.delete(videoTempFile); } } private void _generateVideoXuggler(FileVersion fileVersion, File srcFile, File destFile, String containerType) throws Exception { if (!_isGeneratePreview(fileVersion, containerType)) { return; } StopWatch stopWatch = null; if (_log.isInfoEnabled()) { stopWatch = new StopWatch(); stopWatch.start(); } if (PropsValues.DL_FILE_ENTRY_PREVIEW_FORK_PROCESS_ENABLED) { ProcessCallable<String> processCallable = new LiferayVideoProcessCallable(ServerDetector.getServerId(), PropsUtil.get(PropsKeys.LIFERAY_HOME), Log4JUtil.getCustomLogSettings(), srcFile.getCanonicalPath(), destFile.getCanonicalPath(), FileUtil.createTempFileName(), PropsUtil.getProperties(PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO, false), PropsUtil.getProperties(PropsKeys.XUGGLER_FFPRESET, true)); ProcessExecutor.execute(processCallable, ClassPathUtil.getPortalClassPath()); } else { LiferayConverter liferayConverter = new LiferayVideoConverter(srcFile.getCanonicalPath(), destFile.getCanonicalPath(), FileUtil.createTempFileName(), PropsUtil.getProperties(PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO, false), PropsUtil.getProperties(PropsKeys.XUGGLER_FFPRESET, true)); liferayConverter.convert(); } addFileToStore(fileVersion.getCompanyId(), PREVIEW_PATH, getPreviewFilePath(fileVersion, containerType), destFile); if (_log.isInfoEnabled()) { _log.info("Xuggler generated a " + containerType + " preview video for " + fileVersion.getTitle() + " in " + stopWatch); } } private void _generateVideoXuggler(FileVersion fileVersion, File srcFile, File[] destFiles, int height, int width) { try { for (int i = 0; i < destFiles.length; i++) { _generateVideoXuggler(fileVersion, srcFile, destFiles[i], _PREVIEW_TYPES[i]); } } catch (Exception e) { _log.error(e, e); } } private File _getVideoTempFile(String tempFileId, String targetExtension) { String videoTempFilePath = _getVideoTempFilePath(tempFileId, targetExtension); return new File(videoTempFilePath); } private String _getVideoTempFilePath(String tempFileId, String targetExtension) { StringBundler sb = new StringBundler(5); sb.append(PREVIEW_TMP_PATH); sb.append(tempFileId); for (int i = 0; i < _PREVIEW_TYPES.length; i++) { if (_PREVIEW_TYPES[i].equals(targetExtension)) { sb.append("_tmp"); break; } } sb.append(StringPool.PERIOD); sb.append(targetExtension); return sb.toString(); } private boolean _hasVideo(FileVersion fileVersion) throws Exception { if (!isSupported(fileVersion)) { return false; } int previewsCount = 0; for (int i = 0; i < _PREVIEW_TYPES.length; i++) { String previewFilePath = getPreviewFilePath(fileVersion, _PREVIEW_TYPES[i]); if (DLStoreUtil.hasFile(fileVersion.getCompanyId(), REPOSITORY_ID, previewFilePath)) { previewsCount++; } } if (previewsCount != _PREVIEW_TYPES.length) { return false; } if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) { if (!hasThumbnail(fileVersion, THUMBNAIL_INDEX_DEFAULT)) { return false; } } try { if (isCustomThumbnailsEnabled(1)) { if (!hasThumbnail(fileVersion, THUMBNAIL_INDEX_CUSTOM_1)) { return false; } } if (isCustomThumbnailsEnabled(2)) { if (!hasThumbnail(fileVersion, THUMBNAIL_INDEX_CUSTOM_2)) { return false; } } } catch (Exception e) { _log.error(e, e); } return true; } private boolean _isGeneratePreview(FileVersion fileVersion) throws Exception { int contPreviewsCreated = 0; for (int i = 0; i < _PREVIEW_TYPES.length; i++) { if (!_isGeneratePreview(fileVersion, _PREVIEW_TYPES[i])) { contPreviewsCreated++; } } if (contPreviewsCreated < _PREVIEW_TYPES.length) { return true; } else { return false; } } private boolean _isGeneratePreview(FileVersion fileVersion, String previewType) throws Exception { String previewFilePath = getPreviewFilePath(fileVersion, previewType); if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED && !DLStoreUtil.hasFile(fileVersion.getCompanyId(), REPOSITORY_ID, previewFilePath)) { return true; } return false; } private boolean _isGenerateThumbnail(FileVersion fileVersion) throws Exception { String thumbnailFilePath = getThumbnailFilePath(fileVersion, THUMBNAIL_INDEX_DEFAULT); if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED && !DLStoreUtil.hasFile(fileVersion.getCompanyId(), REPOSITORY_ID, thumbnailFilePath)) { return true; } else { return false; } } private void _queueGeneration(FileVersion fileVersion) { if (_fileVersionIds.contains(fileVersion.getFileVersionId()) || !isSupported(fileVersion)) { return; } _fileVersionIds.add(fileVersion.getFileVersionId()); if (PropsValues.DL_FILE_ENTRY_PROCESSORS_TRIGGER_SYNCHRONOUSLY) { try { MessageBusUtil.sendSynchronousMessage(DestinationNames.DOCUMENT_LIBRARY_VIDEO_PROCESSOR, fileVersion); } catch (MessageBusException mbe) { if (_log.isWarnEnabled()) { _log.warn(mbe, mbe); } } } else { MessageBusUtil.sendMessage(DestinationNames.DOCUMENT_LIBRARY_VIDEO_PROCESSOR, fileVersion); } } private static final String[] _PREVIEW_TYPES = PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_CONTAINERS; private static Log _log = LogFactoryUtil.getLog(VideoProcessorImpl.class); private static VideoProcessorImpl _instance = new VideoProcessorImpl(); static { InstancePool.put(VideoProcessorImpl.class.getName(), _instance); } private Set<String> _videoMimeTypes = SetUtil.fromArray(PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_MIME_TYPES); private List<Long> _fileVersionIds = new Vector<Long>(); private static class LiferayVideoProcessCallable implements ProcessCallable<String> { public LiferayVideoProcessCallable(String serverId, String liferayHome, Map<String, String> customLogSettings, String inputURL, String outputURL, String tempFileName, Properties videoProperties, Properties ffpresetProperties) { _serverId = serverId; _liferayHome = liferayHome; _customLogSettings = customLogSettings; _inputURL = inputURL; _outputURL = outputURL; _tempFileName = tempFileName; _videoProperties = videoProperties; _ffpresetProperties = ffpresetProperties; } public String call() throws ProcessException { Class<?> clazz = getClass(); ClassLoader classLoader = clazz.getClassLoader(); Log4JUtil.initLog4J(_serverId, _liferayHome, classLoader, new Log4jLogFactoryImpl(), _customLogSettings); try { LiferayConverter liferayConverter = new LiferayVideoConverter(_inputURL, _outputURL, _tempFileName, _videoProperties, _ffpresetProperties); liferayConverter.convert(); } catch (Exception e) { throw new ProcessException(e); } return StringPool.BLANK; } private Map<String, String> _customLogSettings; private Properties _ffpresetProperties; private String _inputURL; private String _liferayHome; private String _outputURL; private String _serverId; private String _tempFileName; private Properties _videoProperties; } private static class LiferayVideoThumbnailProcessCallable implements ProcessCallable<String> { public LiferayVideoThumbnailProcessCallable(String serverId, String liferayHome, Map<String, String> customLogSettings, String inputURL, File outputFile, String extension, int height, int width, int percentage) { _serverId = serverId; _liferayHome = liferayHome; _customLogSettings = customLogSettings; _inputURL = inputURL; _outputFile = outputFile; _extension = extension; _height = height; _width = width; _percentage = percentage; } public String call() throws ProcessException { Class<?> clazz = getClass(); ClassLoader classLoader = clazz.getClassLoader(); Log4JUtil.initLog4J(_serverId, _liferayHome, classLoader, new Log4jLogFactoryImpl(), _customLogSettings); try { LiferayConverter liferayConverter = new LiferayVideoThumbnailConverter(_inputURL, _outputFile, _extension, _height, _width, _percentage); liferayConverter.convert(); } catch (Exception e) { throw new ProcessException(e); } return StringPool.BLANK; } private Map<String, String> _customLogSettings; private String _extension; private int _height; private String _inputURL; private String _liferayHome; private File _outputFile; private int _percentage; private String _serverId; private int _width; } }