use classpath jar instead of custom class loaders for CommandLineWrapper (IDEA-133617; IDEA-130440)

This commit is contained in:
Anna Kozlova
2015-07-24 13:11:24 +02:00
parent 5f6cbd3207
commit 2347bcad1f
7 changed files with 256 additions and 198 deletions
@@ -15,15 +15,15 @@
*/
package com.intellij.rt.execution;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
/**
* @author anna
@@ -31,98 +31,36 @@ import java.util.List;
*/
public class CommandLineWrapper {
/**
* The VM property is needed to workaround incorrect escaped URLs handling in WebSphere,
* see <a href="https://youtrack.jetbrains.com/issue/IDEA-126859#comment=27-778948">IDEA-126859</a> for additional details
*/
public static final String PROPERTY_DO_NOT_ESCAPE_CLASSPATH_URL = "idea.do.not.escape.classpath.url";
private static final String PREFIX = "-D";
public static void main(String[] args) throws Exception {
final boolean notEscapeClasspathUrl = Boolean.valueOf(System.getProperty(PROPERTY_DO_NOT_ESCAPE_CLASSPATH_URL)).booleanValue();
final List urls = new ArrayList();
final File file = new File(args[0]);
final StringBuffer buf = new StringBuffer();
final BufferedReader reader = new BufferedReader(new FileReader(file));
final File jarFile = new File(args[0]);
JarInputStream inputStream = null;
try {
while(reader.ready()) {
final String fileName = reader.readLine();
if (buf.length() > 0) {
buf.append(File.pathSeparator);
}
buf.append(fileName);
File classpathElement = new File(fileName);
try {
//noinspection Since15, deprecation
urls.add(notEscapeClasspathUrl ? classpathElement.toURL() : classpathElement.toURI().toURL());
}
catch (NoSuchMethodError e) {
//noinspection deprecation
urls.add(classpathElement.toURL());
inputStream = new JarInputStream(new FileInputStream(jarFile));
final Manifest manifest = inputStream.getManifest();
final String vmParams = manifest.getMainAttributes().getValue("VM-Options");
if (vmParams != null) {
final HashMap vmOptions = new HashMap();
parseVmOptions(vmParams, vmOptions);
for (Iterator iterator = vmOptions.keySet().iterator(); iterator.hasNext(); ) {
String optionName = (String)iterator.next();
System.setProperty(optionName, (String)vmOptions.get(optionName));
}
}
}
catch (IOException ignore) {}
finally {
reader.close();
}
if (!file.delete()) file.deleteOnExit();
System.setProperty("java.class.path", buf.toString());
int startArgsIdx = 2;
if (args[1].equals("@vm_params")) {
startArgsIdx = 4;
final File vmParamsFile = new File(args[2]);
final BufferedReader vmParamsReader = new BufferedReader(new FileReader(vmParamsFile));
try {
while (vmParamsReader.ready()) {
final String vmParam = vmParamsReader.readLine().trim();
final int eqIdx = vmParam.indexOf('=');
String vmParamName;
String vmParamValue;
if (eqIdx > -1 && eqIdx < vmParam.length() - 1) {
vmParamName = vmParam.substring(0, eqIdx);
vmParamValue = vmParam.substring(eqIdx + 1);
} else {
vmParamName = vmParam;
vmParamValue = "";
}
vmParamName = vmParamName.trim();
if (vmParamName.startsWith(PREFIX)) {
vmParamName = vmParamName.substring(PREFIX.length());
System.setProperty(vmParamName, vmParamValue);
}
}
if (inputStream != null) {
inputStream.close();
}
finally {
vmParamsReader.close();
}
if (!vmParamsFile.delete()) vmParamsFile.deleteOnExit();
jarFile.deleteOnExit();
}
String mainClassName = args[startArgsIdx - 1];
String[] mainArgs = new String[args.length - startArgsIdx];
System.arraycopy(args, startArgsIdx, mainArgs, 0, mainArgs.length);
for (int i = 0; i < urls.size(); i++) {
URL url = (URL)urls.get(i);
urls.set(i, internFileProtocol(url));
}
ClassLoader loader = new URLClassLoader((URL[])urls.toArray(new URL[urls.size()]), null);
final String classLoader = System.getProperty("java.system.class.loader");
if (classLoader != null) {
try {
loader = (ClassLoader)Class.forName(classLoader).getConstructor(new Class[]{ClassLoader.class}).newInstance(new Object[]{loader});
}
catch (Exception e) {
//leave URL class loader
}
}
Class mainClass = loader.loadClass(mainClassName);
Thread.currentThread().setContextClassLoader(loader);
String mainClassName = args[1];
String[] mainArgs = new String[args.length - 2];
System.arraycopy(args, 2, mainArgs, 0, mainArgs.length);
Class mainClass = Class.forName(mainClassName);
//noinspection SSBasedInspection
Class mainArgType = (new String[0]).getClass();
Method main = mainClass.getMethod("main", new Class[]{mainArgType});
@@ -130,15 +68,24 @@ public class CommandLineWrapper {
main.invoke(null, new Object[]{mainArgs});
}
private static URL internFileProtocol(URL url) {
try {
if ("file".equals(url.getProtocol())) {
return new URL("file", url.getHost(), url.getPort(), url.getFile());
public static void parseVmOptions(String vmParams, Map vmOptions) {
int idx = vmParams.indexOf(PREFIX);
while (idx >= 0) {
final int indexOf = vmParams.indexOf(PREFIX, idx + PREFIX.length());
final String vmParam = indexOf < 0 ? vmParams.substring(idx) : vmParams.substring(idx, indexOf - 1);
final int eqIdx = vmParam.indexOf('=');
String vmParamName;
String vmParamValue;
if (eqIdx > -1 && eqIdx < vmParam.length() - 1) {
vmParamName = vmParam.substring(0, eqIdx);
vmParamValue = vmParam.substring(eqIdx + 1);
} else {
vmParamName = vmParam;
vmParamValue = "";
}
vmOptions.put(vmParamName.trim().substring(PREFIX.length()), vmParamValue);
idx = indexOf;
}
catch (MalformedURLException ignored) {
}
return url;
}
private static void ensureAccess(Object reflectionObject) {
@@ -20,6 +20,10 @@ import com.intellij.rt.execution.CommandLineWrapper;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipOutputStream;
public abstract class ForkedByModuleSplitter {
protected final ForkedDebuggerHelper myForkedDebuggerHelper = new ForkedDebuggerHelper();
@@ -79,26 +83,8 @@ public abstract class ForkedByModuleSplitter {
builder.add("-classpath");
if (myDynamicClasspath.length() > 0) {
try {
final File classpathFile = File.createTempFile("classpath", null);
classpathFile.deleteOnExit();
final PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(classpathFile), "UTF-8"));
try {
int idx = 0;
while (idx < classpath.length()) {
final int endIdx = classpath.indexOf(File.pathSeparator, idx);
if (endIdx < 0) {
writer.println(classpath.substring(idx));
break;
}
writer.println(classpath.substring(idx, endIdx));
idx = endIdx + File.pathSeparator.length();
}
}
finally {
writer.close();
}
builder.add(myDynamicClasspath);
final File classpathFile = createClasspathJarFile(new Manifest(), classpath);
builder.add(myDynamicClasspath + File.pathSeparator + classpathFile.getAbsolutePath());
builder.add(CommandLineWrapper.class.getName());
builder.add(classpathFile.getAbsolutePath());
}
@@ -172,4 +158,41 @@ public abstract class ForkedByModuleSplitter {
protected void sendTime(long time) {}
protected void sendTree(Object rootDescription) {}
public static File createClasspathJarFile(Manifest manifest, String classpath) throws IOException {
final Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
String classpathForManifest = "";
int idx = 0;
int endIdx = 0;
while (endIdx >= 0) {
endIdx = classpath.indexOf(File.pathSeparator, idx);
String path = endIdx < 0 ? classpath.substring(idx) : classpath.substring(idx, endIdx);
if (classpathForManifest.length() > 0) {
classpathForManifest += " ";
}
try {
//noinspection Since15
classpathForManifest += new File(path).toURI().toURL().toString();
}
catch (NoSuchMethodError e) {
classpathForManifest += new File(path).toURL().toString();
}
idx = endIdx + File.pathSeparator.length();
}
attributes.put(Attributes.Name.CLASS_PATH, classpathForManifest);
File jarFile = File.createTempFile("classpath", ".jar");
ZipOutputStream jarPlugin = null;
try {
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(jarFile));
jarPlugin = new JarOutputStream(out, manifest);
}
finally {
if (jarPlugin != null) jarPlugin.close();
}
jarFile.deleteOnExit();
return jarFile;
}
}