lvcs-impl
[idea/community.git] / lang-api / src / com / intellij / openapi / projectRoots / JdkUtil.java
1 /*
2  * @author max
3  */
4 package com.intellij.openapi.projectRoots;
5
6 import com.intellij.execution.configurations.GeneralCommandLine;
7 import com.intellij.execution.configurations.ParametersList;
8 import com.intellij.execution.configurations.SimpleJavaParameters;
9 import com.intellij.ide.util.PropertiesComponent;
10 import com.intellij.openapi.diagnostic.Logger;
11 import com.intellij.openapi.project.Project;
12 import com.intellij.openapi.util.Comparing;
13 import com.intellij.openapi.util.io.FileUtil;
14 import com.intellij.openapi.vfs.CharsetToolkit;
15 import com.intellij.openapi.vfs.JarFileSystem;
16 import com.intellij.openapi.vfs.VirtualFile;
17 import com.intellij.openapi.vfs.encoding.EncodingManager;
18 import com.intellij.util.PathUtil;
19 import com.intellij.util.lang.UrlClassLoader;
20 import org.jetbrains.annotations.Nullable;
21
22 import java.io.*;
23 import java.nio.charset.Charset;
24 import java.util.Map;
25 import java.util.jar.Attributes;
26 import java.util.jar.JarFile;
27 import java.util.jar.Manifest;
28 import java.util.zip.ZipEntry;
29 import java.util.zip.ZipFile;
30
31 public class JdkUtil {
32   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.JdkUtil");
33   private static final String WRAPPER_CLASS = "com.intellij.rt.execution.CommandLineWrapper";
34
35   private JdkUtil() {
36   }
37
38   /**
39    * @return the specified attribute of the JDK (examines rt.jar) or null if cannot determine the value
40    */
41   @Nullable
42   public static String getJdkMainAttribute(Sdk jdk, Attributes.Name attributeName) {
43     final VirtualFile homeDirectory = jdk.getHomeDirectory();
44     if (homeDirectory == null) {
45       return null;
46     }
47     VirtualFile rtJar = homeDirectory.findFileByRelativePath("jre/lib/rt.jar");
48     if (rtJar == null) {
49       rtJar = homeDirectory.findFileByRelativePath("lib/rt.jar");
50     }
51     if (rtJar == null) {
52       rtJar = homeDirectory.findFileByRelativePath("jre/lib/vm.jar"); // for IBM jdk
53     }
54     if (rtJar == null) {
55       rtJar = homeDirectory.findFileByRelativePath("../Classes/classes.jar"); // for mac
56     }
57     if (rtJar == null) {
58       return null;
59     }
60     VirtualFile rtJarFileContent = JarFileSystem.getInstance().findFileByPath(rtJar.getPath() + JarFileSystem.JAR_SEPARATOR);
61     if (rtJarFileContent == null) {
62       return null;
63     }
64     ZipFile manifestJarFile;
65     try {
66       manifestJarFile = JarFileSystem.getInstance().getJarFile(rtJarFileContent);
67     }
68     catch (IOException e) {
69       return null;
70     }
71     if (manifestJarFile == null) {
72       return null;
73     }
74     try {
75       ZipEntry entry = manifestJarFile.getEntry(JarFile.MANIFEST_NAME);
76       if (entry == null) {
77         return null;
78       }
79       InputStream is = manifestJarFile.getInputStream(entry);
80       Manifest manifest = new Manifest(is);
81       is.close();
82       Attributes attributes = manifest.getMainAttributes();
83       return attributes.getValue(attributeName);
84     }
85     catch (IOException e) {
86       // nothing
87     }
88     return null;
89   }
90
91
92   public static boolean checkForJdk(File file) {
93     file = new File(file.getAbsolutePath() + File.separator + "bin");
94     if (!file.exists()) return false;
95     FileFilter fileFilter = new FileFilter() {
96       @SuppressWarnings({"HardCodedStringLiteral"})
97       public boolean accept(File f) {
98         if (f.isDirectory()) return false;
99         return Comparing.strEqual(FileUtil.getNameWithoutExtension(f), "javac") ||
100                Comparing.strEqual(FileUtil.getNameWithoutExtension(f), "javah");
101       }
102     };
103     File[] children = file.listFiles(fileFilter);
104     return children != null && children.length >= 2;
105   }
106
107   public static boolean checkForJre(String file) {
108     File ioFile = new File(new File(file.replace('/', File.separatorChar)).getAbsolutePath() + File.separator + "bin");
109     if (!ioFile.exists()) return false;
110     FileFilter fileFilter = new FileFilter() {
111       @SuppressWarnings({"HardCodedStringLiteral"})
112       public boolean accept(File f) {
113         return !f.isDirectory() && Comparing.strEqual(FileUtil.getNameWithoutExtension(f), "java");
114       }
115     };
116     File[] children = ioFile.listFiles(fileFilter);
117     return children != null && children.length >= 1;
118   }
119
120   public static GeneralCommandLine setupJVMCommandLine(final String exePath, final SimpleJavaParameters javaParameters,
121                                                     final boolean forceDynamicClasspath) {
122     final GeneralCommandLine commandLine = new GeneralCommandLine();
123     commandLine.setExePath(exePath);
124     ParametersList parametersList = javaParameters.getVMParametersList();
125     commandLine.addParameters(parametersList.getList());
126     if (!parametersList.hasProperty("file.encoding")) {
127       Charset charset = javaParameters.getCharset();
128       if (charset == null) charset = EncodingManager.getInstance().getDefaultCharset();
129       if (charset == null) charset = CharsetToolkit.getDefaultSystemCharset();
130       commandLine.setCharset(charset);
131     }
132
133     final Class commandLineWrapper;
134     if (forceDynamicClasspath && (commandLineWrapper = getCommandLineWrapperClass()) != null) {
135       File classpathFile = null;
136       if(!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){
137         try {
138           classpathFile = FileUtil.createTempFile("classpath", null);
139           final PrintWriter writer = new PrintWriter(classpathFile);
140           try {
141             for (String path : javaParameters.getClassPath().getPathList()) {
142               writer.println(path);
143             }
144           }
145           finally {
146             writer.close();
147           }
148
149           commandLine.addParameter("-classpath");
150           commandLine.addParameter(PathUtil.getJarPathForClass(commandLineWrapper) + File.pathSeparator +
151                                    PathUtil.getJarPathForClass(UrlClassLoader.class));
152         }
153         catch (IOException e) {
154           LOG.error(e);
155         }
156       }
157
158       if (classpathFile != null) {
159         commandLine.addParameter(commandLineWrapper.getName());
160         commandLine.addParameter(classpathFile.getAbsolutePath());
161       }
162     }
163     else if(!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){
164       commandLine.addParameter("-classpath");
165       commandLine.addParameter(javaParameters.getClassPath().getPathsString());
166     }
167
168     final String mainClass = javaParameters.getMainClass();
169     commandLine.addParameter(mainClass);
170     commandLine.addParameters(javaParameters.getProgramParametersList().getList());
171     commandLine.setWorkDirectory(javaParameters.getWorkingDirectory());
172
173     final Map<String, String> env = javaParameters.getEnv();
174     if (env != null) {
175       commandLine.setEnvParams(env);
176       commandLine.setPassParentEnvs(javaParameters.isPassParentEnvs());
177     }
178
179     return commandLine;
180   }
181
182   @Nullable
183   private static Class getCommandLineWrapperClass() {
184     try {
185       return Class.forName(WRAPPER_CLASS);
186     }
187     catch (ClassNotFoundException e) {
188       return null;
189     }
190   }
191
192   public static boolean useDynamicClasspath(@Nullable Project project) {
193     final String hasDynamicProperty = System.getProperty("idea.dynamic.classpath", "false");
194     return Boolean.valueOf(project != null
195                            ? PropertiesComponent.getInstance(project).getOrInit("dynamic.classpath", hasDynamicProperty)
196                            : hasDynamicProperty).booleanValue();
197   }
198 }