| /******************************************************************************* |
| * Copyright (c) 2000, 2018 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 |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.launching; |
| |
| |
| import java.io.File; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.jdt.core.IAccessRule; |
| import org.eclipse.jdt.core.IClasspathAttribute; |
| import org.eclipse.jdt.core.IClasspathEntry; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.launching.IRuntimeClasspathEntry; |
| import org.eclipse.jdt.launching.IRuntimeClasspathEntryResolver; |
| import org.eclipse.jdt.launching.IRuntimeClasspathEntryResolver2; |
| import org.eclipse.jdt.launching.IVMInstall; |
| import org.eclipse.jdt.launching.JavaRuntime; |
| import org.eclipse.jdt.launching.LibraryLocation; |
| |
| /** |
| * Resolves for JRELIB_VARIABLE and JRE_CONTAINER |
| */ |
| public class JRERuntimeClasspathEntryResolver implements IRuntimeClasspathEntryResolver2 { |
| |
| private static IAccessRule[] EMPTY_RULES = new IAccessRule[0]; |
| |
| /** |
| * @see IRuntimeClasspathEntryResolver#resolveRuntimeClasspathEntry(IRuntimeClasspathEntry, ILaunchConfiguration) |
| */ |
| @Override |
| public IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, ILaunchConfiguration configuration) throws CoreException { |
| IVMInstall jre = null; |
| if (entry.getType() == IRuntimeClasspathEntry.CONTAINER && entry.getPath().segmentCount() > 1) { |
| // a specific VM |
| jre = JREContainerInitializer.resolveVM(entry.getPath()); |
| } else { |
| // default VM for config |
| jre = JavaRuntime.computeVMInstall(configuration); |
| } |
| if (jre == null) { |
| // cannot resolve JRE |
| return new IRuntimeClasspathEntry[0]; |
| } |
| return resolveLibraryLocations(jre, entry.getClasspathProperty()); |
| } |
| |
| /** |
| * @see IRuntimeClasspathEntryResolver#resolveRuntimeClasspathEntry(IRuntimeClasspathEntry, IJavaProject) |
| */ |
| @Override |
| public IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, IJavaProject project) throws CoreException { |
| IVMInstall jre = null; |
| if (entry.getType() == IRuntimeClasspathEntry.CONTAINER && entry.getPath().segmentCount() > 1) { |
| // a specific VM |
| jre = JREContainerInitializer.resolveVM(entry.getPath()); |
| } else { |
| // default VM for project |
| jre = JavaRuntime.getVMInstall(project); |
| } |
| if (jre == null) { |
| // cannot resolve JRE |
| return new IRuntimeClasspathEntry[0]; |
| } |
| return resolveLibraryLocations(jre, entry.getClasspathProperty()); |
| } |
| |
| /** |
| * Resolves library locations for the given VM install |
| * @param vm the VM |
| * @param kind the entry kind |
| * @return the array of {@link IRuntimeClasspathEntry}s |
| */ |
| protected IRuntimeClasspathEntry[] resolveLibraryLocations(IVMInstall vm, int kind) { |
| LibraryLocation[] libs = vm.getLibraryLocations(); |
| LibraryLocation[] defaultLibs = vm.getVMInstallType().getDefaultLibraryLocations(vm.getInstallLocation()); |
| boolean overrideJavadoc = false; |
| if (libs == null) { |
| // default system libraries |
| libs = defaultLibs; |
| overrideJavadoc = true; |
| } else if (!isSameArchives(libs, defaultLibs)) { |
| // determine if bootpath should be explicit |
| kind = IRuntimeClasspathEntry.BOOTSTRAP_CLASSES; |
| } |
| if (kind == IRuntimeClasspathEntry.BOOTSTRAP_CLASSES) { |
| File vmInstallLocation= vm.getInstallLocation(); |
| if (vmInstallLocation != null) { |
| LibraryInfo libraryInfo= LaunchingPlugin.getLibraryInfo(vmInstallLocation.getAbsolutePath()); |
| if (libraryInfo != null) { |
| // only return endorsed and bootstrap classpath entries if we have the info |
| // libraries in the 'ext' directories are not loaded by the boot class loader |
| String[] extensionDirsArray = libraryInfo.getExtensionDirs(); |
| Set<String> extensionDirsSet = new HashSet<>(); |
| for (int i = 0; i < extensionDirsArray.length; i++) { |
| extensionDirsSet.add(extensionDirsArray[i]); |
| } |
| List<IRuntimeClasspathEntry> resolvedEntries = new ArrayList<>(libs.length); |
| for (int i = 0; i < libs.length; i++) { |
| LibraryLocation location = libs[i]; |
| IPath libraryPath = location.getSystemLibraryPath(); |
| String dir = libraryPath.toFile().getParent(); |
| // exclude extension directory entries |
| if (!extensionDirsSet.contains(dir)) { |
| resolvedEntries.add(resolveLibraryLocation(vm, location, kind, overrideJavadoc)); |
| } |
| } |
| return resolvedEntries.toArray(new IRuntimeClasspathEntry[resolvedEntries.size()]); |
| } |
| } |
| } |
| List<IRuntimeClasspathEntry> resolvedEntries = new ArrayList<>(libs.length); |
| for (int i = 0; i < libs.length; i++) { |
| IPath systemLibraryPath = libs[i].getSystemLibraryPath(); |
| if (systemLibraryPath.toFile().exists()) { |
| resolvedEntries.add(resolveLibraryLocation(vm, libs[i], kind, overrideJavadoc)); |
| } |
| } |
| return resolvedEntries.toArray(new IRuntimeClasspathEntry[resolvedEntries.size()]); |
| } |
| |
| /** |
| * Return whether the given list of libraries refer to the same archives in the same |
| * order. Only considers the binary archive (not source or javadoc locations). |
| * |
| * @param libs the locations |
| * @param defaultLibs the default locations |
| * @return whether the given list of libraries refer to the same archives in the same |
| * order |
| */ |
| public static boolean isSameArchives(LibraryLocation[] libs, LibraryLocation[] defaultLibs) { |
| if (libs.length != defaultLibs.length) { |
| return false; |
| } |
| IPath dpath = null, lpath = null; |
| for (int i = 0; i < defaultLibs.length; i++) { |
| dpath = defaultLibs[i].getSystemLibraryPath(); |
| lpath = libs[i].getSystemLibraryPath(); |
| if(Platform.getOS().equals(Platform.OS_WIN32)) { |
| //the .equals method of IPath ignores trailing separators so we must as well |
| if (!dpath.removeTrailingSeparator().toOSString().equalsIgnoreCase(lpath.removeTrailingSeparator().toOSString())) { |
| return false; |
| } |
| } else if (!dpath.equals(lpath)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * @see IRuntimeClasspathEntryResolver#resolveVMInstall(IClasspathEntry) |
| */ |
| @Override |
| public IVMInstall resolveVMInstall(IClasspathEntry entry) { |
| switch (entry.getEntryKind()) { |
| case IClasspathEntry.CPE_VARIABLE: |
| if (entry.getPath().segment(0).equals(JavaRuntime.JRELIB_VARIABLE)) { |
| return JavaRuntime.getDefaultVMInstall(); |
| } |
| break; |
| case IClasspathEntry.CPE_CONTAINER: |
| if (entry.getPath().segment(0).equals(JavaRuntime.JRE_CONTAINER)) { |
| return JREContainerInitializer.resolveVM(entry.getPath()); |
| } |
| break; |
| default: |
| break; |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.launching.IRuntimeClasspathEntryResolver2#isVMInstallReference(org.eclipse.jdt.core.IClasspathEntry) |
| */ |
| @Override |
| public boolean isVMInstallReference(IClasspathEntry entry) { |
| switch (entry.getEntryKind()) { |
| case IClasspathEntry.CPE_VARIABLE: |
| if (entry.getPath().segment(0).equals(JavaRuntime.JRELIB_VARIABLE)) { |
| return true; |
| } |
| break; |
| case IClasspathEntry.CPE_CONTAINER: |
| if (entry.getPath().segment(0).equals(JavaRuntime.JRE_CONTAINER)) { |
| return true; |
| } |
| break; |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns a runtime classpath entry for the given library in the specified VM. |
| * |
| * @param vm the VM |
| * @param location the location |
| * @param kind the classpath entry kind |
| * @param overrideJavaDoc if the JavaDoc location should be overridden or not |
| * @return runtime classpath entry |
| * @since 3.2 |
| */ |
| private IRuntimeClasspathEntry resolveLibraryLocation(IVMInstall vm, LibraryLocation location, int kind, boolean overrideJavaDoc) { |
| IPath libraryPath = location.getSystemLibraryPath(); |
| URL javadocLocation = location.getJavadocLocation(); |
| if (overrideJavaDoc && javadocLocation == null) { |
| javadocLocation = vm.getJavadocLocation(); |
| } |
| IClasspathAttribute[] attributes = null; |
| if (javadocLocation == null) { |
| attributes = new IClasspathAttribute[0]; |
| } else { |
| attributes = new IClasspathAttribute[]{JavaCore.newClasspathAttribute(IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, javadocLocation.toExternalForm())}; |
| } |
| IClasspathEntry cpe = JavaCore.newLibraryEntry(libraryPath, location.getSystemLibraryPath(), location.getPackageRootPath(), EMPTY_RULES, attributes, false); |
| IRuntimeClasspathEntry resolved = new RuntimeClasspathEntry(cpe); |
| resolved.setClasspathProperty(kind); |
| IPath sourcePath = location.getSystemLibrarySourcePath(); |
| if (sourcePath != null && !sourcePath.isEmpty()) { |
| resolved.setSourceAttachmentPath(sourcePath); |
| resolved.setSourceAttachmentRootPath(location.getPackageRootPath()); |
| } |
| return resolved; |
| } |
| |
| } |