/**
* Copyright (c) 2000-present 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.configuration.Filter;
import com.liferay.portal.kernel.io.DummyOutputStream;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.process.ClassPathUtil;
import com.liferay.portal.kernel.process.ProcessException;
import com.liferay.portal.kernel.util.OSDetector;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.ReflectionUtil;
import com.liferay.portal.kernel.util.SetUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xuggler.Xuggler;
import com.liferay.portal.kernel.xuggler.XugglerInstallException;
import com.liferay.portal.util.PropsUtil;
import com.liferay.portal.xuggler.XugglerImpl;
import com.xuggle.ferry.JNILibrary;
import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Shuyang Zhou
*/
public class XugglerAutoInstallHelper {
public static void installNativeLibraries() throws ProcessException {
if (_isNativeLibraryInstalled()) {
if (_log.isDebugEnabled()) {
_log.debug("Xuggler is already installed");
}
return;
}
String xugglerJarFile = _getXugglerJarFileName();
if (xugglerJarFile == null) {
_log.error(
"Xuggler auto install is not supported on system: " +
System.getProperty("os.name") + "/" +
System.getProperty("os.arch"));
return;
}
ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
PortalClassLoaderUtil.setClassLoader(
ClassLoader.getSystemClassLoader());
try {
Xuggler xuggler = new XugglerImpl();
try {
xuggler.installNativeLibraries(xugglerJarFile);
}
catch (XugglerInstallException.MustBeURLClassLoader xie) {
if (_log.isDebugEnabled()) {
_log.debug(xie, xie);
}
}
catch (Exception e) {
throw new ProcessException(e);
}
if (xuggler.isNativeLibraryInstalled()) {
if (_log.isInfoEnabled()) {
_log.info("Xuggler installed successfully");
}
}
else {
_log.error("Xuggler auto install failed");
}
}
finally {
PortalClassLoaderUtil.setClassLoader(classLoader);
}
}
public static class IsNativeLibraryInstalledCallable
implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
PrintStream printStream = System.out;
System.setOut(new PrintStream(new DummyOutputStream()));
Package pkg = JNILibrary.class.getPackage();
Logger logger = Logger.getLogger(pkg.getName());
Level level = logger.getLevel();
logger.setLevel(Level.OFF);
String property = System.getProperty(
"java.util.logging.config.file");
System.setProperty("java.util.logging.config.file", "configFile");
Xuggler xuggler = new XugglerImpl();
Field informAdministratorField = ReflectionUtil.getDeclaredField(
XugglerImpl.class, "_informAdministrator");
informAdministratorField.setBoolean(xuggler, false);
try {
return xuggler.isNativeLibraryInstalled();
}
finally {
if (property == null) {
System.clearProperty("java.util.logging.config.file");
}
else {
System.setProperty(
"java.util.logging.config.file", property);
}
logger.setLevel(level);
System.setOut(printStream);
}
}
}
private static String _getXugglerJarFileName() {
String bitmode = OSDetector.getBitmode();
if (Validator.isNull(bitmode) ||
(!bitmode.equals("32") && !bitmode.equals("64"))) {
return null;
}
if (OSDetector.isApple()) {
return PropsUtil.get(
PropsKeys.XUGGLER_JAR_FILE, new Filter(bitmode + "-mac"));
}
if (OSDetector.isLinux()) {
return PropsUtil.get(
PropsKeys.XUGGLER_JAR_FILE, new Filter(bitmode + "-linux"));
}
if (OSDetector.isWindows()) {
return PropsUtil.get(
PropsKeys.XUGGLER_JAR_FILE, new Filter(bitmode + "-win"));
}
return null;
}
private static boolean _isNativeLibraryInstalled() {
Properties properties = PropsUtil.getProperties(
PropsKeys.XUGGLER_JAR_FILE, false);
Set<Object> jarFiles = SetUtil.fromCollection(properties.values());
jarFiles.remove(_getXugglerJarFileName());
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
Set<URL> urls = ClassPathUtil.getClassPathURLs(contextClassLoader);
Iterator<URL> iterator = urls.iterator();
while (iterator.hasNext()) {
URL url = iterator.next();
String protocol = url.getProtocol();
if (protocol.equals("file")) {
File file = new File(url.getPath());
Matcher matcher = _pattern.matcher(file.getName());
if (matcher.matches()) {
if (jarFiles.contains(matcher.replaceAll("$1$2"))) {
file.delete();
iterator.remove();
}
}
}
}
URLClassLoader urlClassLoader = new URLClassLoader(
urls.toArray(new URL[urls.size()]), null);
currentThread.setContextClassLoader(urlClassLoader);
try {
Class<Callable<Boolean>> clazz =
(Class<Callable<Boolean>>)urlClassLoader.loadClass(
IsNativeLibraryInstalledCallable.class.getName());
Callable<Boolean> callable = clazz.newInstance();
return callable.call();
}
catch (Exception e) {
return false;
}
finally {
currentThread.setContextClassLoader(contextClassLoader);
}
}
private static final Log _log = LogFactoryUtil.getLog(
XugglerAutoInstallHelper.class);
private static final Pattern _pattern = Pattern.compile(
"(.*)-\\d+-\\d+(\\.jar)");
}