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