/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java

https://bitbucket.org/nbargnesi/idea · Java · 313 lines · 259 code · 31 blank · 23 comment · 57 complexity · cc17115cef70949b843681006c6bed2a MD5 · raw file

  1. /*
  2. * Copyright 2000-2012 JetBrains s.r.o.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * @author max
  18. */
  19. package com.intellij.openapi.projectRoots;
  20. import com.intellij.execution.configurations.GeneralCommandLine;
  21. import com.intellij.execution.configurations.ParametersList;
  22. import com.intellij.execution.configurations.SimpleJavaParameters;
  23. import com.intellij.ide.util.PropertiesComponent;
  24. import com.intellij.openapi.diagnostic.Logger;
  25. import com.intellij.openapi.project.Project;
  26. import com.intellij.openapi.util.Comparing;
  27. import com.intellij.openapi.util.io.FileUtil;
  28. import com.intellij.openapi.vfs.CharsetToolkit;
  29. import com.intellij.openapi.vfs.JarFileSystem;
  30. import com.intellij.openapi.vfs.VirtualFile;
  31. import com.intellij.openapi.vfs.encoding.EncodingManager;
  32. import com.intellij.util.PathUtil;
  33. import com.intellij.util.lang.UrlClassLoader;
  34. import gnu.trove.THashMap;
  35. import org.jetbrains.annotations.NotNull;
  36. import org.jetbrains.annotations.Nullable;
  37. import java.io.*;
  38. import java.nio.charset.Charset;
  39. import java.nio.charset.UnsupportedCharsetException;
  40. import java.util.List;
  41. import java.util.jar.Attributes;
  42. import java.util.jar.JarFile;
  43. import java.util.jar.Manifest;
  44. public class JdkUtil {
  45. private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.JdkUtil");
  46. private static final String WRAPPER_CLASS = "com.intellij.rt.execution.CommandLineWrapper";
  47. private JdkUtil() {
  48. }
  49. /**
  50. * @return the specified attribute of the JDK (examines rt.jar) or null if cannot determine the value
  51. */
  52. @Nullable
  53. public static String getJdkMainAttribute(@NotNull Sdk jdk, Attributes.Name attributeName) {
  54. final VirtualFile homeDirectory = jdk.getHomeDirectory();
  55. if (homeDirectory == null) {
  56. return null;
  57. }
  58. VirtualFile rtJar = homeDirectory.findFileByRelativePath("jre/lib/rt.jar");
  59. if (rtJar == null) {
  60. rtJar = homeDirectory.findFileByRelativePath("lib/rt.jar");
  61. }
  62. if (rtJar == null) {
  63. rtJar = homeDirectory.findFileByRelativePath("jre/lib/vm.jar"); // for IBM jdk
  64. }
  65. if (rtJar == null) {
  66. rtJar = homeDirectory.findFileByRelativePath("../Classes/classes.jar"); // for mac
  67. }
  68. if (rtJar == null) {
  69. String versionString = jdk.getVersionString();
  70. if (versionString != null) {
  71. final int start = versionString.indexOf("\"");
  72. final int end = versionString.lastIndexOf("\"");
  73. versionString = start >= 0 && (end > start)? versionString.substring(start + 1, end) : null;
  74. }
  75. return versionString;
  76. }
  77. VirtualFile rtJarFileContent = JarFileSystem.getInstance().findFileByPath(rtJar.getPath() + JarFileSystem.JAR_SEPARATOR);
  78. if (rtJarFileContent == null) {
  79. return null;
  80. }
  81. com.intellij.openapi.vfs.JarFile manifestJarFile;
  82. try {
  83. manifestJarFile = JarFileSystem.getInstance().getJarFile(rtJarFileContent);
  84. }
  85. catch (IOException e) {
  86. return null;
  87. }
  88. if (manifestJarFile == null) {
  89. return null;
  90. }
  91. try {
  92. com.intellij.openapi.vfs.JarFile.JarEntry entry = manifestJarFile.getEntry(JarFile.MANIFEST_NAME);
  93. if (entry == null) {
  94. return null;
  95. }
  96. InputStream is = manifestJarFile.getInputStream(entry);
  97. Manifest manifest = new Manifest(is);
  98. is.close();
  99. Attributes attributes = manifest.getMainAttributes();
  100. return attributes.getValue(attributeName);
  101. }
  102. catch (IOException e) {
  103. // nothing
  104. }
  105. return null;
  106. }
  107. public static boolean checkForJdk(final File homePath) {
  108. File binPath = new File(homePath.getAbsolutePath() + File.separator + "bin");
  109. if (!binPath.exists()) return false;
  110. FileFilter fileFilter = new FileFilter() {
  111. @SuppressWarnings({"HardCodedStringLiteral"})
  112. public boolean accept(File f) {
  113. if (f.isDirectory()) return false;
  114. return Comparing.strEqual(FileUtil.getNameWithoutExtension(f), "javac") ||
  115. Comparing.strEqual(FileUtil.getNameWithoutExtension(f), "javah");
  116. }
  117. };
  118. File[] children = binPath.listFiles(fileFilter);
  119. return children != null && children.length >= 2 &&
  120. checkForRuntime(homePath.getAbsolutePath());
  121. }
  122. public static boolean checkForJre(String homePath) {
  123. homePath = new File(FileUtil.toSystemDependentName(homePath)).getAbsolutePath();
  124. File binPath = new File(homePath + File.separator + "bin");
  125. if (!binPath.exists()) return false;
  126. FileFilter fileFilter = new FileFilter() {
  127. @SuppressWarnings({"HardCodedStringLiteral"})
  128. public boolean accept(File f) {
  129. return !f.isDirectory() && Comparing.strEqual(FileUtil.getNameWithoutExtension(f), "java");
  130. }
  131. };
  132. File[] children = binPath.listFiles(fileFilter);
  133. return children != null && children.length >= 1 &&
  134. checkForRuntime(homePath);
  135. }
  136. public static boolean checkForRuntime(final String homePath) {
  137. return new File(new File(new File(homePath, "jre"), "lib"), "rt.jar").exists() ||
  138. new File(new File(homePath, "lib"), "rt.jar").exists() ||
  139. new File(new File(new File(homePath, ".."), "Classes"), "classes.jar").exists() || // Apple JDK
  140. new File(new File(new File(homePath, "jre"), "lib"), "vm.jar").exists() || // IBM JDK
  141. new File(homePath, "classes").isDirectory(); // custom build
  142. }
  143. public static GeneralCommandLine setupJVMCommandLine(final String exePath,
  144. final SimpleJavaParameters javaParameters,
  145. final boolean forceDynamicClasspath) {
  146. final GeneralCommandLine commandLine = new GeneralCommandLine();
  147. commandLine.setExePath(exePath);
  148. final ParametersList vmParametersList = javaParameters.getVMParametersList();
  149. commandLine.setEnvParams(javaParameters.getEnv());
  150. commandLine.setPassParentEnvs(javaParameters.isPassParentEnvs());
  151. final Class commandLineWrapper;
  152. if ((commandLineWrapper = getCommandLineWrapperClass()) != null) {
  153. if (javaParameters.isDynamicVMOptions() && useDynamicVMOptions()) {
  154. File vmParamsFile = null;
  155. try {
  156. vmParamsFile = FileUtil.createTempFile("vm_params", null);
  157. final PrintWriter writer = new PrintWriter(vmParamsFile);
  158. try {
  159. for (String param : vmParametersList.getList()) {
  160. if (param.startsWith("-D")) {
  161. writer.println(param);
  162. }
  163. }
  164. }
  165. finally {
  166. writer.close();
  167. }
  168. }
  169. catch (IOException e) {
  170. LOG.error(e);
  171. }
  172. final List<String> list = vmParametersList.getList();
  173. for (String param : list) {
  174. if (!param.trim().startsWith("-D")) {
  175. commandLine.addParameter(param);
  176. }
  177. }
  178. commandLine.addParameter("@vm_params");
  179. commandLine.addParameter(vmParamsFile.getAbsolutePath());
  180. }
  181. else {
  182. commandLine.addParameters(vmParametersList.getList());
  183. }
  184. if (forceDynamicClasspath) {
  185. File classpathFile = null;
  186. if (!vmParametersList.hasParameter("-classpath") && !vmParametersList.hasParameter("-cp")) {
  187. try {
  188. classpathFile = FileUtil.createTempFile("classpath", null);
  189. final PrintWriter writer = new PrintWriter(classpathFile);
  190. try {
  191. for (String path : javaParameters.getClassPath().getPathList()) {
  192. writer.println(path);
  193. }
  194. }
  195. finally {
  196. writer.close();
  197. }
  198. String classpath = PathUtil.getJarPathForClass(commandLineWrapper);
  199. final Class<UrlClassLoader> ourUrlClassLoader = UrlClassLoader.class;
  200. if (ourUrlClassLoader.getName().equals(vmParametersList.getPropertyValue("java.system.class.loader"))) {
  201. classpath += File.pathSeparator + PathUtil.getJarPathForClass(ourUrlClassLoader);
  202. classpath += File.pathSeparator + PathUtil.getJarPathForClass(THashMap.class);
  203. }
  204. commandLine.addParameter("-classpath");
  205. commandLine.addParameter(classpath);
  206. }
  207. catch (IOException e) {
  208. LOG.error(e);
  209. }
  210. }
  211. appendEncoding(javaParameters, commandLine, vmParametersList);
  212. if (classpathFile != null) {
  213. commandLine.addParameter(commandLineWrapper.getName());
  214. commandLine.addParameter(classpathFile.getAbsolutePath());
  215. }
  216. }
  217. else {
  218. appendEncodingClasspath(javaParameters, commandLine, vmParametersList);
  219. }
  220. }
  221. else {
  222. appendParamsEncodingClasspath(javaParameters, commandLine, vmParametersList);
  223. }
  224. final String mainClass = javaParameters.getMainClass();
  225. commandLine.addParameter(mainClass);
  226. commandLine.addParameters(javaParameters.getProgramParametersList().getList());
  227. commandLine.setWorkDirectory(javaParameters.getWorkingDirectory());
  228. return commandLine;
  229. }
  230. private static void appendParamsEncodingClasspath(SimpleJavaParameters javaParameters,
  231. GeneralCommandLine commandLine,
  232. ParametersList parametersList) {
  233. commandLine.addParameters(parametersList.getList());
  234. appendEncodingClasspath(javaParameters, commandLine, parametersList);
  235. }
  236. private static void appendEncodingClasspath(SimpleJavaParameters javaParameters,
  237. GeneralCommandLine commandLine,
  238. ParametersList parametersList) {
  239. appendEncoding(javaParameters, commandLine, parametersList);
  240. if (!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){
  241. commandLine.addParameter("-classpath");
  242. commandLine.addParameter(javaParameters.getClassPath().getPathsString());
  243. }
  244. }
  245. private static void appendEncoding(SimpleJavaParameters javaParameters, GeneralCommandLine commandLine, ParametersList parametersList) {
  246. // Value of -Dfile.encoding and charset of GeneralCommandLine should be in sync in order process's input and output be correctly handled.
  247. String encoding = parametersList.getPropertyValue("file.encoding");
  248. if (encoding == null) {
  249. Charset charset = javaParameters.getCharset();
  250. if (charset == null) charset = EncodingManager.getInstance().getDefaultCharset();
  251. if (charset == null) charset = CharsetToolkit.getDefaultSystemCharset();
  252. commandLine.addParameter("-Dfile.encoding=" + charset.name());
  253. commandLine.setCharset(charset);
  254. }
  255. else {
  256. try {
  257. Charset charset = Charset.forName(encoding);
  258. commandLine.setCharset(charset);
  259. }
  260. catch (UnsupportedCharsetException ignore) {
  261. }
  262. }
  263. }
  264. @Nullable
  265. private static Class getCommandLineWrapperClass() {
  266. try {
  267. return Class.forName(WRAPPER_CLASS);
  268. }
  269. catch (ClassNotFoundException e) {
  270. return null;
  271. }
  272. }
  273. public static boolean useDynamicClasspath(@Nullable Project project) {
  274. final String hasDynamicProperty = System.getProperty("idea.dynamic.classpath", "false");
  275. return Boolean.valueOf(project != null
  276. ? PropertiesComponent.getInstance(project).getOrInit("dynamic.classpath", hasDynamicProperty)
  277. : hasDynamicProperty).booleanValue();
  278. }
  279. public static boolean useDynamicVMOptions() {
  280. return Boolean.valueOf(PropertiesComponent.getInstance().getOrInit("dynamic.vmoptions", "true")).booleanValue();
  281. }
  282. }