platform: unified loading of system libraries (done right)

This commit is contained in:
Roman Shevchenko
2013-08-26 00:20:47 +04:00
parent d492a6fd7d
commit c33dc4a870
5 changed files with 31 additions and 76 deletions
@@ -62,7 +62,6 @@ public class BootstrapClassLoaderUtil extends ClassUtilCore {
addAdditionalClassPath(classpath);
UrlClassLoader newClassLoader = UrlClassLoader.build()
.urls(filterClassPath(classpath))
.nativeLibs("IdeaWin32", "focusKiller", "jumpListBridge")
.allowLock().useCache().get();
// prepare plugins
@@ -30,6 +30,7 @@ import com.intellij.ui.AppUIUtil;
import com.intellij.util.Consumer;
import com.intellij.util.EnvironmentUtil;
import com.intellij.util.SnappyInitializer;
import com.intellij.util.lang.UrlClassLoader;
import com.intellij.util.text.DateFormatUtilRt;
import com.sun.jna.Native;
import org.jetbrains.annotations.NonNls;
@@ -246,7 +247,7 @@ public class StartupUtil {
if (SystemInfo.isWin2kOrNewer && !Main.isHeadless()) {
try {
System.loadLibrary("focusKiller");
UrlClassLoader.loadPlatformLibrary("focusKiller");
log.info("Using \"FocusKiller\" library to prevent focus stealing.");
}
catch (Throwable t) {
@@ -16,6 +16,7 @@
package com.intellij.ui.win;
import com.intellij.idea.StartupUtil;
import com.intellij.util.lang.UrlClassLoader;
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -29,7 +30,7 @@ public class RecentTasks {
new WeakReference<Thread>(Thread.currentThread());
static {
System.loadLibrary("jumpListBridge");
UrlClassLoader.loadPlatformLibrary("jumpListBridge");
}
private synchronized static void init() {
@@ -15,16 +15,12 @@
*/
package com.intellij.openapi.util.io.win32;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.lang.UrlClassLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
/**
* Do not use this class directly.
*
@@ -38,36 +34,10 @@ public class IdeaWin32 {
private static final IdeaWin32 ourInstance;
static {
boolean available = false;
if (SystemInfo.isWin2kOrNewer) {
String libName = SystemInfo.is64Bit ? "IdeaWin64.dll" : "IdeaWin32.dll";
try {
String path = PathManager.getBinPath() + "/" + libName;
if (!new File(path).exists()) {
path = PathManager.getHomePath() + "/community/bin/win/" + libName;
if (!new File(path).exists()) {
path = PathManager.getHomePath() + "/bin/win/" + libName;
if (!new File(path).exists()) {
path = PathManager.getHomePathFor(IdeaWin32.class) + "/bin/" + libName;
if (!new File(path).exists()) {
throw new FileNotFoundException("Native filesystem .dll is missing (path=" + PathManager.getBinPath() +
" content=" + Arrays.toString(new File(PathManager.getBinPath()).list()) + ")");
}
}
}
}
LOG.debug("Loading " + path);
System.load(path);
available = true;
}
catch (Throwable t) {
LOG.error("Failed to load native filesystem for Windows", t);
}
}
IdeaWin32 instance = null;
if (available) {
if (SystemInfo.isWin2kOrNewer) {
try {
UrlClassLoader.loadPlatformLibrary("IdeaWin32");
instance = new IdeaWin32();
LOG.info("Native filesystem for Windows is operational");
}
@@ -18,6 +18,7 @@ package com.intellij.util.lang;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.win32.IdeaWin32;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
@@ -31,7 +32,10 @@ import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
public class UrlClassLoader extends ClassLoader {
@NonNls static final String CLASS_EXTENSION = ".class";
@@ -43,7 +47,6 @@ public class UrlClassLoader extends ClassLoader {
private boolean myUseCache = false;
private boolean myAcceptUnescaped = false;
private boolean myPreload = true;
private String[] myNativeLibs = null;
private Builder() { }
@@ -56,7 +59,6 @@ public class UrlClassLoader extends ClassLoader {
public Builder useCache(boolean useCache) { myUseCache = useCache; return this; }
public Builder allowUnescaped() { myAcceptUnescaped = true; return this; }
public Builder noPreload() { myPreload = false; return this; }
public Builder nativeLibs(String... libNames) { myNativeLibs = libNames; return this; }
public UrlClassLoader get() { return new UrlClassLoader(this); }
}
@@ -66,7 +68,6 @@ public class UrlClassLoader extends ClassLoader {
private final List<URL> myURLs;
private final ClassPath myClassPath;
private final Set<String> myNativeLibs;
/** @deprecated use {@link #build()} (to remove in IDEA 14) */
public UrlClassLoader(@NotNull ClassLoader parent) {
@@ -98,7 +99,6 @@ public class UrlClassLoader extends ClassLoader {
}
});
myClassPath = new ClassPath(myURLs, lockJars, useCache, allowUnescaped, preload);
myNativeLibs = Collections.emptySet();
}
protected UrlClassLoader(@NotNull Builder builder) {
@@ -110,7 +110,6 @@ public class UrlClassLoader extends ClassLoader {
}
});
myClassPath = new ClassPath(myURLs, builder.myLockJars, builder.myUseCache, builder.myAcceptUnescaped, builder.myPreload);
myNativeLibs = builder.myNativeLibs != null ? ContainerUtil.newHashSet(builder.myNativeLibs) : Collections.<String>emptySet();
}
public static URL internProtocol(@NotNull URL url) {
@@ -151,12 +150,6 @@ public class UrlClassLoader extends ClassLoader {
}
}
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
return super.loadClass(name, resolve);
}
@Nullable
protected Class _findClass(@NotNull String name) {
Resource res = myClassPath.getResource(name.replace('.', '/').concat(CLASS_EXTENSION), false);
@@ -233,38 +226,22 @@ public class UrlClassLoader extends ClassLoader {
return myClassPath.getResources(name, true);
}
@Override
protected String findLibrary(String libName) {
if (BinPathHolder.path != null && myNativeLibs.contains(libName)) {
String fileName = mapLibraryName(libName);
return BinPathHolder.path + File.separator + fileName;
}
public static void loadPlatformLibrary(@NotNull String libName) {
String libFileName = mapLibraryName(libName);
String libPath = PathManager.getBinPath() + "/" + libFileName;
return super.findLibrary(libName);
}
private static class BinPathHolder {
private static final String path;
static {
String homePath = PathManager.getHomePath();
if (new File(homePath, ".idea").exists()) {
if (new File(homePath, "community").exists()) {
homePath += File.separator + "community";
if (!new File(libPath).exists()) {
String platform = getPlatformName();
if (!new File(libPath = PathManager.getHomePath() + "/community/bin/" + platform + libFileName).exists()) {
if (!new File(libPath = PathManager.getHomePath() + "/bin/" + platform + libFileName).exists()) {
if (!new File(libPath = PathManager.getHomePathFor(IdeaWin32.class) + "/bin/" + libFileName).exists()) {
throw new UnsatisfiedLinkError("'" + libFileName + "' not found among " + Arrays.toString(new File(PathManager.getBinPath()).listFiles()));
}
}
String libDir = null;
String prefix = homePath + File.separator + "bin" + File.separator;
if (SystemInfo.isWindows) libDir = prefix + "win";
else if (SystemInfo.isMac) libDir = prefix + "mac";
else if (SystemInfo.isLinux) libDir = prefix + "linux";
path = libDir;
}
else {
path = PathManager.getBinPath();
}
}
System.load(libPath);
}
private static String mapLibraryName(String libName) {
@@ -278,4 +255,11 @@ public class UrlClassLoader extends ClassLoader {
}
return fileName;
}
private static String getPlatformName() {
if (SystemInfo.isWindows) return "win/";
else if (SystemInfo.isMac) return "mac/";
else if (SystemInfo.isLinux) return "linux/";
else return "";
}
}