Preloader: extract nested classes to top-level
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.preloading;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedParameters")
|
||||||
|
public abstract class ClassHandler {
|
||||||
|
public byte[] instrument(String resourceName, byte[] data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beforeDefineClass(String name, int sizeInBytes) {}
|
||||||
|
public void afterDefineClass(String name) {}
|
||||||
|
|
||||||
|
public void beforeLoadJar(File jarFile) {}
|
||||||
|
public void afterLoadJar(File jarFile) {}
|
||||||
|
}
|
||||||
@@ -17,10 +17,6 @@
|
|||||||
package org.jetbrains.jet.preloading;
|
package org.jetbrains.jet.preloading;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.net.URLStreamHandler;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
@@ -30,19 +26,6 @@ import java.util.zip.ZipInputStream;
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class ClassPreloadingUtils {
|
public class ClassPreloadingUtils {
|
||||||
|
|
||||||
public static abstract class ClassHandler {
|
|
||||||
public byte[] instrument(String resourceName, byte[] data) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void beforeDefineClass(String name, int sizeInBytes) {}
|
|
||||||
public void afterDefineClass(String name) {}
|
|
||||||
|
|
||||||
public void beforeLoadJar(File jarFile) {}
|
|
||||||
public void afterLoadJar(File jarFile) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a class loader that loads all classes from {@code jarFiles} into memory to make loading faster (avoid skipping through zip archives).
|
* Creates a class loader that loads all classes from {@code jarFiles} into memory to make loading faster (avoid skipping through zip archives).
|
||||||
*
|
*
|
||||||
@@ -70,7 +53,7 @@ public class ClassPreloadingUtils {
|
|||||||
parentClassLoader = preloadClasses(classpath, classCountEstimation, parentClassLoader, null, handler);
|
parentClassLoader = preloadClasses(classpath, classCountEstimation, parentClassLoader, null, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
return createMemoryBasedClassLoader(parentClassLoader, entries, handler, classesToLoadByParent);
|
return new MemoryBasedClassLoader(classesToLoadByParent, parentClassLoader, entries, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassLoader preloadClasses(
|
public static ClassLoader preloadClasses(
|
||||||
@@ -116,109 +99,6 @@ public class ClassPreloadingUtils {
|
|||||||
return classpath;
|
return classpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ClassLoader createMemoryBasedClassLoader(
|
|
||||||
final ClassLoader parent,
|
|
||||||
final Map<String, Object> preloadedResources,
|
|
||||||
final ClassHandler handler,
|
|
||||||
final ClassCondition classesToLoadByParent
|
|
||||||
) {
|
|
||||||
return new ClassLoader(null) {
|
|
||||||
@Override
|
|
||||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
|
||||||
if (classesToLoadByParent != null && classesToLoadByParent.accept(name)) {
|
|
||||||
if (parent == null) {
|
|
||||||
return super.loadClass(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return parent.loadClass(name);
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException e) {
|
|
||||||
return super.loadClass(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look in this class loader and then in the parent one
|
|
||||||
Class<?> aClass = super.loadClass(name);
|
|
||||||
if (aClass == null) {
|
|
||||||
if (parent == null) {
|
|
||||||
throw new ClassNotFoundException("Class not available in preloader: " + name);
|
|
||||||
}
|
|
||||||
return parent.loadClass(name);
|
|
||||||
}
|
|
||||||
return aClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
|
||||||
String internalName = name.replace('.', '/').concat(".class");
|
|
||||||
Object resources = preloadedResources.get(internalName);
|
|
||||||
if (resources == null) return null;
|
|
||||||
|
|
||||||
ResourceData resourceData = resources instanceof ResourceData
|
|
||||||
? ((ResourceData) resources)
|
|
||||||
: ((List<ResourceData>) resources).get(0);
|
|
||||||
|
|
||||||
int sizeInBytes = resourceData.bytes.length;
|
|
||||||
if (handler != null) {
|
|
||||||
handler.beforeDefineClass(name, sizeInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<?> definedClass = defineClass(name, resourceData.bytes, 0, sizeInBytes);
|
|
||||||
|
|
||||||
if (handler != null) {
|
|
||||||
handler.afterDefineClass(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return definedClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URL getResource(String name) {
|
|
||||||
URL resource = super.getResource(name);
|
|
||||||
if (resource == null && parent != null) {
|
|
||||||
return parent.getResource(name);
|
|
||||||
}
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected URL findResource(String name) {
|
|
||||||
Enumeration<URL> resources = findResources(name);
|
|
||||||
return resources.hasMoreElements() ? resources.nextElement() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Enumeration<URL> getResources(String name) throws IOException {
|
|
||||||
Enumeration<URL> resources = super.getResources(name);
|
|
||||||
if (!resources.hasMoreElements() && parent != null) {
|
|
||||||
return parent.getResources(name);
|
|
||||||
}
|
|
||||||
return resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Enumeration<URL> findResources(String name) {
|
|
||||||
Object resources = preloadedResources.get(name);
|
|
||||||
if (resources == null) {
|
|
||||||
return Collections.enumeration(Collections.<URL>emptyList());
|
|
||||||
}
|
|
||||||
else if (resources instanceof ResourceData) {
|
|
||||||
return Collections.enumeration(Collections.singletonList(((ResourceData) resources).getURL()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert resources instanceof ArrayList : name;
|
|
||||||
List<ResourceData> resourceDatas = (ArrayList<ResourceData>) resources;
|
|
||||||
List<URL> urls = new ArrayList<URL>(resourceDatas.size());
|
|
||||||
for (ResourceData data : resourceDatas) {
|
|
||||||
urls.add(data.getURL());
|
|
||||||
}
|
|
||||||
return Collections.enumeration(urls);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a map of name to resources. Each value is either a ResourceData if there's only one instance (in the vast majority of cases)
|
* @return a map of name to resources. Each value is either a ResourceData if there's only one instance (in the vast majority of cases)
|
||||||
* or a non-empty ArrayList of ResourceData if there's many
|
* or a non-empty ArrayList of ResourceData if there's many
|
||||||
@@ -299,41 +179,4 @@ public class ClassPreloadingUtils {
|
|||||||
|
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class ResourceData {
|
|
||||||
private final File jarFile;
|
|
||||||
private final String resourceName;
|
|
||||||
private final byte[] bytes;
|
|
||||||
|
|
||||||
public ResourceData(File jarFile, String resourceName, byte[] bytes) {
|
|
||||||
this.jarFile = jarFile;
|
|
||||||
this.resourceName = resourceName;
|
|
||||||
this.bytes = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public URL getURL() {
|
|
||||||
try {
|
|
||||||
String path = "file:" + jarFile + "!/" + resourceName;
|
|
||||||
return new URL("jar", null, 0, path, new URLStreamHandler() {
|
|
||||||
@Override
|
|
||||||
protected URLConnection openConnection(URL u) throws IOException {
|
|
||||||
return new URLConnection(u) {
|
|
||||||
@Override
|
|
||||||
public void connect() throws IOException {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getInputStream() throws IOException {
|
|
||||||
return new ByteArrayInputStream(bytes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (MalformedURLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.preloading;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class MemoryBasedClassLoader extends ClassLoader {
|
||||||
|
private final ClassCondition classesToLoadByParent;
|
||||||
|
private final ClassLoader parent;
|
||||||
|
private final Map<String, Object> preloadedResources;
|
||||||
|
private final ClassHandler handler;
|
||||||
|
|
||||||
|
public MemoryBasedClassLoader(
|
||||||
|
ClassCondition classesToLoadByParent,
|
||||||
|
ClassLoader parent,
|
||||||
|
Map<String, Object> preloadedResources,
|
||||||
|
ClassHandler handler
|
||||||
|
) {
|
||||||
|
super(null);
|
||||||
|
this.classesToLoadByParent = classesToLoadByParent;
|
||||||
|
this.parent = parent;
|
||||||
|
this.preloadedResources = preloadedResources;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
if (classesToLoadByParent != null && classesToLoadByParent.accept(name)) {
|
||||||
|
if (parent == null) {
|
||||||
|
return super.loadClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return parent.loadClass(name);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
return super.loadClass(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look in this class loader and then in the parent one
|
||||||
|
Class<?> aClass = super.loadClass(name);
|
||||||
|
if (aClass == null) {
|
||||||
|
if (parent == null) {
|
||||||
|
throw new ClassNotFoundException("Class not available in preloader: " + name);
|
||||||
|
}
|
||||||
|
return parent.loadClass(name);
|
||||||
|
}
|
||||||
|
return aClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
String internalName = name.replace('.', '/').concat(".class");
|
||||||
|
Object resources = preloadedResources.get(internalName);
|
||||||
|
if (resources == null) return null;
|
||||||
|
|
||||||
|
ResourceData resourceData = resources instanceof ResourceData
|
||||||
|
? ((ResourceData) resources)
|
||||||
|
: ((List<ResourceData>) resources).get(0);
|
||||||
|
|
||||||
|
int sizeInBytes = resourceData.bytes.length;
|
||||||
|
if (handler != null) {
|
||||||
|
handler.beforeDefineClass(name, sizeInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?> definedClass = defineClass(name, resourceData.bytes, 0, sizeInBytes);
|
||||||
|
|
||||||
|
if (handler != null) {
|
||||||
|
handler.afterDefineClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return definedClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getResource(String name) {
|
||||||
|
URL resource = super.getResource(name);
|
||||||
|
if (resource == null && parent != null) {
|
||||||
|
return parent.getResource(name);
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URL findResource(String name) {
|
||||||
|
Enumeration<URL> resources = findResources(name);
|
||||||
|
return resources.hasMoreElements() ? resources.nextElement() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<URL> getResources(String name) throws IOException {
|
||||||
|
Enumeration<URL> resources = super.getResources(name);
|
||||||
|
if (!resources.hasMoreElements() && parent != null) {
|
||||||
|
return parent.getResources(name);
|
||||||
|
}
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Enumeration<URL> findResources(String name) {
|
||||||
|
Object resources = preloadedResources.get(name);
|
||||||
|
if (resources == null) {
|
||||||
|
return Collections.enumeration(Collections.<URL>emptyList());
|
||||||
|
}
|
||||||
|
else if (resources instanceof ResourceData) {
|
||||||
|
return Collections.enumeration(Collections.singletonList(((ResourceData) resources).getURL()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert resources instanceof ArrayList : "Resource map should contain ResourceData or ArrayList<ResourceData>: " + name;
|
||||||
|
List<ResourceData> resourceDatas = (ArrayList<ResourceData>) resources;
|
||||||
|
List<URL> urls = new ArrayList<URL>(resourceDatas.size());
|
||||||
|
for (ResourceData data : resourceDatas) {
|
||||||
|
urls.add(data.getURL());
|
||||||
|
}
|
||||||
|
return Collections.enumeration(urls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -186,7 +186,7 @@ public class Preloader {
|
|||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Handler extends ClassPreloadingUtils.ClassHandler {
|
private static class Handler extends ClassHandler {
|
||||||
public void done() {}
|
public void done() {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.preloading;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.net.URLStreamHandler;
|
||||||
|
|
||||||
|
public final class ResourceData {
|
||||||
|
public final File jarFile;
|
||||||
|
public final String resourceName;
|
||||||
|
public final byte[] bytes;
|
||||||
|
|
||||||
|
public ResourceData(File jarFile, String resourceName, byte[] bytes) {
|
||||||
|
this.jarFile = jarFile;
|
||||||
|
this.resourceName = resourceName;
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getURL() {
|
||||||
|
try {
|
||||||
|
String path = "file:" + jarFile + "!/" + resourceName;
|
||||||
|
return new URL("jar", null, 0, path, new URLStreamHandler() {
|
||||||
|
@Override
|
||||||
|
protected URLConnection openConnection(URL u) throws IOException {
|
||||||
|
return new URLConnection(u) {
|
||||||
|
@Override
|
||||||
|
public void connect() throws IOException {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return new ByteArrayInputStream(bytes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (MalformedURLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user