| /******************************************************************************* |
| * Copyright (c) 2000, 2013 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Jeff Myers myersj@gmail.com - fix for #75201 |
| * Ralf Ebert ralf@ralfebert.de - fix for #307109 |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.launching.macosx; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jdt.internal.launching.LaunchingPlugin; |
| import org.eclipse.jdt.internal.launching.LibraryInfo; |
| import org.eclipse.jdt.internal.launching.MacInstalledJREs; |
| import org.eclipse.jdt.internal.launching.StandardVMType; |
| import org.eclipse.jdt.launching.IVMInstall; |
| import org.eclipse.jdt.launching.IVMInstallType; |
| import org.eclipse.jdt.launching.JavaRuntime; |
| import org.eclipse.jdt.launching.VMStandin; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * This class provides the implementation of the {@link IVMInstallType} for Mac OSX. |
| * |
| * The default VM locations are outlined below. each VM except for developer VMs provide links in the |
| * <code>/System/Library/Frameworks/JavaVM.framework/Versions/</code> folder, with a link named |
| * <code>CurrentJDK</code> that points to the VM you have set using the Java preference tool in the system preferences. |
| * <br><br> |
| * The directory structure for Java VMs prior to Snow Leopard is as follows: |
| * <pre> |
| * /System/Library/Frameworks/JavaVM.framework/Versions/ |
| * 1.3.1/ |
| * Classes/ |
| * classes.jar |
| * ui.jar |
| * Home/ |
| * src.jar |
| * </pre> |
| * |
| * The directory structure for developer VMs is: |
| * <pre> |
| * /Library/Java/JavaVirtualMachines/ |
| * 1.7.0.jdk/ |
| * Contents/ |
| * Home/ |
| * bin/ |
| * lib/ |
| * ... |
| * src.zip |
| * </pre> |
| * |
| * The directory structure for Snow Leopard and Lion VMs is: |
| * <pre> |
| * /System/Library/Java/JavaVirtualMachines/ |
| * 1.6.0.jdk/ |
| * Contents/ |
| * Classes/ |
| * Home/ |
| * src.zip |
| * </pre> |
| * |
| * @see http://developer.apple.com/library/mac/#qa/qa1170/_index.html |
| * @see http://developer.apple.com/library/mac/#releasenotes/Java/JavaSnowLeopardUpdate3LeopardUpdate8RN/NewandNoteworthy/NewandNoteworthy.html#//apple_ref/doc/uid/TP40010380-CH4-SW1 |
| */ |
| public class MacOSXVMInstallType extends StandardVMType { |
| |
| /** The OS keeps all the JVM versions in this directory */ |
| private static final String JVM_VERSION_LOC= "/System/Library/Frameworks/JavaVM.framework/Versions/"; //$NON-NLS-1$ |
| private static final File JVM_VERSIONS_FOLDER= new File(JVM_VERSION_LOC); |
| /** The name of a Unix link to MacOS X's default VM */ |
| private static final String CURRENT_JDK= "CurrentJDK"; //$NON-NLS-1$ |
| /** The root of a JVM */ |
| private static final String JVM_HOME= "Home"; //$NON-NLS-1$ |
| /** The doc (for all JVMs) lives here (if the developer kit has been expanded)*/ |
| private static final String JAVADOC_LOC= "/Developer/Documentation/Java/Reference/"; //$NON-NLS-1$ |
| /** The doc for 1.4.1 is kept in a sub directory of the above. */ |
| private static final String JAVADOC_SUBDIR= "/doc/api"; //$NON-NLS-1$ |
| /** |
| * The name of the src.zip file for the JDK source |
| * @since 3.2.200 |
| */ |
| static final String SRC_ZIP = "src.zip"; //$NON-NLS-1$ |
| /** |
| * The name of the src.jar file for legacy JDK/JREs |
| * @since 3.2.200 |
| */ |
| static final String SRC_JAR = "src.jar"; //$NON-NLS-1$ |
| /** |
| * The name of the source used for libraries on the Mac |
| * @since 3.2.200 |
| */ |
| static final String SRC_NAME = "src"; //$NON-NLS-1$ |
| /** |
| * The name of the Contents folder found within a JRE/JDK folder |
| * @since 3.2.200 |
| */ |
| static final String JVM_CONTENTS = "Contents"; //$NON-NLS-1$ |
| /** |
| * The name of the Classes folder used to hold the libraries for a legacy JDK/JRE |
| * @since 3.2.200 |
| */ |
| static final String JVM_CLASSES = "Classes"; //$NON-NLS-1$ |
| /** |
| * The name of the Versions folder for legacy JRE/JDK installs |
| * @since 3.2.200 |
| */ |
| static final String JVM_VERSIONS = "Versions"; //$NON-NLS-1$ |
| |
| @Override |
| public String getName() { |
| return Messages.MacOSXVMInstallType_0; |
| } |
| |
| @Override |
| public IVMInstall doCreateVMInstall(String id) { |
| return new MacOSXVMInstall(this, id); |
| } |
| |
| /* |
| * @see IVMInstallType#detectInstallLocation() |
| */ |
| @Override |
| public File detectInstallLocation() { |
| try { |
| // try to find the VM used to launch Eclipse |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=407402 |
| File defaultLocation = getJavaHomeLocation(); |
| |
| // find all installed VMs |
| VMStandin[] vms = MacInstalledJREs.getInstalledJREs(null); |
| File firstLocation = null; |
| IVMInstall firstInstall = null; |
| IVMInstall defaultInstall = null; |
| for (int i= 0; i < vms.length; i++) { |
| File location = vms[i].getInstallLocation(); |
| IVMInstall install = findVMInstall(vms[i].getId()); |
| if (install == null) { |
| install= vms[i].convertToRealVM(); |
| } |
| if (i == 0) { |
| firstLocation = location; |
| firstInstall = install; |
| } |
| if (defaultInstall == null && defaultLocation != null && defaultLocation.equals(location)) { |
| defaultInstall = install; |
| } |
| } |
| |
| // determine the default VM |
| if (defaultInstall == null) { |
| if (defaultLocation != null) { |
| // prefer the VM used to launch Eclipse |
| String version = System.getProperty("java.version"); //$NON-NLS-1$ |
| VMStandin standin = new MacInstalledJREs.MacVMStandin(this, |
| defaultLocation, |
| version == null ? Messages.MacOSXVMInstallType_jre : NLS.bind(Messages.MacOSXVMInstallType_jre_version, version), |
| (version == null ? "???" : version), //$NON-NLS-1$ |
| String.valueOf(System.currentTimeMillis())); |
| defaultInstall = standin.convertToRealVM(); |
| } else { |
| defaultInstall = firstInstall; |
| defaultLocation = firstLocation; |
| } |
| } |
| if (defaultInstall != null) { |
| try { |
| JavaRuntime.setDefaultVMInstall(defaultInstall, null); |
| } catch (CoreException e) { |
| LaunchingPlugin.log(e); |
| } |
| } |
| return defaultLocation; |
| } catch (CoreException e) { |
| MacOSXLaunchingPlugin.getDefault().getLog().log(e.getStatus()); |
| return detectInstallLocationOld(); |
| } |
| } |
| |
| /** |
| * The proper way to find installed JREs is to parse the XML output produced from "java_home -X" |
| * (see bug 325777). However, if that fails, revert to the hard coded search. |
| * |
| * @return file that points to the default JRE install |
| */ |
| private File detectInstallLocationOld() { |
| String javaVMName= System.getProperty("java.vm.name"); //$NON-NLS-1$ |
| if (javaVMName == null) { |
| return null; |
| } |
| if (!JVM_VERSIONS_FOLDER.exists() || !JVM_VERSIONS_FOLDER.isDirectory()) { |
| String message= NLS.bind(Messages.MacOSXVMInstallType_1, JVM_VERSIONS_FOLDER); |
| LaunchingPlugin.log(message); |
| return null; |
| } |
| // find all installed VMs |
| File defaultLocation= null; |
| File[] versions= getAllVersionsOld(); |
| File currentJDK= getCurrentJDKOld(); |
| for (int i= 0; i < versions.length; i++) { |
| File versionFile= versions[i]; |
| String version= versionFile.getName(); |
| File home= new File(versionFile, JVM_HOME); |
| if (home.exists()) { |
| boolean isDefault= currentJDK.equals(versionFile); |
| IVMInstall install= findVMInstall(version); |
| if (install == null) { |
| VMStandin vm= new VMStandin(this, version); |
| vm.setInstallLocation(home); |
| vm.setName(version); |
| vm.setLibraryLocations(getDefaultLibraryLocations(home)); |
| vm.setJavadocLocation(getDefaultJavadocLocation(home)); |
| install= vm.convertToRealVM(); |
| } |
| if (isDefault) { |
| defaultLocation= home; |
| try { |
| JavaRuntime.setDefaultVMInstall(install, null); |
| } catch (CoreException e) { |
| LaunchingPlugin.log(e); |
| } |
| } |
| } |
| } |
| return defaultLocation; |
| } |
| |
| /** |
| * The proper way to find installed JREs is to parse the XML output produced from "java_home -X" |
| * (see bug 325777). However, if that fails, revert to the hard coded search. |
| * |
| * @return array of files that point to JRE install directories |
| */ |
| private File[] getAllVersionsOld() { |
| File[] versionFiles= JVM_VERSIONS_FOLDER.listFiles(); |
| for (int i= 0; i < versionFiles.length; i++) { |
| versionFiles[i]= resolveSymbolicLinks(versionFiles[i]); |
| } |
| return versionFiles; |
| } |
| |
| /** |
| * The proper way to find the default JRE is to parse the XML output produced from "java_home -X" |
| * and take the first entry in the list. However, if that fails, revert to the hard coded search. |
| * |
| * @return a file that points to the default JRE install directory |
| */ |
| private File getCurrentJDKOld() { |
| return resolveSymbolicLinks(new File(JVM_VERSIONS_FOLDER, CURRENT_JDK)); |
| } |
| |
| private File resolveSymbolicLinks(File file) { |
| try { |
| return file.getCanonicalFile(); |
| } catch (IOException ex) { |
| return file; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.launching.StandardVMType#getDefaultLibraryInfo(java.io.File) |
| */ |
| @Override |
| protected LibraryInfo getDefaultLibraryInfo(File installLocation) { |
| IPath rtjar = getDefaultSystemLibrary(installLocation); |
| if(rtjar.toFile().isFile()) { |
| //not a Mac OS VM, default to the standard VM type info collection |
| return super.getDefaultLibraryInfo(installLocation); |
| } |
| File classes = new File(installLocation, "../Classes"); //$NON-NLS-1$ |
| File lib1= new File(classes, "classes.jar"); //$NON-NLS-1$ |
| File lib2= new File(classes, "ui.jar"); //$NON-NLS-1$ |
| |
| String[] libs = new String[] { lib1.toString(),lib2.toString() }; |
| |
| File lib = new File(installLocation, "lib"); //$NON-NLS-1$ |
| File extDir = new File(lib, "ext"); //$NON-NLS-1$ |
| String[] dirs = null; |
| if (extDir.exists()) { |
| dirs = new String[] {extDir.getAbsolutePath()}; |
| } else { |
| dirs = new String[0]; |
| } |
| |
| File endDir = new File(lib, "endorsed"); //$NON-NLS-1$ |
| String[] endDirs = null; |
| if (endDir.exists()) { |
| endDirs = new String[] {endDir.getAbsolutePath()}; |
| } else { |
| endDirs = new String[0]; |
| } |
| |
| return new LibraryInfo("???", libs, dirs, endDirs); //$NON-NLS-1$ |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.launching.StandardVMType#getDefaultSystemLibrarySource(java.io.File) |
| */ |
| @Override |
| protected IPath getDefaultSystemLibrarySource(File libLocation) { |
| File parent = libLocation.getParentFile(); |
| File src = null; |
| //Walk the parent hierarchy, stop if we run out of parents or we hit the /Contents directory. |
| //For the new shape of JRE/JDKs we can stop once we hit the root Contents folder, for legacy versions |
| //we can stop when we hit the Versions folder |
| String pname = parent.getName(); |
| while (parent != null && !JVM_CONTENTS.equals(pname) && !JVM_VERSIONS.equals(pname)) { |
| //In Mac OSX supplied JDK/JREs the /Home directory is co-located to the /Classes directory |
| if(JVM_CLASSES.equals(pname)) { |
| src = new File(parent.getParent(), JVM_HOME); |
| src = getSourceInParent(src); |
| } |
| else { |
| src = getSourceInParent(parent); |
| } |
| if(src != null) { |
| if (src.getName().endsWith(".jar")) { //$NON-NLS-1$ |
| setDefaultRootPath(SRC_NAME); |
| } else { |
| setDefaultRootPath(""); //$NON-NLS-1$ |
| } |
| |
| return new Path(src.getPath()); |
| } |
| parent = parent.getParentFile(); |
| } |
| setDefaultRootPath(""); //$NON-NLS-1$ |
| return Path.EMPTY; |
| } |
| |
| /** |
| * Checks to see if <code>src.zip</code> or <code>src.jar</code> exists in the given parent |
| * folder. Returns <code>null</code> if it does not exist. |
| * <br><br> |
| * The newer naming of the archive is <code>src.zip</code> and the older (pre-1.6) is |
| * <code>src.jar</code> |
| * |
| * @param parent the parent directory |
| * @return the {@link File} for the source archive or <code>null</code> |
| * @since 3.2.200 |
| */ |
| File getSourceInParent(File parent) { |
| if(parent.isDirectory()) { |
| File src = new File(parent, SRC_ZIP); |
| if(src.isFile()) { |
| return src; |
| } |
| src = new File(src, SRC_JAR); |
| if(src.isFile()) { |
| return src; |
| } |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.launching.StandardVMType#validateInstallLocation(java.io.File) |
| */ |
| @Override |
| public IStatus validateInstallLocation(File javaHome) { |
| String id= MacOSXLaunchingPlugin.getUniqueIdentifier(); |
| File java= new File(javaHome, "bin"+File.separator+"java"); //$NON-NLS-2$ //$NON-NLS-1$ |
| if (java.isFile()) |
| { |
| return new Status(IStatus.OK, id, 0, "ok", null); //$NON-NLS-1$ |
| } |
| return new Status(IStatus.ERROR, id, 0, Messages.MacOSXVMInstallType_2, null); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.launching.StandardVMType#getDefaultJavadocLocation(java.io.File) |
| */ |
| @Override |
| public URL getDefaultJavadocLocation(File installLocation) { |
| // try in local filesystem |
| String id= null; |
| try { |
| String post= File.separator + JVM_HOME; |
| String path= installLocation.getCanonicalPath(); |
| if (path.startsWith(JVM_VERSION_LOC) && path.endsWith(post)) { |
| id= path.substring(JVM_VERSION_LOC.length(), path.length()-post.length()); |
| } |
| } catch (IOException ex) { |
| // we use the fall back from below |
| } |
| if (id != null) { |
| String s= JAVADOC_LOC + id + JAVADOC_SUBDIR; |
| File docLocation= new File(s); |
| if (!docLocation.exists()) { |
| s= JAVADOC_LOC + id; |
| docLocation= new File(s); |
| if (!docLocation.exists()) { |
| s= null; |
| } |
| } |
| if (s != null) { |
| try { |
| return new URL("file", "", s); //$NON-NLS-1$ //$NON-NLS-2$ |
| } catch (MalformedURLException ex) { |
| // we use the fall back from below |
| } |
| } |
| } |
| |
| // fall back |
| return super.getDefaultJavadocLocation(installLocation); |
| } |
| |
| /* |
| * Overridden to make it visible. |
| */ |
| @Override |
| protected String getVMVersion(File javaHome, File javaExecutable) { |
| return super.getVMVersion(javaHome, javaExecutable); |
| } |
| } |