001
014
015 package com.liferay.portlet.documentlibrary.util;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.messaging.DestinationNames;
020 import com.liferay.portal.kernel.messaging.MessageBusException;
021 import com.liferay.portal.kernel.messaging.MessageBusUtil;
022 import com.liferay.portal.kernel.process.ClassPathUtil;
023 import com.liferay.portal.kernel.process.ProcessCallable;
024 import com.liferay.portal.kernel.process.ProcessException;
025 import com.liferay.portal.kernel.process.ProcessExecutor;
026 import com.liferay.portal.kernel.repository.model.FileVersion;
027 import com.liferay.portal.kernel.util.FileUtil;
028 import com.liferay.portal.kernel.util.PropsKeys;
029 import com.liferay.portal.kernel.util.ServerDetector;
030 import com.liferay.portal.kernel.util.SetUtil;
031 import com.liferay.portal.kernel.util.StringBundler;
032 import com.liferay.portal.kernel.util.StringPool;
033 import com.liferay.portal.kernel.util.Validator;
034 import com.liferay.portal.log.Log4jLogFactoryImpl;
035 import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
036 import com.liferay.portal.util.PrefsPropsUtil;
037 import com.liferay.portal.util.PropsUtil;
038 import com.liferay.portal.util.PropsValues;
039 import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
040 import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
041 import com.liferay.util.log4j.Log4JUtil;
042
043 import java.io.File;
044 import java.io.InputStream;
045
046 import java.util.List;
047 import java.util.Map;
048 import java.util.Set;
049 import java.util.Vector;
050
051 import org.apache.commons.lang.time.StopWatch;
052
053
058 public class AudioProcessor extends DefaultPreviewableProcessor {
059
060 public static final String PREVIEW_TYPE = "mp3";
061
062 public static void generateAudio(FileVersion fileVersion) throws Exception {
063 _instance._generateAudio(fileVersion);
064 }
065
066 public static Set<String> getAudioMimeTypes() {
067 return _instance._audioMimeTypes;
068 }
069
070 public static InputStream getPreviewAsStream(FileVersion fileVersion)
071 throws Exception {
072
073 return _instance.doGetPreviewAsStream(fileVersion);
074 }
075
076 public static long getPreviewFileSize(FileVersion fileVersion)
077 throws Exception {
078
079 return _instance.doGetPreviewFileSize(fileVersion);
080 }
081
082 public static boolean hasAudio(FileVersion fileVersion) {
083 boolean hasAudio = false;
084
085 try {
086 hasAudio = _instance._hasAudio(fileVersion);
087
088 if (!hasAudio && _instance.isSupported(fileVersion)) {
089 _instance._queueGeneration(fileVersion);
090 }
091 }
092 catch (Exception e) {
093 _log.error(e, e);
094 }
095
096 return hasAudio;
097 }
098
099 public static boolean isAudioSupported(FileVersion fileVersion) {
100 return _instance.isSupported(fileVersion);
101 }
102
103 public static boolean isAudioSupported(String mimeType) {
104 return _instance.isSupported(mimeType);
105 }
106
107 public AudioProcessor() {
108 FileUtil.mkdirs(PREVIEW_TMP_PATH);
109 }
110
111 public boolean isSupported(String mimeType) {
112 if (Validator.isNull(mimeType)) {
113 return false;
114 }
115
116 try {
117 if (PrefsPropsUtil.getBoolean(
118 PropsKeys.XUGGLER_ENABLED, PropsValues.XUGGLER_ENABLED)) {
119
120 return _audioMimeTypes.contains(mimeType);
121 }
122 }
123 catch (Exception e) {
124 }
125
126 return false;
127 }
128
129 public void trigger(FileVersion fileVersion) {
130 _instance._queueGeneration(fileVersion);
131 }
132
133 @Override
134 protected String getPreviewType() {
135 return PREVIEW_TYPE;
136 }
137
138 private void _generateAudio(FileVersion fileVersion) throws Exception {
139 String tempFileId = DLUtil.getTempFileId(
140 fileVersion.getFileEntryId(), fileVersion.getVersion());
141
142 File audioTempFile = _getAudioTempFile(
143 tempFileId, fileVersion.getExtension());
144 File previewTempFile = getPreviewTempFile(tempFileId);
145
146 try {
147 if (!PrefsPropsUtil.getBoolean(
148 PropsKeys.XUGGLER_ENABLED, PropsValues.XUGGLER_ENABLED) ||
149 _hasAudio(fileVersion)) {
150
151 return;
152 }
153
154 if (_isGeneratePreview(fileVersion)) {
155 File file = null;
156
157 if (fileVersion instanceof LiferayFileVersion) {
158 try {
159 LiferayFileVersion liferayFileVersion =
160 (LiferayFileVersion)fileVersion;
161
162 file = liferayFileVersion.getFile(false);
163 }
164 catch (UnsupportedOperationException uoe) {
165 }
166 }
167
168 if (file == null) {
169 InputStream inputStream = fileVersion.getContentStream(
170 false);
171
172 FileUtil.write(audioTempFile, inputStream);
173
174 file = audioTempFile;
175 }
176
177 try {
178 _generateAudioXuggler(fileVersion, file, previewTempFile);
179 }
180 catch (Exception e) {
181 _log.error(e, e);
182 }
183 }
184 }
185 catch (NoSuchFileEntryException nsfee) {
186 }
187 finally {
188 _fileVersionIds.remove(fileVersion.getFileVersionId());
189
190 FileUtil.delete(audioTempFile);
191 FileUtil.delete(previewTempFile);
192 }
193 }
194
195 private void _generateAudioXuggler(
196 FileVersion fileVersion, File srcFile, File destFile)
197 throws Exception {
198
199 StopWatch stopWatch = null;
200
201 if (_log.isInfoEnabled()) {
202 stopWatch = new StopWatch();
203
204 stopWatch.start();
205 }
206
207 try {
208 ProcessCallable<String> processCallable =
209 new LiferayAudioProcessCallable(
210 ServerDetector.getServerId(),
211 PropsUtil.get(PropsKeys.LIFERAY_HOME),
212 Log4JUtil.getCustomLogSettings(),
213 srcFile.getCanonicalPath(), destFile.getCanonicalPath());
214
215 ProcessExecutor.execute(
216 processCallable, ClassPathUtil.getPortalClassPath());
217 }
218 catch (Exception e) {
219 _log.error(e, e);
220 }
221
222 addFileToStore(
223 fileVersion.getCompanyId(), PREVIEW_PATH,
224 getPreviewFilePath(fileVersion), destFile);
225
226 if (_log.isInfoEnabled()) {
227 _log.info(
228 "Xuggler generated a preview audio for " +
229 fileVersion.getTitle() + " in " + stopWatch);
230 }
231 }
232
233 private File _getAudioTempFile(String tempFileId, String targetExtension) {
234 String audioTempFilePath = _getAudioTempFilePath(
235 tempFileId, targetExtension);
236
237 return new File(audioTempFilePath);
238 }
239
240 private String _getAudioTempFilePath(
241 String tempFileId, String targetExtension) {
242
243 StringBundler sb = new StringBundler(5);
244
245 sb.append(PREVIEW_TMP_PATH);
246 sb.append(tempFileId);
247
248 if (PREVIEW_TYPE.equals(targetExtension)) {
249 sb.append("_tmp");
250 }
251
252 sb.append(StringPool.PERIOD);
253 sb.append(targetExtension);
254
255 return sb.toString();
256 }
257
258 private boolean _hasAudio(FileVersion fileVersion) throws Exception {
259 if (!isSupported(fileVersion)) {
260 return false;
261 }
262
263 boolean previewExists = DLStoreUtil.hasFile(
264 fileVersion.getCompanyId(), REPOSITORY_ID,
265 getPreviewFilePath(fileVersion));
266
267 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED && previewExists) {
268 return true;
269 }
270
271 return false;
272 }
273
274 private boolean _isGeneratePreview(FileVersion fileVersion)
275 throws Exception {
276
277 String previewFilePath = getPreviewFilePath(fileVersion);
278
279 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
280 !DLStoreUtil.hasFile(
281 fileVersion.getCompanyId(), REPOSITORY_ID, previewFilePath)) {
282
283 return true;
284 }
285 else {
286 return false;
287 }
288 }
289
290 private void _queueGeneration(FileVersion fileVersion) {
291 if (_fileVersionIds.contains(fileVersion.getFileVersionId()) ||
292 !isSupported(fileVersion)) {
293
294 return;
295 }
296
297 _fileVersionIds.add(fileVersion.getFileVersionId());
298
299 if (PropsValues.DL_FILE_ENTRY_PROCESSORS_TRIGGER_SYNCHRONOUSLY) {
300 try {
301 MessageBusUtil.sendSynchronousMessage(
302 DestinationNames.DOCUMENT_LIBRARY_AUDIO_PROCESSOR,
303 fileVersion);
304 }
305 catch (MessageBusException mbe) {
306 if (_log.isWarnEnabled()) {
307 _log.warn(mbe, mbe);
308 }
309 }
310 }
311 else {
312 MessageBusUtil.sendMessage(
313 DestinationNames.DOCUMENT_LIBRARY_AUDIO_PROCESSOR, fileVersion);
314 }
315 }
316
317 private static Log _log = LogFactoryUtil.getLog(AudioProcessor.class);
318
319 private static AudioProcessor _instance = new AudioProcessor();
320
321 private Set<String> _audioMimeTypes = SetUtil.fromArray(
322 PropsValues.DL_FILE_ENTRY_PREVIEW_AUDIO_MIME_TYPES);
323 private List<Long> _fileVersionIds = new Vector<Long>();
324
325 private static class LiferayAudioProcessCallable
326 implements ProcessCallable<String> {
327
328 public LiferayAudioProcessCallable(
329 String serverId, String liferayHome,
330 Map<String, String> customLogSettings, String inputURL,
331 String outputURL) {
332
333 _serverId = serverId;
334 _liferayHome = liferayHome;
335 _customLogSettings = customLogSettings;
336 _inputURL = inputURL;
337 _outputURL = outputURL;
338 }
339
340 public String call() throws ProcessException {
341 Class<?> clazz = getClass();
342
343 ClassLoader classLoader = clazz.getClassLoader();
344
345 Log4JUtil.initLog4J(
346 _serverId, _liferayHome, classLoader, new Log4jLogFactoryImpl(),
347 _customLogSettings);
348
349 try {
350 LiferayConverter liferayConverter = new LiferayAudioConverter(
351 _inputURL, _outputURL);
352
353 liferayConverter.convert();
354 }
355 catch (Exception e) {
356 throw new ProcessException(e);
357 }
358
359 return StringPool.BLANK;
360 }
361
362 private Map<String, String> _customLogSettings;
363 private String _inputURL;
364 private String _liferayHome;
365 private String _outputURL;
366 private String _serverId;
367
368 }
369
370 }