platform: URL class loader builder

This commit is contained in:
Roman Shevchenko
2013-08-23 13:49:59 +04:00
parent 2a785d25fa
commit d0b8432dd3
14 changed files with 105 additions and 64 deletions
@@ -56,11 +56,11 @@ public class BootstrapClassLoaderUtil extends ClassUtilCore {
public static UrlClassLoader initClassLoader(boolean updatePlugins) throws Exception {
PathManager.loadProperties();
List<URL> classpathElements = new ArrayList<URL>();
addParentClasspath(classpathElements);
addIDEALibraries(classpathElements);
addAdditionalClassPath(classpathElements);
UrlClassLoader newClassLoader = new UrlClassLoader(filterClassPath(classpathElements), null, true, true);
List<URL> classpath = new ArrayList<URL>();
addParentClasspath(classpath);
addIDEALibraries(classpath);
addAdditionalClassPath(classpath);
UrlClassLoader newClassLoader = UrlClassLoader.build().urls(filterClassPath(classpath)).allowLock().useCache().get();
// prepare plugins
if (updatePlugins && !isLoadingOfExternalPluginsDisabled()) {
@@ -47,7 +47,7 @@ public class PluginClassLoader extends UrlClassLoader {
final PluginId pluginId,
final String version,
final File pluginRoot) {
super(urls, null, true, true);
super(build().urls(urls).allowLock().useCache());
myParents = parents;
myPluginId = pluginId;
myPluginVersion = version;
@@ -270,7 +270,7 @@ public class ExternalSystemApiUtil {
}
return result;
}
@SuppressWarnings("unchecked")
@NotNull
public static <T> Collection<DataNode<T>> getChildren(@NotNull DataNode<?> node, @NotNull Key<T> key) {
@@ -341,7 +341,7 @@ public class ExternalSystemApiUtil {
}
});
}
public static void executeOnEdt(boolean synchronous, @NotNull Runnable task) {
if (synchronous) {
if (ApplicationManager.getApplication().isDispatchThread()) {
@@ -393,7 +393,7 @@ public class ExternalSystemApiUtil {
* </pre>
* This method allows to differentiate between them (e.g. we don't want to change language level when new module is imported to
* an existing project).
*
*
* @return <code>true</code> if new project is being imported; <code>false</code> if new module is being imported
*/
public static boolean isNewProjectConstruction() {
@@ -441,7 +441,7 @@ public class ExternalSystemApiUtil {
* module.
* <p/>
* This method tries to find root project's config path assuming that given path points to a sub-project's config path.
*
*
* @param externalProjectPath external sub-project's config path
* @param externalSystemId target external system
* @param project target ide project
@@ -554,17 +554,17 @@ public class ExternalSystemApiUtil {
/**
* There is a possible case that methods of particular object should be executed with classpath different from the one implied
* by the current class' classloader. External system offers {@link ParametersEnhancer#enhanceLocalProcessing(List)} method
* by the current class' class loader. External system offers {@link ParametersEnhancer#enhanceLocalProcessing(List)} method
* for defining that custom classpath.
* <p/>
* It's also possible that particular implementation of {@link ParametersEnhancer} is compiled using dependency to classes
* which are provided by the {@link ParametersEnhancer#enhanceLocalProcessing(List) expanded classpath}. E.g. a class
* <code>'A'</code> might use method of class <code>'B'</code> and 'A' is located at the current (system/plugin) classpath but
* <code>'B'</code> is not. We need to reload <code>'A'</code> using its expanded classpath then, i.e. create new classloaded
* <code>'B'</code> is not. We need to reload <code>'A'</code> using its expanded classpath then, i.e. create new class loaded
* with that expanded classpath and load <code>'A'</code> by it.
* <p/>
* This method allows to do that.
*
*
* @param clazz custom classpath-aware class which instance should be created (is assumed to have a no-args constructor)
* @param <T> target type
* @return newly created instance of the given class loaded by custom classpath-aware loader
@@ -591,7 +591,7 @@ public class ExternalSystemApiUtil {
//noinspection unchecked
urls.addAll((Collection<? extends URL>)method.invoke(baseLoader));
}
UrlClassLoader loader = new UrlClassLoader(urls, baseLoader.getParent()) {
UrlClassLoader loader = new UrlClassLoader(UrlClassLoader.build().urls(urls).parent(baseLoader.getParent())) {
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.equals(clazz.getName())) {
@@ -32,8 +32,7 @@ public class RecentTasks {
static {
final String libraryName = (System.getProperty("sun.arch.data.model").contains("64"))?
"jumplistbridge64.dll":
"jumplistbridge.dll";
"jumpListBridge64.dll": "jumpListBridge.dll";
final String binPath = PathManager.getBinPath();
final String communityBinPath = PathManager.getHomePath() + File.separatorChar + "community" + File.separatorChar + "bin";
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.lang;
import com.intellij.openapi.application.PathManager;
@@ -96,11 +95,17 @@ public class ClassPath {
}
}
/** @deprecated use {@link #ClassPath(java.util.List, boolean, boolean, boolean, boolean)} (to remove in IDEA 14) */
public ClassPath(URL[] urls, boolean canLockJars, boolean canUseCache) {
this(urls, canLockJars, canUseCache, false, true);
this(Arrays.asList(urls), canLockJars, canUseCache, false, true);
}
/** @deprecated use {@link #ClassPath(java.util.List, boolean, boolean, boolean, boolean)} (to remove in IDEA 14) */
public ClassPath(URL[] urls, boolean canLockJars, boolean canUseCache, boolean acceptUnescapedUrls, boolean preloadJarContents) {
this(Arrays.asList(urls), canLockJars, canUseCache, acceptUnescapedUrls, preloadJarContents);
}
public ClassPath(List<URL> urls, boolean canLockJars, boolean canUseCache, boolean acceptUnescapedUrls, boolean preloadJarContents) {
myCanLockJars = canLockJars;
myCanUseCache = canUseCache;
myAcceptUnescapedUrls = acceptUnescapedUrls;
@@ -110,7 +115,17 @@ public class ClassPath {
// Accessed by reflection from PluginClassLoader // TODO: do we need it?
void addURL(URL url) {
push(new URL[]{url});
push(Collections.singletonList(url));
}
private void push(List<URL> urls) {
if (!urls.isEmpty()) {
synchronized (myUrls) {
for (int i = urls.size() - 1; i >= 0; i--) {
myUrls.push(urls.get(i));
}
}
}
}
@Nullable
@@ -229,14 +244,6 @@ public class ClassPath {
return loader;
}
private void push(URL[] urls) {
if (urls.length == 0) return;
synchronized (myUrls) {
for (int i = urls.length - 1; i >= 0; i--) myUrls.push(urls[i]);
}
}
private class MyEnumeration implements Enumeration<URL> {
private int myIndex = 0;
private Resource myRes = null;
@@ -36,41 +36,76 @@ import java.util.List;
public class UrlClassLoader extends ClassLoader {
@NonNls static final String CLASS_EXTENSION = ".class";
private final ClassPath myClassPath;
public static final class Builder {
private List<URL> myURLs = ContainerUtil.emptyList();
private ClassLoader myParent = null;
private boolean myLockJars = false;
private boolean myUseCache = false;
private boolean myAcceptUnescaped = false;
private boolean myPreload = true;
private Builder() { }
public Builder urls(List<URL> urls) { myURLs = urls; return this; }
public Builder urls(URL... urls) { myURLs = Arrays.asList(urls); return this; }
public Builder parent(ClassLoader parent) { myParent = parent; return this; }
public Builder allowLock() { myLockJars = true; return this; }
public Builder allowLock(boolean lockJars) { myLockJars = lockJars; return this; }
public Builder useCache() { myUseCache = true; return this; }
public Builder useCache(boolean useCache) { myUseCache = useCache; return this; }
public Builder allowUnescaped() { myAcceptUnescaped = true; return this; }
public Builder noPreload() { myPreload = false; return this; }
public UrlClassLoader get() { return new UrlClassLoader(this); }
}
public static Builder build() {
return new Builder();
}
private final List<URL> myURLs;
private final ClassPath myClassPath;
/** @deprecated use {@link #build()} (to remove in IDEA 14) */
public UrlClassLoader(@NotNull ClassLoader parent) {
this(Arrays.asList(((URLClassLoader)parent).getURLs()), parent.getParent(), true, true);
this(build().urls(((URLClassLoader)parent).getURLs()).parent(parent.getParent()).allowLock().useCache());
}
/** @deprecated use {@link #build()} (to remove in IDEA 14) */
public UrlClassLoader(List<URL> urls, @Nullable ClassLoader parent) {
this(urls, parent, false, false);
this(build().urls(urls).parent(parent));
}
/** @deprecated use {@link #build()} (to remove in IDEA 14) */
public UrlClassLoader(URL[] urls, @Nullable ClassLoader parent) {
this(Arrays.asList(urls), parent, false, false);
this(build().urls(urls).parent(parent));
}
public UrlClassLoader(List<URL> urls, @Nullable ClassLoader parent, boolean canLockJars, boolean canUseCache) {
this(urls, parent, canLockJars, canUseCache, false, true);
/** @deprecated use {@link #build()} (to remove in IDEA 14) */
public UrlClassLoader(List<URL> urls, @Nullable ClassLoader parent, boolean lockJars, boolean useCache) {
this(build().urls(urls).parent(parent).allowLock(lockJars).useCache(useCache));
}
public UrlClassLoader(List<URL> urls,
@Nullable ClassLoader parent,
boolean canLockJars,
boolean canUseCache,
boolean acceptUnescapedUrls,
boolean preloadJarContents) {
/** @deprecated use {@link #build()} (to remove in IDEA 14) */
public UrlClassLoader(List<URL> urls, @Nullable ClassLoader parent, boolean lockJars, boolean useCache, boolean allowUnescaped, boolean preload) {
super(parent);
List<URL> list = ContainerUtil.map(urls, new Function<URL, URL>() {
myURLs = ContainerUtil.map(urls, new Function<URL, URL>() {
@Override
public URL fun(URL url) {
return internProtocol(url);
}
});
myClassPath = new ClassPath(list.toArray(new URL[list.size()]), canLockJars, canUseCache, acceptUnescapedUrls, preloadJarContents);
myURLs = list;
myClassPath = new ClassPath(myURLs, lockJars, useCache, allowUnescaped, preload);
}
protected UrlClassLoader(@NotNull Builder builder) {
super(builder.myParent);
myURLs = ContainerUtil.map(builder.myURLs, new Function<URL, URL>() {
@Override
public URL fun(URL url) {
return internProtocol(url);
}
});
myClassPath = new ClassPath(myURLs, builder.myLockJars, builder.myUseCache, builder.myAcceptUnescaped, builder.myPreload);
}
public static URL internProtocol(@NotNull URL url) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Properties;
@@ -117,11 +116,11 @@ public class AntInstallation {
public String getVersion() {
return VERSION.get(myProperties);
}
public String getHomeDir() {
return HOME_DIR.get(myProperties);
}
public AbstractProperty.AbstractPropertyContainer getProperties() {
return myProperties;
}
@@ -134,7 +133,7 @@ public class AntInstallation {
public void updateClasspath() {
myClassLoaderHolder.updateClasspath();
}
public static AntInstallation fromHome(String homePath) throws ConfigurationException {
File antHome = new File(homePath);
String antPath = "'" + antHome.getAbsolutePath() + "'";
@@ -166,7 +165,7 @@ public class AntInstallation {
Properties properties = new Properties();
InputStream stream = null;
try {
stream = new UrlClassLoader(Collections.singletonList(antJar.toURL()), null, false, false, true, false).getResourceAsStream(VERSION_RESOURCE);
stream = UrlClassLoader.build().urls(antJar.toURI().toURL()).allowUnescaped().noPreload().get().getResourceAsStream(VERSION_RESOURCE);
properties.load(stream);
}
catch (MalformedURLException e) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ public class AntResourcesClassLoader extends UrlClassLoader {
private final Set<String> myMisses = new THashSet<String>();
public AntResourcesClassLoader(final List<URL> urls, final ClassLoader parentLoader, final boolean canLockJars, final boolean canUseCache) {
super(urls, parentLoader, canLockJars, canUseCache, true, false);
super(build().urls(urls).parent(parentLoader).allowLock(canLockJars).useCache(canUseCache).allowUnescaped().noPreload());
}
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -99,9 +99,9 @@ public class ShowSerializedXmlAction extends DumbAwareAction {
LOG.info(e1);
}
}
final Project project = module.getProject();
UrlClassLoader loader = new UrlClassLoader(urls, XmlSerializer.class.getClassLoader());
UrlClassLoader loader = UrlClassLoader.build().urls(urls).parent(XmlSerializer.class.getClassLoader()).get();
final Class<?> aClass;
try {
aClass = Class.forName(className, true, loader);
@@ -98,7 +98,8 @@ public class AppEngineSdkUtil {
public static Map<String, Set<String>> computeWhiteList(final File toolsApiJarFile) {
try {
final THashMap<String, Set<String>> map = new THashMap<String, Set<String>>();
ClassLoader loader = new UrlClassLoader(Collections.singletonList(toolsApiJarFile.toURI().toURL()), AppEngineSdkUtil.class.getClassLoader());
final ClassLoader loader = UrlClassLoader.build().urls(toolsApiJarFile.toURI().toURL()).parent(
AppEngineSdkUtil.class.getClassLoader()).get();
final Class<?> whiteListClass = Class.forName("com.google.apphosting.runtime.security.WhiteList", true, loader);
final Set<String> classes = (Set<String>) whiteListClass.getMethod("getWhiteList").invoke(null);
for (String qualifiedName : classes) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -149,7 +149,7 @@ public class GradlePositionManager extends ScriptPositionManagerHelper {
}
}
return new UrlClassLoader(urls, null);
return UrlClassLoader.build().urls(urls).get();
}
private class ScriptSourceMapCalculator implements CachedValueProvider<FactoryMap<File, String>> {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -144,7 +144,7 @@ public class AntTasksProvider {
private final Future<Map<String, Class>> myFuture;
public AntClassLoader(ArrayList<URL> urls) {
super(urls, null, false, false, true, false);
super(build().urls(urls).allowUnescaped().noPreload());
myFuture = ApplicationManager.getApplication().executeOnPooledThread(new Callable<Map<String, Class>>() {
@Override
public Map<String, Class> call() throws Exception {
@@ -80,7 +80,7 @@ public class JavaFxInjectPageLanguageIntention extends PsiElementBaseIntentionAc
}
}
return new UrlClassLoader(urls, null);
return UrlClassLoader.build().urls(urls).get();
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ public final class LoaderFactory {
public static LoaderFactory getInstance(final Project project) {
return ServiceManager.getService(project, LoaderFactory.class);
}
public LoaderFactory(final Project project) {
myProject = project;
myModule2ClassLoader = new ConcurrentWeakHashMap<Module, ClassLoader>();
@@ -155,7 +155,7 @@ public final class LoaderFactory {
private final String myModuleName;
public DesignTimeClassLoader(final List<URL> urls, final ClassLoader parent, final String moduleName) {
super(urls, parent);
super(build().urls(urls).parent(parent));
myModuleName = moduleName;
}