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