Rename package jet -> kotlin in preloader and instrumentation
org.jetbrains.jet.preloading -> org.jetbrains.kotlin.preloading
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.preloading;
|
||||
|
||||
public interface ClassCondition {
|
||||
boolean accept(String className);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.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) {}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.preloading;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ClassPreloadingUtils {
|
||||
/**
|
||||
* Creates a class loader that loads all classes from {@code jarFiles} into memory to make loading faster (avoid skipping through zip archives).
|
||||
*
|
||||
* NOTE: if many resources with the same name exist, only the first one will be loaded
|
||||
*
|
||||
* @param jarFiles jars to load all classes from
|
||||
* @param classCountEstimation an estimated number of classes in a the jars
|
||||
* @param parentClassLoader parent class loader
|
||||
* @param handler handler to be notified on class definitions done by this class loader, or null
|
||||
* @param classesToLoadByParent condition to load some classes via parent class loader
|
||||
* @return a class loader that reads classes from memory
|
||||
* @throws IOException on from reading the jar
|
||||
*/
|
||||
public static ClassLoader preloadClasses(
|
||||
Collection<File> jarFiles,
|
||||
int classCountEstimation,
|
||||
ClassLoader parentClassLoader,
|
||||
ClassCondition classesToLoadByParent,
|
||||
ClassHandler handler
|
||||
) throws IOException {
|
||||
Map<String, Object> entries = loadAllClassesFromJars(jarFiles, classCountEstimation, handler);
|
||||
|
||||
Collection<File> classpath = mergeClasspathFromManifests(entries);
|
||||
if (!classpath.isEmpty()) {
|
||||
parentClassLoader = preloadClasses(classpath, classCountEstimation, parentClassLoader, null, handler);
|
||||
}
|
||||
|
||||
return new MemoryBasedClassLoader(classesToLoadByParent, parentClassLoader, entries, handler);
|
||||
}
|
||||
|
||||
public static ClassLoader preloadClasses(
|
||||
Collection<File> jarFiles, int classCountEstimation, ClassLoader parentClassLoader, ClassCondition classesToLoadByParent
|
||||
) throws IOException {
|
||||
return preloadClasses(jarFiles, classCountEstimation, parentClassLoader, classesToLoadByParent, null);
|
||||
}
|
||||
|
||||
private static Collection<File> mergeClasspathFromManifests(Map<String, Object> preloadedResources) throws IOException {
|
||||
Object manifest = preloadedResources.get(JarFile.MANIFEST_NAME);
|
||||
if (manifest instanceof ResourceData) {
|
||||
return extractManifestClasspath((ResourceData) manifest);
|
||||
}
|
||||
else if (manifest instanceof ArrayList) {
|
||||
List<File> result = new ArrayList<File>();
|
||||
for (ResourceData data : (ArrayList<ResourceData>) manifest) {
|
||||
result.addAll(extractManifestClasspath(data));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
assert manifest == null : "Resource map should contain ResourceData or ArrayList<ResourceData>: " + manifest;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static Collection<File> extractManifestClasspath(ResourceData manifestData) throws IOException {
|
||||
Manifest manifest = new Manifest(new ByteArrayInputStream(manifestData.bytes));
|
||||
String classpathSpaceSeparated = (String) manifest.getMainAttributes().get(Attributes.Name.CLASS_PATH);
|
||||
if (classpathSpaceSeparated == null) return Collections.emptyList();
|
||||
|
||||
Collection<File> classpath = new ArrayList<File>(1);
|
||||
for (String jar : classpathSpaceSeparated.split(" ")) {
|
||||
if (".".equals(jar)) continue;
|
||||
|
||||
if (!jar.endsWith(".jar")) {
|
||||
throw new UnsupportedOperationException("Class-Path attribute should only contain paths to JAR files: " + jar);
|
||||
}
|
||||
|
||||
classpath.add(new File(manifestData.jarFile.getParent(), jar));
|
||||
}
|
||||
|
||||
return classpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
private static Map<String, Object> loadAllClassesFromJars(
|
||||
Collection<File> jarFiles,
|
||||
int classNumberEstimate,
|
||||
ClassHandler handler
|
||||
) throws IOException {
|
||||
// 0.75 is HashMap.DEFAULT_LOAD_FACTOR
|
||||
Map<String, Object> resources = new HashMap<String, Object>((int) (classNumberEstimate / 0.75));
|
||||
|
||||
for (File jarFile : jarFiles) {
|
||||
if (handler != null) {
|
||||
handler.beforeLoadJar(jarFile);
|
||||
}
|
||||
|
||||
FileInputStream fileInputStream = new FileInputStream(jarFile);
|
||||
try {
|
||||
byte[] buffer = new byte[10 * 1024];
|
||||
ZipInputStream stream = new ZipInputStream(new BufferedInputStream(fileInputStream));
|
||||
while (true) {
|
||||
ZipEntry entry = stream.getNextEntry();
|
||||
if (entry == null) break;
|
||||
if (entry.isDirectory()) continue;
|
||||
|
||||
int size = (int) entry.getSize();
|
||||
int effectiveSize = size < 0 ? 32 : size;
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(effectiveSize);
|
||||
|
||||
int count;
|
||||
while ((count = stream.read(buffer)) > 0) {
|
||||
bytes.write(buffer, 0, count);
|
||||
}
|
||||
|
||||
String name = entry.getName();
|
||||
byte[] data = bytes.toByteArray();
|
||||
if (handler != null) {
|
||||
data = handler.instrument(name, data);
|
||||
}
|
||||
ResourceData resourceData = new ResourceData(jarFile, name, data);
|
||||
|
||||
Object previous = resources.get(name);
|
||||
if (previous == null) {
|
||||
resources.put(name, resourceData);
|
||||
}
|
||||
else if (previous instanceof ResourceData) {
|
||||
List<ResourceData> list = new ArrayList<ResourceData>();
|
||||
list.add((ResourceData) previous);
|
||||
list.add(resourceData);
|
||||
resources.put(name, list);
|
||||
}
|
||||
else {
|
||||
assert previous instanceof ArrayList :
|
||||
"Resource map should contain ResourceData or ArrayList<ResourceData>: " + name;
|
||||
((ArrayList<ResourceData>) previous).add(resourceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
fileInputStream.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (handler != null) {
|
||||
handler.afterLoadJar(jarFile);
|
||||
}
|
||||
}
|
||||
|
||||
for (Object value : resources.values()) {
|
||||
if (value instanceof ArrayList) {
|
||||
((ArrayList) value).trimToSize();
|
||||
}
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.preloading;
|
||||
|
||||
import org.jetbrains.kotlin.preloading.instrumentation.Instrumenter;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
|
||||
public class Preloader {
|
||||
|
||||
public static final int PRELOADER_ARG_COUNT = 4;
|
||||
private static final String INSTRUMENT_PREFIX = "instrument=";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < PRELOADER_ARG_COUNT) {
|
||||
printUsageAndExit();
|
||||
}
|
||||
|
||||
List<File> files = parseClassPath(args[0]);
|
||||
|
||||
String mainClassCanonicalName = args[1];
|
||||
|
||||
int classNumber;
|
||||
try {
|
||||
classNumber = Integer.parseInt(args[2]);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println(e.getMessage());
|
||||
printUsageAndExit();
|
||||
return;
|
||||
}
|
||||
|
||||
String modeStr = args[3];
|
||||
final Mode mode = parseMode(modeStr);
|
||||
URL[] instrumentersClasspath = parseInstrumentersClasspath(mode, modeStr);
|
||||
|
||||
final long startTime = System.nanoTime();
|
||||
|
||||
ClassLoader parent = Preloader.class.getClassLoader();
|
||||
|
||||
ClassLoader withInstrumenter = instrumentersClasspath.length > 0 ? new URLClassLoader(instrumentersClasspath, parent) : parent;
|
||||
|
||||
final Handler handler = getHandler(mode, withInstrumenter);
|
||||
ClassLoader preloaded = ClassPreloadingUtils.preloadClasses(files, classNumber, withInstrumenter, null, handler);
|
||||
|
||||
Class<?> mainClass = preloaded.loadClass(mainClassCanonicalName);
|
||||
Method mainMethod = mainClass.getMethod("main", String[].class);
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mode != Mode.NO_TIME) {
|
||||
System.out.println();
|
||||
System.out.println("=== Preloader's measurements: ");
|
||||
long dt = System.nanoTime() - startTime;
|
||||
System.out.format("Total time: %.3fs\n", dt / 1e9);
|
||||
}
|
||||
handler.done();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
mainMethod.invoke(0, new Object[] {Arrays.copyOfRange(args, PRELOADER_ARG_COUNT, args.length)});
|
||||
}
|
||||
|
||||
private static URL[] parseInstrumentersClasspath(Mode mode, String modeStr)
|
||||
throws MalformedURLException {
|
||||
URL[] instrumentersClasspath;
|
||||
if (mode == Mode.INSTRUMENT) {
|
||||
List<File> instrumentersClassPathFiles = parseClassPath(getClassPath(modeStr));
|
||||
instrumentersClasspath = new URL[instrumentersClassPathFiles.size()];
|
||||
for (int i = 0; i < instrumentersClassPathFiles.size(); i++) {
|
||||
File file = instrumentersClassPathFiles.get(i);
|
||||
instrumentersClasspath[i] = file.toURI().toURL();
|
||||
}
|
||||
}
|
||||
else {
|
||||
instrumentersClasspath = new URL[0];
|
||||
}
|
||||
return instrumentersClasspath;
|
||||
}
|
||||
|
||||
private static String getClassPath(String modeStr) {
|
||||
return modeStr.substring(INSTRUMENT_PREFIX.length());
|
||||
}
|
||||
|
||||
private static List<File> parseClassPath(String classpath) {
|
||||
String[] paths = classpath.split("\\" + File.pathSeparator);
|
||||
List<File> files = new ArrayList<File>(paths.length);
|
||||
for (String path : paths) {
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
System.out.println("File does not exist: " + file);
|
||||
printUsageAndExit();
|
||||
}
|
||||
files.add(file);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private static Handler getHandler(Mode mode, ClassLoader withInstrumenter) {
|
||||
if (mode == Mode.NO_TIME) return new Handler();
|
||||
|
||||
final Instrumenter instrumenter = mode == Mode.INSTRUMENT ? loadInstrumenter(withInstrumenter) : Instrumenter.DO_NOTHING;
|
||||
|
||||
final int[] counter = new int[1];
|
||||
final int[] size = new int[1];
|
||||
return new Handler() {
|
||||
@Override
|
||||
public void beforeDefineClass(String name, int sizeInBytes) {
|
||||
counter[0]++;
|
||||
size[0] += sizeInBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
System.out.println();
|
||||
System.out.println("Loaded classes: " + counter[0]);
|
||||
System.out.println("Loaded classes size: " + size[0]);
|
||||
System.out.println();
|
||||
|
||||
instrumenter.dump(System.out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] instrument(String resourceName, byte[] data) {
|
||||
return instrumenter.instrument(resourceName, data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Instrumenter loadInstrumenter(ClassLoader withInstrumenter) {
|
||||
ServiceLoader<Instrumenter> loader = ServiceLoader.load(Instrumenter.class, withInstrumenter);
|
||||
Iterator<Instrumenter> instrumenters = loader.iterator();
|
||||
if (instrumenters.hasNext()) {
|
||||
Instrumenter instrumenter = instrumenters.next();
|
||||
if (instrumenters.hasNext()) {
|
||||
System.err.println("PRELOADER WARNING: Only the first instrumenter is used: " + instrumenter.getClass());
|
||||
}
|
||||
return instrumenter;
|
||||
}
|
||||
else {
|
||||
System.err.println("PRELOADER WARNING: No instrumenters found");
|
||||
return Instrumenter.DO_NOTHING;
|
||||
}
|
||||
}
|
||||
|
||||
private enum Mode {
|
||||
NO_TIME,
|
||||
TIME,
|
||||
INSTRUMENT
|
||||
}
|
||||
|
||||
private static Mode parseMode(String arg) {
|
||||
if ("time".equals(arg)) return Mode.TIME;
|
||||
if ("notime".equals(arg)) return Mode.NO_TIME;
|
||||
if (arg.startsWith(INSTRUMENT_PREFIX)) return Mode.INSTRUMENT;
|
||||
|
||||
System.out.println("Unrecognized argument: " + arg);
|
||||
printUsageAndExit();
|
||||
return Mode.NO_TIME;
|
||||
}
|
||||
|
||||
private static void printUsageAndExit() {
|
||||
System.out.println("Usage: Preloader <paths to jars> <main class> <class number estimate> <notime|time|instrument=<instrumenters class path>> <parameters to pass to the main class>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static class Handler extends ClassHandler {
|
||||
public void done() {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.preloading.instrumentation;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public interface Instrumenter {
|
||||
|
||||
Instrumenter DO_NOTHING = new Instrumenter() {
|
||||
@Override
|
||||
public byte[] instrument(String resourceName, byte[] data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintStream out) {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
byte[] instrument(String resourceName, byte[] data);
|
||||
void dump(PrintStream out);
|
||||
}
|
||||
Reference in New Issue
Block a user